Search Apps Documentation Source Content File Folder Download Copy Actions Download

config_test.gno

12.99 Kb ยท 309 lines
  1package config
  2
  3import (
  4	"chain"
  5	"chain/runtime"
  6	"errors"
  7	"testing"
  8
  9	"gno.land/p/moul/authz"
 10	"gno.land/p/nt/testutils"
 11	"gno.land/p/nt/uassert"
 12)
 13
 14var (
 15	originAddr     = testutils.TestAddress("origin")
 16	manager1Addr   = testutils.TestAddress("manager1")
 17	manager2Addr   = testutils.TestAddress("manager2")
 18	nonManagerAddr = testutils.TestAddress("nonManager")
 19)
 20
 21// Helper to reset the Authorizer for each test, simulating initialization.
 22func setupTest(cur realm, t *testing.T) {
 23	t.Helper()
 24
 25	// Set the initial caller context
 26	testing.SetRealm(testing.NewUserRealm(originAddr))
 27	// Initialize the Authorizer with the originAddr as the sole member,
 28	// simulating the state after NewWithOrigin() in a real deployment.
 29	Authorizer = authz.NewWithAuthority(authz.NewMemberAuthority(originAddr))
 30	// Ensure the origin address is the initial manager
 31	uassert.True(t, HasManager(cur, originAddr), "origin should be the initial manager")
 32}
 33
 34func TestAddManager(cur realm, t *testing.T) {
 35	setupTest(cur, t)
 36
 37	// Origin adds manager1 - Should succeed
 38	testing.SetRealm(testing.NewUserRealm(originAddr))
 39	err := AddManager(cross, manager1Addr)
 40	uassert.NoError(t, err, "origin adding manager1 should succeed")
 41	uassert.True(t, HasManager(cur, manager1Addr), "manager1 should now be a manager")
 42
 43	// Non-manager tries to add manager2 - Should fail
 44	testing.SetRealm(testing.NewUserRealm(nonManagerAddr))
 45	err = AddManager(cross, manager2Addr)
 46	uassert.Error(t, err, "non-manager adding manager2 should fail")
 47	uassert.False(t, HasManager(cur, manager2Addr), "manager2 should not have been added")
 48
 49	// Manager1 adds manager2 - Should succeed
 50	testing.SetRealm(testing.NewUserRealm(manager1Addr))
 51	err = AddManager(cross, manager2Addr)
 52	uassert.NoError(t, err, "manager1 adding manager2 should succeed")
 53	uassert.True(t, HasManager(cur, manager2Addr), "manager2 should now be a manager")
 54
 55	// Transfer authority away from MemberAuthority
 56	testing.SetRealm(testing.NewUserRealm(originAddr)) // Origin transfers
 57	err = TransferManagement(cross, authz.NewAutoAcceptAuthority())
 58	uassert.NoError(t, err, "transferring authority should succeed")
 59
 60	// Try adding after transfer - Should fail (wrong authority type)
 61	testing.SetRealm(testing.NewUserRealm(manager1Addr))
 62	err = AddManager(cross, nonManagerAddr) // Try adding someone new
 63	uassert.ErrorContains(t, err, "current authority is not a MemberAuthority", "adding manager should fail after transfer")
 64}
 65
 66func TestRemoveManager(cur realm, t *testing.T) {
 67	setupTest(cur, t)
 68
 69	// Add manager1 first
 70	testing.SetRealm(testing.NewUserRealm(originAddr))
 71	err := AddManager(cross, manager1Addr)
 72	uassert.NoError(t, err, "setup: failed to add manager1")
 73	uassert.True(t, HasManager(cur, manager1Addr), "setup: manager1 should be added")
 74
 75	// Non-manager tries to remove manager1 - Should fail
 76	testing.SetRealm(testing.NewUserRealm(nonManagerAddr))
 77	err = RemoveManager(cross, manager1Addr)
 78	uassert.Error(t, err, "non-manager removing manager1 should fail")
 79	uassert.True(t, HasManager(cur, manager1Addr), "manager1 should still be a manager")
 80
 81	// Origin removes manager1 - Should succeed
 82	testing.SetRealm(testing.NewUserRealm(originAddr))
 83	err = RemoveManager(cross, manager1Addr)
 84	uassert.NoError(t, err, "origin removing manager1 should succeed")
 85	uassert.False(t, HasManager(cur, manager1Addr), "manager1 should now be removed")
 86
 87	// Add manager1 again for next test case
 88	testing.SetRealm(testing.NewUserRealm(originAddr))
 89	err = AddManager(cross, manager1Addr)
 90	uassert.NoError(t, err, "setup: failed to re-add manager1")
 91
 92	// Transfer authority
 93	testing.SetRealm(testing.NewUserRealm(originAddr))
 94	err = TransferManagement(cross, authz.NewAutoAcceptAuthority())
 95	uassert.NoError(t, err, "transferring authority should succeed")
 96
 97	// Try removing after transfer - Should fail (wrong authority type)
 98	testing.SetRealm(testing.NewUserRealm(originAddr)) // Use origin, doesn't matter which user now
 99	err = RemoveManager(cross, manager1Addr)
100	uassert.ErrorContains(t, err, "current authority is not a MemberAuthority", "removing manager should fail after transfer")
101}
102
103func TestListManagers(cur realm, t *testing.T) {
104	setupTest(cur, t)
105	initialList := ListManagers(cross)
106	assertAddrSliceEqual(t, []address{originAddr}, initialList)
107	// Add manager1 and manager2
108	testing.SetRealm(testing.NewUserRealm(originAddr))
109	err := AddManager(cross, manager1Addr)
110	uassert.NoError(t, err)
111	err = AddManager(cross, manager2Addr)
112	uassert.NoError(t, err)
113
114	// List should contain origin, manager1, manager2
115	list1 := ListManagers(cross)
116	expected1 := []address{manager2Addr, manager1Addr, originAddr}
117	assertAddrSliceEqual(t, expected1, list1)
118
119	// Remove manager1
120	testing.SetRealm(testing.NewUserRealm(originAddr)) // Can be origin or manager2
121	err = RemoveManager(cross, manager1Addr)
122	uassert.NoError(t, err)
123
124	// List should contain origin, manager2
125	list2 := ListManagers(cross)
126	expected2 := []address{manager2Addr, originAddr}
127	assertAddrSliceEqual(t, expected2, list2)
128
129	// Transfer authority
130	testing.SetRealm(testing.NewUserRealm(originAddr))
131	err = TransferManagement(cross, authz.NewAutoAcceptAuthority())
132	uassert.NoError(t, err)
133
134	// List should be empty after transfer
135	list3 := ListManagers(cross)
136	uassert.True(t, len(list3) == 0, "manager list should be empty after transfer")
137}
138
139func TestHasManager(cur realm, t *testing.T) {
140	setupTest(cur, t)
141
142	// Initially, only origin is manager
143	uassert.True(t, HasManager(cross, originAddr), "origin should initially be a manager")
144	uassert.False(t, HasManager(cross, manager1Addr), "manager1 should not initially be a manager")
145	uassert.False(t, HasManager(cross, nonManagerAddr), "nonManager should not initially be a manager")
146
147	// Add manager1
148	testing.SetRealm(testing.NewUserRealm(originAddr))
149	err := AddManager(cross, manager1Addr)
150	uassert.NoError(t, err)
151
152	// Check again
153	uassert.True(t, HasManager(cross, originAddr), "origin should still be a manager")
154	uassert.True(t, HasManager(cross, manager1Addr), "manager1 should now be a manager")
155	uassert.False(t, HasManager(cross, nonManagerAddr), "nonManager should still not be a manager")
156
157	// Transfer authority
158	testing.SetRealm(testing.NewUserRealm(originAddr))
159	err = TransferManagement(cross, authz.NewAutoAcceptAuthority())
160	uassert.NoError(t, err)
161
162	// After transfer, HasManager should always return false for MemberAuthority checks
163	uassert.False(t, HasManager(cross, originAddr), "HasManager should be false after transfer")
164	uassert.False(t, HasManager(cross, manager1Addr), "HasManager should be false after transfer")
165	uassert.False(t, HasManager(cross, nonManagerAddr), "HasManager should be false after transfer")
166}
167
168func TestTransferManagement(cur realm, t *testing.T) {
169	setupTest(cur, t)
170
171	// Add manager1
172	testing.SetRealm(testing.NewUserRealm(originAddr))
173	err := AddManager(cross, manager1Addr)
174	uassert.NoError(t, err)
175
176	// Create a new authority (MemberAuthority with manager2)
177	newAuthority := authz.NewMemberAuthority(manager2Addr)
178
179	// Non-manager tries to transfer - Should fail
180	testing.SetRealm(testing.NewUserRealm(nonManagerAddr))
181	err = TransferManagement(cross, newAuthority)
182	uassert.Error(t, err, "non-manager transfer should fail")
183	_, isMemberAuth := Authorizer.Authority().(*authz.MemberAuthority)
184	uassert.True(t, isMemberAuth, "authority should still be MemberAuthority") // Verify it didn't change
185
186	// Manager1 tries to transfer - Should succeed
187	testing.SetRealm(testing.NewUserRealm(manager1Addr))
188	err = TransferManagement(cross, newAuthority)
189	uassert.NoError(t, err, "manager1 transfer should succeed")
190
191	// Verify current authority is the new one
192	currentAuth := Authorizer.Authority()
193	uassert.True(t, currentAuth == newAuthority, "current authority should be the new one")
194
195	// Verify origin is no longer a manager under the *new* authority
196	testing.SetRealm(testing.NewUserRealm(manager2Addr)) // Need new manager to check
197	uassert.False(t, HasManager(cross, originAddr), "origin should not be manager under new authority")
198	uassert.False(t, HasManager(cross, manager1Addr), "manager1 should not be manager under new authority")
199	uassert.True(t, HasManager(cross, manager2Addr), "manager2 should be manager under new authority")
200
201	// Try adding a manager using the old origin - Should fail
202	testing.SetRealm(testing.NewUserRealm(originAddr))
203	err = AddManager(cross, nonManagerAddr)
204	uassert.Error(t, err, "origin should not be able to add manager after transfer")
205
206	// Try adding a manager using the new manager (manager2) - Should succeed
207	testing.SetRealm(testing.NewUserRealm(manager2Addr))
208	err = AddManager(cross, nonManagerAddr)
209	uassert.NoError(t, err, "new manager (manager2) should be able to add managers")
210	uassert.True(t, HasManager(cross, nonManagerAddr), "nonManager should be added by manager2")
211
212	// Try transferring to nil - Should fail
213	testing.SetRealm(testing.NewUserRealm(manager2Addr))
214	err = TransferManagement(cross, nil)
215	uassert.ErrorContains(t, err, "new authority cannot be nil", "transferring to nil should fail")
216}
217
218func TestTransferToContractAuthority(cur realm, t *testing.T) {
219	setupTest(cur, t) // Origin is the initial manager
220
221	contractPath := "gno.land/r/testcontract"
222	contractRealm := testing.NewCodeRealm(contractPath) // Simulate contract realm
223
224	// Define a simple contract authority handler
225	handlerExecuted := false // Track if the handler itself gets called
226	contractAuth := authz.NewContractAuthority(contractPath, func(title string, action authz.PrivilegedAction) error {
227		// Simulate contract checking the caller *before* executing
228		caller := runtime.CurrentRealm().Address()
229		expectedContractAddr := chain.PackageAddress(contractPath)
230		if caller != expectedContractAddr {
231			// Fail before marking executed or running action
232			// Note: In a real scenario, this handler might just ignore the call
233			// if the caller isn't right, rather than returning an error,
234			// depending on the desired contract logic. Returning an error
235			// here helps the test verify the handler wasn't improperly called.
236			return errors.New("handler: caller is not the contract")
237		}
238
239		// Only mark executed and run action if caller is correct
240		handlerExecuted = true
241		return action()
242	})
243
244	// Origin transfers management to the contract authority
245	testing.SetRealm(testing.NewUserRealm(originAddr))
246	err := TransferManagement(cross, contractAuth)
247	uassert.NoError(t, err, "transfer to contract authority failed")
248	uassert.True(t, Authorizer.Authority() == contractAuth, "authority should now be the contract authority")
249
250	// Now, actions like AddManager/RemoveManager should fail because the current
251	// authority is no longer a MemberAuthority. The contract would need its own
252	// logic executed via Authorizer.DoByCurrent() to manage members if desired.
253
254	// Try adding a manager (will check authority type) - Should fail
255	testing.SetRealm(testing.NewUserRealm(originAddr)) // Caller doesn't matter for this check
256	err = AddManager(cross, manager1Addr)
257	uassert.ErrorContains(t, err, "current authority is not a MemberAuthority", "AddManager should fail with ContractAuthority")
258
259	// Simulate an action authorized *by the contract* using Authorizer.Do
260	var contractActionExecuted bool
261	handlerExecuted = false         // Reset tracker
262	testing.SetRealm(contractRealm) // Call must originate from the contract now
263	err = Authorizer.DoByCurrent("some_contract_action", func() error {
264		contractActionExecuted = true
265		// Imagine contract logic here
266		return nil
267	})
268	uassert.NoError(t, err, "contract action via Authorizer.Do failed")
269	uassert.True(t, handlerExecuted, "handler should have been executed by contract call") // Verify handler ran
270	uassert.True(t, contractActionExecuted, "contract action should have been executed")
271
272	// Simulate an action from a user - Should fail before handler is called
273	var userActionExecuted bool
274	handlerExecuted = false // Reset tracker
275	testing.SetRealm(testing.NewUserRealm(nonManagerAddr))
276	err = Authorizer.DoByCurrent("some_user_action", func() error {
277		userActionExecuted = true
278		return nil
279	})
280	// The ContractAuthority.Authorize method should return an error
281	// because the handler now returns an error if the caller isn't the contract.
282	uassert.Error(t, err, "user action via Authorizer.Do should fail when contract is authority")
283	uassert.ErrorContains(t, err, "handler: caller is not the contract", "error should originate from handler check") // Check specific error
284	uassert.False(t, handlerExecuted, "handler should NOT have been executed by user call")                           // Verify handler didn't run past the check
285	uassert.False(t, userActionExecuted, "user action should not have been executed")
286}
287
288// Helper to check if a slice contains a specific address
289func containsAddr(list []address, addr address) bool {
290	for _, item := range list {
291		if item == addr {
292			return true
293		}
294	}
295	return false
296}
297
298func assertAddrSliceEqual(t *testing.T, expected, actual []address) {
299	t.Helper()
300	if len(expected) != len(actual) {
301		t.Fatalf("expected slice length %d, got %d. Expected: %v, Got: %v", len(expected), len(actual), expected, actual)
302	}
303
304	for i := range expected {
305		if expected[i] != actual[i] {
306			t.Fatalf("slices differ at index %d. Expected: %v, Got: %v", i, expected, actual)
307		}
308	}
309}