verifier_test.gno
7.72 Kb · 213 lines
1package names
2
3import (
4 "testing"
5
6 "gno.land/p/nt/testutils/v0"
7 "gno.land/p/nt/uassert/v0"
8 "gno.land/p/nt/urequire/v0"
9)
10
11// cur is a zero-value realm used as a placeholder when forwarding to
12// uassert/urequire dispatch helpers that gained an `rlm realm` param.
13// These tests pass `func()` callbacks (no crossing inside the callback),
14// so rlm is ignored — a nil realm here is safe.
15var cur realm
16var (
17 alice = testutils.TestAddress("alice")
18 bob = testutils.TestAddress("bob")
19)
20
21func TestDefaultVerifier(t *testing.T) {
22 // Disabled: any case is true (regardless of paused or lookup).
23 uassert.True(t, verifier(false, false, alice, alice.String(), nil))
24 uassert.True(t, verifier(false, false, "", alice.String(), nil))
25 uassert.True(t, verifier(false, false, alice, "somerandomusername", nil))
26
27 // Pre-Enable bypass takes priority over paused — even when paused=true,
28 // !isEnabled returns true. This is the documented "stage pause before
29 // Enable" behavior.
30 uassert.True(t, verifier(false, true, alice, alice.String(), nil))
31 uassert.True(t, verifier(false, true, alice, "anything", nil))
32
33 // Enabled: PA namespace check.
34 uassert.True(t, verifier(true, false, alice, alice.String(), nil))
35
36 // Enabled: non-PA namespaces denied when no registered-name lookup.
37 uassert.False(t, verifier(true, false, alice, "notregistered", nil))
38 uassert.False(t, verifier(true, false, alice, "alice", nil))
39
40 // Enabled: empty name/address.
41 uassert.False(t, verifier(true, false, address(""), "", nil))
42 uassert.False(t, verifier(true, false, alice, "", nil))
43 uassert.False(t, verifier(true, false, address(""), "something", nil))
44}
45
46// TestRegisteredNameVerifier exercises the second authorization path —
47// the registered-name lookup. Uses a fake lookup so this test doesn't
48// depend on r/sys/users state.
49func TestRegisteredNameVerifier(t *testing.T) {
50 // Lookup that says "gnobody" is registered to alice.
51 aliceOwnsGnobody := func(name string) (address, bool) {
52 if name == "gnobody" {
53 return alice, true
54 }
55 return "", false
56 }
57
58 // alice can deploy under "gnobody" (her registered name).
59 uassert.True(t, verifier(true, false, alice, "gnobody", aliceOwnsGnobody))
60
61 // bob cannot deploy under "gnobody" (registered to alice, not bob).
62 uassert.False(t, verifier(true, false, bob, "gnobody", aliceOwnsGnobody))
63
64 // Unknown name still rejects (lookup returns ok=false).
65 uassert.False(t, verifier(true, false, alice, "notregistered", aliceOwnsGnobody))
66
67 // PA path still works alongside registered-name lookup. Tried first.
68 uassert.True(t, verifier(true, false, alice, alice.String(), aliceOwnsGnobody))
69
70 // Disabled bypasses both paths entirely (returns true regardless).
71 uassert.True(t, verifier(false, false, bob, "gnobody", aliceOwnsGnobody))
72
73 // Empty namespace + non-nil lookup: still rejects (early-out before lookup).
74 uassert.False(t, verifier(true, false, alice, "", aliceOwnsGnobody))
75
76 // Lookup returns ok=true for current-but-mismatched address.
77 bobOwnsGnobody := func(name string) (address, bool) {
78 if name == "gnobody" {
79 return bob, true
80 }
81 return "", false
82 }
83 uassert.False(t, verifier(true, false, alice, "gnobody", bobOwnsGnobody))
84}
85
86// TestPausedVerifier covers the emergency-halt semantic. When paused
87// AND enabled, the verifier rejects EVERY namespace check including PA.
88func TestPausedVerifier(t *testing.T) {
89 // Lookup that says "gnobody" is registered to alice. Used to confirm
90 // the registered-name path is also halted by pause.
91 aliceOwnsGnobody := func(name string) (address, bool) {
92 if name == "gnobody" {
93 return alice, true
94 }
95 return "", false
96 }
97
98 t.Run("paused blocks PA namespaces", func(t *testing.T) {
99 // PA would normally succeed (addr.String() == namespace), but
100 // pause short-circuits before the PA check.
101 uassert.False(t, verifier(true, true, alice, alice.String(), nil))
102 uassert.False(t, verifier(true, true, alice, alice.String(), aliceOwnsGnobody))
103 })
104
105 t.Run("paused blocks registered-name namespaces", func(t *testing.T) {
106 // Registered-name path would normally succeed, but pause
107 // short-circuits before the lookup is consulted.
108 uassert.False(t, verifier(true, true, alice, "gnobody", aliceOwnsGnobody))
109 })
110
111 t.Run("paused blocks any other namespace too", func(t *testing.T) {
112 uassert.False(t, verifier(true, true, alice, "anything", aliceOwnsGnobody))
113 uassert.False(t, verifier(true, true, alice, "", aliceOwnsGnobody))
114 uassert.False(t, verifier(true, true, address(""), "anything", aliceOwnsGnobody))
115 })
116
117 t.Run("pre-Enable bypass takes priority over paused", func(t *testing.T) {
118 // !enabled is checked BEFORE paused in the verifier — the
119 // pre-Enable shortcut returns true regardless of pause state.
120 // This is the "pause is staged, applies on Enable" semantic.
121 uassert.True(t, verifier(false, true, alice, alice.String(), nil))
122 uassert.True(t, verifier(false, true, alice, "gnobody", aliceOwnsGnobody))
123 uassert.True(t, verifier(false, true, alice, "anything", nil))
124 })
125
126 t.Run("paused=false with enabled=true behaves normally", func(t *testing.T) {
127 // Sanity: just confirms the false case doesn't accidentally do
128 // something different from the no-pause baseline.
129 uassert.True(t, verifier(true, false, alice, alice.String(), nil))
130 uassert.True(t, verifier(true, false, alice, "gnobody", aliceOwnsGnobody))
131 uassert.False(t, verifier(true, false, bob, "gnobody", aliceOwnsGnobody))
132 })
133}
134
135// TestProposeSetPaused_idempotency verifies the proposal-creation guard:
136// requesting a pause state that already matches the current state panics
137// at proposal-creation time, so voters never see a no-op proposal.
138//
139// NOTE: this test mutates the package-level `paused` var directly to
140// avoid driving the full DAO flow. Restores the value via defer.
141func TestProposeSetPaused_idempotency(cur realm, t *testing.T) {
142 saved := paused
143 defer func() { paused = saved }()
144
145 t.Run("propose pause when already paused panics", func(t *testing.T) {
146 paused = true
147 urequire.PanicsWithMessage(t, cur,
148 "paused state already matches requested value; no-op proposal rejected",
149 func() { ProposeSetPaused(cur, true) })
150 })
151
152 t.Run("propose unpause when already unpaused panics", func(t *testing.T) {
153 paused = false
154 urequire.PanicsWithMessage(t, cur,
155 "paused state already matches requested value; no-op proposal rejected",
156 func() { ProposeSetPaused(cur, false) })
157 })
158
159 t.Run("propose pause when unpaused succeeds", func(t *testing.T) {
160 paused = false
161 urequire.NotPanics(t, cur, func() { ProposeSetPaused(cur, true) })
162 // The proposal-create call doesn't actually mutate paused —
163 // only its execution would. Confirm.
164 uassert.False(t, paused)
165 })
166
167 t.Run("propose unpause when paused succeeds", func(t *testing.T) {
168 paused = true
169 urequire.NotPanics(t, cur, func() { ProposeSetPaused(cur, false) })
170 // Same: proposal-create does not mutate.
171 uassert.True(t, paused)
172 })
173}
174
175// TestSetPaused_internal verifies the private setPaused actuator
176// directly. Bypasses the proposal flow to confirm the toggle and the
177// event-emission path independently.
178func TestSetPaused_internal(cur realm, t *testing.T) {
179 saved := paused
180 defer func() { paused = saved }()
181
182 paused = false
183 setPaused(0, cur, true)
184 uassert.True(t, paused)
185
186 setPaused(0, cur, false)
187 uassert.False(t, paused)
188}
189
190func TestIsPaused(t *testing.T) {
191 saved := paused
192 defer func() { paused = saved }()
193
194 paused = false
195 uassert.False(t, IsPaused())
196
197 paused = true
198 uassert.True(t, IsPaused())
199}
200
201func TestEnable(cur realm, t *testing.T) {
202 testing.SetRealm(testing.NewUserRealm(testutils.TestAddress("random")))
203 uassert.AbortsWithMessage(t, cur, "caller is not admin", func() {
204 Enable(cross(cur))
205 })
206 uassert.False(t, IsEnabled())
207
208 testing.SetRealm(testing.NewUserRealm(admin))
209 uassert.NotPanics(t, cur, func() {
210 Enable(cross(cur))
211 })
212 uassert.True(t, IsEnabled())
213}