govdao_test.gno

7.91 Kb ยท 263 lines
  1package impl
  2
  3import (
  4	"std"
  5	"strings"
  6	"testing"
  7
  8	"gno.land/p/demo/testutils"
  9	"gno.land/p/demo/urequire"
 10	"gno.land/r/gov/dao"
 11	"gno.land/r/gov/dao/v3/memberstore"
 12)
 13
 14func init() {
 15	loadMembers()
 16	dao.UpdateImpl(cross, dao.UpdateRequest{
 17		DAO:         govDAO,
 18		AllowedDAOs: []string{"gno.land/r/gov/dao/v3/impl"},
 19	})
 20}
 21
 22var (
 23	m1    = testutils.TestAddress("m1")
 24	m11   = testutils.TestAddress("m1.1")
 25	m111  = testutils.TestAddress("m1.1.1")
 26	m1111 = testutils.TestAddress("m1.1.1.1")
 27	m2    = testutils.TestAddress("m2")
 28	m3    = testutils.TestAddress("m3")
 29	m4    = testutils.TestAddress("m4")
 30	m5    = testutils.TestAddress("m5")
 31	m6    = testutils.TestAddress("m6")
 32
 33	noMember = testutils.TestAddress("nm1")
 34)
 35
 36func loadMembers() {
 37	// This is needed because state is saved between unit tests,
 38	// and we want to avoid having real members used on tests
 39	mstore := memberstore.Get()
 40	mstore.DeleteAll()
 41
 42	mstore.SetTier(memberstore.T1)
 43	mstore.SetTier(memberstore.T2)
 44	mstore.SetTier(memberstore.T3)
 45
 46	mstore.SetMember(memberstore.T1, m1, memberByTier(memberstore.T1))
 47	mstore.SetMember(memberstore.T1, m11, memberByTier(memberstore.T1))
 48	mstore.SetMember(memberstore.T1, m111, memberByTier(memberstore.T1))
 49	mstore.SetMember(memberstore.T1, m1111, memberByTier(memberstore.T1))
 50
 51	mstore.SetMember(memberstore.T2, m2, memberByTier(memberstore.T2))
 52	mstore.SetMember(memberstore.T2, m3, memberByTier(memberstore.T2))
 53	mstore.SetMember(memberstore.T3, m4, memberByTier(memberstore.T3))
 54	mstore.SetMember(memberstore.T3, m5, memberByTier(memberstore.T3))
 55	mstore.SetMember(memberstore.T3, m6, memberByTier(memberstore.T3))
 56}
 57
 58func TestCreateProposalAndVote(cur realm, t *testing.T) {
 59	loadMembers()
 60
 61	portfolio := "# This is my portfolio:\n\n- THINGS"
 62
 63	testing.SetOriginCaller(noMember)
 64	testing.SetRealm(std.NewCodeRealm("gno.land/r/gov/dao/v3/impl"))
 65
 66	nm1 := testutils.TestAddress("nm1")
 67
 68	urequire.AbortsWithMessage(t, "Only T1 and T2 members can be added by proposal. To add a T3 member use AddMember function directly.", func(cur realm) {
 69		dao.MustCreateProposal(cross, NewAddMemberRequest(cur, nm1, memberstore.T3, portfolio))
 70	})
 71
 72	urequire.AbortsWithMessage(t, "proposer is not a member", func(cur realm) {
 73		dao.MustCreateProposal(cross, NewAddMemberRequest(cur, nm1, memberstore.T2, portfolio))
 74	})
 75
 76	testing.SetOriginCaller(m1)
 77	testing.SetRealm(std.NewCodeRealm("gno.land/r/gov/dao/v3/impl"))
 78
 79	proposalRequest := NewAddMemberRequest(cur, nm1, memberstore.T2, portfolio)
 80
 81	testing.SetOriginCaller(m1)
 82	pid := dao.MustCreateProposal(cross, proposalRequest)
 83	urequire.Equal(t, int(pid), 0)
 84
 85	// m1 votes yes because that member is interested on it
 86	dao.MustVoteOnProposal(cross, dao.VoteRequest{
 87		Option:     dao.YesVote,
 88		ProposalID: dao.ProposalID(0),
 89	})
 90
 91	testing.SetOriginCaller(m11)
 92
 93	dao.MustVoteOnProposal(cross, dao.VoteRequest{
 94		Option:     dao.NoVote,
 95		ProposalID: dao.ProposalID(0),
 96	})
 97
 98	testing.SetOriginCaller(m2)
 99
100	dao.MustVoteOnProposal(cross, dao.VoteRequest{
101		Option:     dao.NoVote,
102		ProposalID: dao.ProposalID(0),
103	})
104
105	testing.SetOriginCaller(m3)
106
107	dao.MustVoteOnProposal(cross, dao.VoteRequest{
108		Option:     dao.NoVote,
109		ProposalID: dao.ProposalID(0),
110	})
111
112	testing.SetOriginCaller(m4)
113
114	urequire.AbortsWithMessage(t, "member on specified tier is not allowed to vote on this proposal", func() {
115		dao.MustVoteOnProposal(cross, dao.VoteRequest{
116			Option:     dao.NoVote,
117			ProposalID: dao.ProposalID(0),
118		})
119	})
120
121	testing.SetOriginCaller(m111)
122
123	// Same effect as:
124	// dao.MustVoteOnProposal(dao.VoteRequest{
125	// 	Option:     dao.NoVote,
126	// 	ProposalID: dao.ProposalID(0),
127	// })
128	dao.MustVoteOnProposalSimple(cross, 0, "NO")
129
130	urequire.Equal(t, true, contains(dao.Render(""), "Proposal open for votes"))
131	urequire.Equal(t, true, contains(dao.Render(""), "15.789473684210526%"))
132	urequire.Equal(t, true, contains(dao.Render(""), "52.63157894736842%"))
133
134	urequire.AbortsWithMessage(t, "proposal didn't reach supermajority yet: 66", func() {
135		dao.ExecuteProposal(cross, dao.ProposalID(0))
136	})
137
138	testing.SetOriginCaller(m1111)
139	dao.MustVoteOnProposal(cross, dao.VoteRequest{
140		Option:     dao.NoVote,
141		ProposalID: dao.ProposalID(0),
142	})
143
144	accepted := dao.ExecuteProposal(cross, dao.ProposalID(0))
145	urequire.Equal(t, false, accepted)
146
147	urequire.Equal(t, true, contains(dao.Render(""), "**PROPOSAL HAS BEEN DENIED**"))
148	urequire.Equal(t, true, contains(dao.Render(""), "NO PERCENT: 68.42105263157895%"))
149}
150
151func TestProposalPagination(cur realm, t *testing.T) {
152	loadMembers()
153	portfolio := "### This is my portfolio:\n\n- THINGS"
154
155	testing.SetOriginCaller(m1)
156	testing.SetRealm(std.NewCodeRealm("gno.land/r/gov/dao/v3/impl"))
157
158	nm1 := testutils.TestAddress("nm1")
159
160	var pid dao.ProposalID
161
162	proposalRequest := NewAddMemberRequest(cur, nm1, memberstore.T2, portfolio)
163
164	testing.SetOriginCaller(m1)
165	pid = dao.MustCreateProposal(cross, proposalRequest)
166
167	// TODO: tests keep the same vm state: https://github.com/gnolang/gno/issues/1982
168	urequire.Equal(t, 1, int(pid))
169
170	pid = dao.MustCreateProposal(cross, proposalRequest)
171	urequire.Equal(t, 2, int(pid))
172
173	pid = dao.MustCreateProposal(cross, proposalRequest)
174	urequire.Equal(t, 3, int(pid))
175
176	pid = dao.MustCreateProposal(cross, proposalRequest)
177	urequire.Equal(t, 4, int(pid))
178
179	pid = dao.MustCreateProposal(cross, proposalRequest)
180	urequire.Equal(t, 5, int(pid))
181
182	pid = dao.MustCreateProposal(cross, proposalRequest)
183	urequire.Equal(t, 6, int(pid))
184
185	urequire.Equal(t, true, contains(dao.Render(""), "## Proposal with id: 6"))
186	urequire.Equal(t, true, contains(dao.Render(""), "## Proposal with id: 5"))
187	urequire.Equal(t, true, contains(dao.Render(""), "## Proposal with id: 4"))
188
189	urequire.Equal(t, true, contains(dao.Render("/?page=2"), "## Proposal with id: 3"))
190	urequire.Equal(t, true, contains(dao.Render("/?page=2"), "## Proposal with id: 2"))
191	urequire.Equal(t, true, contains(dao.Render("/?page=2"), "## Proposal with id: 1"))
192	urequire.Equal(t, true, contains(dao.Render("/?page=3"), "## Proposal with id: 0"))
193}
194
195func TestUpgradeDaoImplementation(t *testing.T) {
196	loadMembers()
197
198	testing.SetOriginCaller(noMember)
199	testing.SetRealm(std.NewCodeRealm("gno.land/r/gov/dao/v3/impl"))
200
201	urequire.PanicsWithMessage(t, "proposer is not a member", func() {
202		NewUpgradeDaoImplRequest(govDAO, "gno.land/r/gov/dao/v4/impl", "Something happened and we have to fix it.")
203	})
204
205	testing.SetOriginCaller(m1)
206	testing.SetRealm(std.NewCodeRealm("gno.land/r/gov/dao/v3/impl"))
207
208	preq := NewUpgradeDaoImplRequest(govDAO, "gno.land/r/gov/dao/v4/impl", "Something happened and we have to fix it.")
209
210	testing.SetOriginCaller(m1)
211	pid := dao.MustCreateProposal(cross, preq)
212	urequire.Equal(t, int(pid), 7)
213
214	// m1 votes yes because that member is interested on it
215	dao.MustVoteOnProposal(cross, dao.VoteRequest{
216		Option:     dao.YesVote,
217		ProposalID: dao.ProposalID(pid),
218	})
219
220	testing.SetOriginCaller(m11)
221
222	dao.MustVoteOnProposal(cross, dao.VoteRequest{
223		Option:     dao.YesVote,
224		ProposalID: dao.ProposalID(pid),
225	})
226
227	testing.SetOriginCaller(m2)
228
229	dao.MustVoteOnProposal(cross, dao.VoteRequest{
230		Option:     dao.YesVote,
231		ProposalID: dao.ProposalID(pid),
232	})
233
234	testing.SetOriginCaller(m3)
235
236	dao.MustVoteOnProposal(cross, dao.VoteRequest{
237		Option:     dao.YesVote,
238		ProposalID: dao.ProposalID(pid),
239	})
240
241	testing.SetOriginCaller(m111)
242
243	// Same effect as:
244	// dao.MustVoteOnProposal(dao.VoteRequest{
245	// 	Option:     dao.YesVote,
246	// 	ProposalID: dao.ProposalID(pid),
247	// })
248	dao.MustVoteOnProposalSimple(cross, int64(pid), "YES")
249
250	urequire.Equal(t, true, contains(dao.Render("7"), "Proposal open for votes"))
251	urequire.Equal(t, true, contains(dao.Render("7"), "68.42105263157895%"))
252	urequire.Equal(t, true, contains(dao.Render("7"), "0%"))
253
254	accepted := dao.ExecuteProposal(cross, dao.ProposalID(pid))
255	urequire.Equal(t, true, accepted)
256	urequire.Equal(t, true, contains(dao.Render("7"), "**PROPOSAL HAS BEEN ACCEPTED**"))
257	urequire.Equal(t, true, contains(dao.Render("7"), "YES PERCENT: 68.42105263157895%"))
258
259}
260
261func contains(s, substr string) bool {
262	return strings.Index(s, substr) >= 0
263}