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}