administration_test.gno
7.00 Kb · 197 lines
1package bolo
2
3import (
4 "chain"
5 "testing"
6
7 "gno.land/p/nt/testutils/v0"
8)
9
10// TestAdministration walks the admin's writes on a fresh deployment, each called
11// straight from the test's body, as AssertOriginCall requires (plan §3.3): the
12// launch values, then each write's effect, then the handover to a realm, which
13// then administers through C11's realm branch. The writes' refusals are tested in
14// txtar (admin.txtar): a crossing call's panic can't be recovered here.
15func TestAdministration(cur realm, t *testing.T) {
16 // The walk changes every setting and the admin: put them back, so later
17 // tests start from the launch values.
18 defer restoreSettings(admin, pendingAdmin, params, presets, minDonation, escrowCap, tipRecipient, paused, sunset, categoryOrder)
19
20 // The launch values as API §2.2 states them: literals, not the constants under
21 // test.
22 if p := GetParams(); p != (Params{1_000_000, 90 * 86400, 60 * 86400, 30 * 86400}) {
23 t.Errorf("launch params = %v", p)
24 }
25 s := GetSettings()
26 if s.Version != "v0" || s.Presets != [4]int64{5_000_000, 10_000_000, 20_000_000, 50_000_000} ||
27 s.MinDonation != 1_000_000 || s.MaxEscrowBalance != 1_000_000_000 ||
28 s.TipRecipient != adminAddr || s.Paused || s.Sunset {
29 t.Errorf("launch settings = %v", s)
30 }
31 launchSet := []string{
32 "medical", "emergency", "disaster", "humanitarian", "water", "food",
33 "education", "orphans", "animals", "funeral", "worship", "community",
34 "sport", "celebration", "personal", "other",
35 }
36 if len(s.Categories) != len(launchSet) {
37 t.Errorf("launch categories = %v", s.Categories)
38 }
39 for i, code := range launchSet {
40 if i >= len(s.Categories) || s.Categories[i] != code || !categories.Has(code) {
41 t.Errorf("launch category %d: want %s, listed and found", i, code)
42 }
43 }
44 if a, p := GetAdmin(); a != adminAddr || p != "" {
45 t.Errorf("GetAdmin() = %s, %q", a, p)
46 }
47 // GetSettings hands out a copy (C6).
48 s.Categories[0] = "changed"
49 if GetSettings().Categories[0] != "medical" {
50 t.Errorf("GetSettings shares its categories with the realm")
51 }
52
53 testing.SetRealm(testing.NewUserRealm(adminAddr))
54 SetParams(cross(cur), 2_000_000, 30, 14, 0)
55 SetMinDonation(cross(cur), 500_000)
56 SetPresets(cross(cur), 1_000_000, 2_000_000, 3_000_000, 4_000_000)
57 SetEscrowCap(cross(cur), 0)
58 AddCategory(cross(cur), "garden")
59 treasurer := testutils.TestAddress("treasurer")
60 SetTipRecipient(cross(cur), treasurer)
61 Pause(cross(cur))
62 Sunset(cross(cur))
63 if p := GetParams(); p != (Params{2_000_000, 30 * secondsPerDay, 14 * secondsPerDay, 0}) {
64 t.Errorf("params = %v", p)
65 }
66 s = GetSettings()
67 if s.MinDonation != 500_000 || s.Presets != [4]int64{1_000_000, 2_000_000, 3_000_000, 4_000_000} ||
68 s.MaxEscrowBalance != 0 || s.TipRecipient != treasurer || !s.Paused || !s.Sunset ||
69 len(s.Categories) != 17 || s.Categories[16] != "garden" || !categories.Has("garden") {
70 t.Errorf("settings = %v", s)
71 }
72 Unpause(cross(cur))
73 if GetSettings().Paused {
74 t.Errorf("still paused")
75 }
76
77 // The handover (ADR D11): a second proposal replaces the first; accepting ends
78 // the proposal, and the new admin is a realm.
79 dao := chain.PackageAddress("gno.land/r/test/dao")
80 ProposeAdmin(cross(cur), testutils.TestAddress("someone"))
81 ProposeAdmin(cross(cur), dao)
82 if a, p := GetAdmin(); a != adminAddr || p != dao {
83 t.Errorf("after two proposals: GetAdmin() = %s, %s", a, p)
84 }
85 testing.SetRealm(testing.NewCodeRealm("gno.land/r/test/dao"))
86 AcceptAdmin(cross(cur))
87 if a, p := GetAdmin(); a != dao || p != "" {
88 t.Errorf("after accepting: GetAdmin() = %s, %q", a, p)
89 }
90 SetEscrowCap(cross(cur), 7)
91 if GetSettings().MaxEscrowBalance != 7 {
92 t.Errorf("the realm admin's write didn't apply")
93 }
94}
95
96func TestCheckParams(t *testing.T) {
97 if got := checkParams(1, 1, 7, 0); got != (Params{1, secondsPerDay, 7 * secondsPerDay, 0}) {
98 t.Errorf("lower bounds: %v", got)
99 }
100 if got := checkParams(1, 3650, 3650, 3650); got != (Params{1, 3650 * secondsPerDay, 3650 * secondsPerDay, 3650 * secondsPerDay}) {
101 t.Errorf("upper bounds: %v", got)
102 }
103 for name, c := range map[string]struct {
104 deposit int64
105 dormancy, exitDelay, hold int
106 }{
107 "no deposit": {0, 90, 60, 30},
108 "negative deposit": {-1, 90, 60, 30},
109 "no dormancy": {1, 0, 60, 30},
110 "dormancy too long": {1, 3651, 60, 30},
111 "exit delay too short": {1, 90, 6, 30},
112 "exit delay too long": {1, 90, 3651, 30},
113 "negative bond hold": {1, 90, 60, -1},
114 "bond hold too long": {1, 90, 60, 3651},
115 } {
116 if !panicsWith(func() { checkParams(c.deposit, c.dormancy, c.exitDelay, c.hold) }, ErrSetting) {
117 t.Errorf("%s: not refused", name)
118 }
119 }
120}
121
122func TestCheckPresets(t *testing.T) {
123 if got := checkPresets(1, 2, 3, 4); got != [4]int64{1, 2, 3, 4} {
124 t.Errorf("checkPresets = %v", got)
125 }
126 for name, p := range map[string][4]int64{
127 "zero": {0, 2, 3, 4},
128 "negative": {-1, 2, 3, 4},
129 "equal pair": {1, 2, 2, 4},
130 "last equal": {1, 2, 3, 3},
131 "first equal": {1, 1, 3, 4},
132 "descending": {4, 3, 2, 1},
133 } {
134 if !panicsWith(func() { checkPresets(p[0], p[1], p[2], p[3]) }, ErrSetting) {
135 t.Errorf("%s: not refused", name)
136 }
137 }
138}
139
140func TestCheckOutsideBolo(t *testing.T) {
141 checkOutsideBolo(testutils.TestAddress("treasurer"))
142 campaign := escrowAddr(9)
143 derived.Set(campaign.String(), true)
144 defer derived.Remove(campaign.String())
145 for name, a := range map[string]address{
146 "the realm": realmAddr(),
147 "slashed": slashedAddr(),
148 "the storage deposit": depositAddr(),
149 "the registry": registryAddr(),
150 "the registry's deposit": registryDepositAddr(),
151 "a campaign's escrow": campaign,
152 "malformed": "g1notanaddress",
153 } {
154 if !panicsWith(func() { checkOutsideBolo(a) }, ErrSetting) {
155 t.Errorf("%s: not refused", name)
156 }
157 }
158}
159
160func TestCheckNewCategory(t *testing.T) {
161 checkNewCategory("orchard")
162 checkNewCategory("abc")
163 checkNewCategory("abcdefghijklmnopqrst")
164 for name, code := range map[string]string{
165 "too short": "ab",
166 "too long": "abcdefghijklmnopqrstu",
167 "capitals": "Orchard",
168 "a digit": "orchard2",
169 "a space": "or chard",
170 "already listed": "water",
171 } {
172 if !panicsWith(func() { checkNewCategory(code) }, ErrSetting) {
173 t.Errorf("%s: not refused", name)
174 }
175 }
176 // The 50th fits, the 51st doesn't (API §3.6, INV-9).
177 saved := categoryOrder
178 defer func() { categoryOrder = saved }()
179 for len(categoryOrder) < 49 {
180 categoryOrder = append(categoryOrder, "filler")
181 }
182 checkNewCategory("orchard")
183 categoryOrder = append(categoryOrder, "orchard")
184 if !panicsWith(func() { checkNewCategory("grove") }, ErrSetting) {
185 t.Errorf("a 51st category: not refused")
186 }
187}
188
189// restoreSettings puts back what TestAdministration changes.
190func restoreSettings(a, pending address, p Params, pr [4]int64, minimum, ceiling int64, tips address, pause, sun bool, order []string) {
191 admin, pendingAdmin, params, presets = a, pending, p, pr
192 minDonation, escrowCap, tipRecipient, paused, sunset = minimum, ceiling, tips, pause, sun
193 for _, code := range categoryOrder[len(order):] {
194 categories.Remove(code)
195 }
196 categoryOrder = order
197}