Search Apps Documentation Source Content File Folder Download Copy Actions Download

govdao_test.gno

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