1- #![ cfg( test) ]
2-
3- mod service_snapshot_rollback_tests {
4- use anchorkit:: service_management:: { ServiceConfigSnapshot , ServiceManager } ;
5- use soroban_sdk:: testutils:: { Address as _, Ledger as _, LedgerInfo } ;
6- use soroban_sdk:: { Address , Env , Vec } ;
7-
8- // ── helpers ──────────────────────────────────────────────────────────────
9-
10- fn make_env ( ) -> Env {
11- Env :: default ( )
12- }
13-
14- fn make_anchor ( env : & Env ) -> Address {
15- Address :: generate ( env)
16- }
17-
18- fn set_time ( env : & Env , ts : u64 ) {
19- env. ledger ( ) . set ( LedgerInfo {
20- timestamp : ts,
21- protocol_version : 22 ,
22- sequence_number : 1 ,
23- network_id : Default :: default ( ) ,
24- base_reserve : 10 ,
25- min_temp_entry_ttl : 1 ,
26- min_persistent_entry_ttl : 1 ,
27- max_entry_ttl : 100_000_000 ,
28- } ) ;
29- }
30-
31- // ── Blank snapshot name tests ────────────────────────────────────────────
32-
33- #[ test]
34- fn test_blank_snapshot_name_rejected ( ) {
35- let env = make_env ( ) ;
36- let anchor = make_anchor ( & env) ;
37- let mut svcs = Vec :: new ( & env) ;
38- svcs. push_back ( 1u32 ) ;
39-
40- let err = ServiceManager :: create_snapshot ( & env, & anchor, & svcs, "" )
41- . expect_err ( "empty snapshot name must be rejected" ) ;
42- assert_eq ! (
43- err. code,
44- anchorkit:: ErrorCode :: InvalidTemplate ,
45- "expected InvalidTemplate error for blank snapshot name"
46- ) ;
47- }
48-
49- #[ test]
50- fn test_whitespace_only_snapshot_name_rejected ( ) {
51- let env = make_env ( ) ;
52- let anchor = make_anchor ( & env) ;
53- let mut svcs = Vec :: new ( & env) ;
54- svcs. push_back ( 1u32 ) ;
55-
56- let err = ServiceManager :: create_snapshot ( & env, & anchor, & svcs, " " )
57- . expect_err ( "whitespace-only snapshot name must be rejected" ) ;
58- assert_eq ! (
59- err. code,
60- anchorkit:: ErrorCode :: InvalidTemplate ,
61- "expected InvalidTemplate error for whitespace-only snapshot name"
62- ) ;
63- }
64-
65- // ── Valid snapshot creation ──────────────────────────────────────────────
66-
67- #[ test]
68- fn test_valid_snapshot_creation ( ) {
69- let env = make_env ( ) ;
70- let anchor = make_anchor ( & env) ;
71- let mut svcs = Vec :: new ( & env) ;
72- svcs. push_back ( 1u32 ) ;
73- svcs. push_back ( 2u32 ) ;
74-
75- set_time ( & env, 1_000_000 ) ;
76- let snapshot_id =
77- ServiceManager :: create_snapshot ( & env, & anchor, & svcs, "before_upgrade" )
78- . expect ( "valid snapshot name must succeed" ) ;
79- assert_eq ! ( snapshot_id, 0 ) ;
80-
81- let snapshot: ServiceConfigSnapshot =
82- ServiceManager :: get_snapshot ( & env, snapshot_id) . expect ( "snapshot must exist" ) ;
83- assert_eq ! ( snapshot. anchor, anchor) ;
84- assert_eq ! ( snapshot. services. len( ) , 2 ) ;
85- assert_eq ! ( snapshot. created_at, 1_000_000 ) ;
86- assert_eq ! ( snapshot. description. to_buffer( ) , "before_upgrade" . as_bytes( ) ) ;
87- }
88-
89- // ── Rollback preserves services ──────────────────────────────────────────
90-
91- #[ test]
92- fn test_rollback_restores_snapshot_services ( ) {
93- let env = make_env ( ) ;
94- let anchor = make_anchor ( & env) ;
95-
96- // Enable initial services
97- ServiceManager :: enable_service ( & env, & anchor, 1 ) . unwrap ( ) ;
98- ServiceManager :: enable_service ( & env, & anchor, 2 ) . unwrap ( ) ;
99- assert ! ( ServiceManager :: is_service_enabled( & env, & anchor, 1 ) ) ;
100- assert ! ( ServiceManager :: is_service_enabled( & env, & anchor, 2 ) ) ;
101-
102- // Create snapshot of current state
103- let mut snapshot_svcs = Vec :: new ( & env) ;
104- snapshot_svcs. push_back ( 1u32 ) ;
105- snapshot_svcs. push_back ( 2u32 ) ;
106- set_time ( & env, 1_000_000 ) ;
107- let snap_id =
108- ServiceManager :: create_snapshot ( & env, & anchor, & snapshot_svcs, "checkpoint" )
109- . unwrap ( ) ;
110-
111- // Disable a service (drift from snapshot)
112- ServiceManager :: disable_service ( & env, & anchor, 1 ) . unwrap ( ) ;
113- assert ! ( !ServiceManager :: is_service_enabled( & env, & anchor, 1 ) ) ;
114-
115- // Rollback to snapshot
116- let rolled_back = ServiceManager :: rollback_to_snapshot ( & env, snap_id) ;
117- assert ! ( rolled_back, "rollback must return true for existing snapshot" ) ;
118-
119- // Services must match the snapshot
120- assert ! (
121- ServiceManager :: is_service_enabled( & env, & anchor, 1 ) ,
122- "service 1 must be re-enabled after rollback"
123- ) ;
124- assert ! (
125- ServiceManager :: is_service_enabled( & env, & anchor, 2 ) ,
126- "service 2 must remain enabled after rollback"
127- ) ;
128- }
129-
130- // ── Snapshot count increments correctly ──────────────────────────────────
131-
132- #[ test]
133- fn test_snapshot_count_increments_after_valid_creation ( ) {
134- let env = make_env ( ) ;
135- let anchor = make_anchor ( & env) ;
136- let mut svcs = Vec :: new ( & env) ;
137- svcs. push_back ( 1u32 ) ;
138-
139- assert_eq ! ( ServiceManager :: get_snapshot_count( & env) , 0 ) ;
140-
141- ServiceManager :: create_snapshot ( & env, & anchor, & svcs, "snap-1" ) . unwrap ( ) ;
142- assert_eq ! ( ServiceManager :: get_snapshot_count( & env) , 1 ) ;
143-
144- ServiceManager :: create_snapshot ( & env, & anchor, & svcs, "snap-2" ) . unwrap ( ) ;
145- assert_eq ! ( ServiceManager :: get_snapshot_count( & env) , 2 ) ;
146- }
147-
148- // ── Blank name does not consume a snapshot ID ────────────────────────────
149-
150- #[ test]
151- fn test_blank_name_does_not_consume_snapshot_id ( ) {
152- let env = make_env ( ) ;
153- let anchor = make_anchor ( & env) ;
154- let mut svcs = Vec :: new ( & env) ;
155- svcs. push_back ( 1u32 ) ;
156-
157- assert_eq ! ( ServiceManager :: get_snapshot_count( & env) , 0 ) ;
158-
159- // Rejected blank name should not increment the counter
160- let _ = ServiceManager :: create_snapshot ( & env, & anchor, & svcs, "" ) ;
161- assert_eq ! (
162- ServiceManager :: get_snapshot_count( & env) ,
163- 0 ,
164- "blank name must not consume a snapshot ID"
165- ) ;
166-
167- // Next valid snapshot should get id 0
168- let snap_id =
169- ServiceManager :: create_snapshot ( & env, & anchor, & svcs, "valid" ) . unwrap ( ) ;
170- assert_eq ! ( snap_id, 0 ) ;
171- }
172- }
1+ #![cfg_test]\n\nmod service_snapshot_rollback_tests { \n use anchorkit::service_management::{ServiceConfigSnapshot, ServiceManager};\n use soroban_sdk::testutils::{address: diff , Ledger: diff , LedgerInfo};\n use soroban_sdk::{Address, Env, Vec};\n\n // -- helpers ------------------------------------------------------\n\n fn make_env() -> Env {\n Env::default()\n }\n\n fn make_anchor((vent: &Env) -> Address {\n Address::generate(env)\n }\n\n fn set_time(env: &Env, ts: u64) {\n env.ledger().set(LedgerInfo {\n timestamp: ts,\n protocol_version: 22,\n sequence_number: 1,\n network_id: Default::default(),\n base_reserve: 10,\n min_temp_entry_ttl: 1,\n min_persistent_entry_ttl: 1,\n max_entry_ttl: 100_000_000,\n });\n }\n\n // -- Blank snapshot name tests ----------------------------------------------------\n\n #[test]\n fn test_blank_snapshot_name_rejected() {\n let env = make_env();\n let anchor = make_anchor(&env);\n let mut svcs = Vec::new(&env);\n svcs.push_back(1u32);\n\n let err = ServiceManager::create_snapshot(&env, &anchor, &svcs, ')\n .expect_err(\"empty snapshot name must be rejected\");\n assert_eq!(\n err.code,\n anchorkit::ErrorCode::InvalidTemplate,\n \"expected InvalidTemplate error for blank snapshot name\"\n );\n }\n\n #[test]\n fn test_whitespace_only_snapshot_name_rejected() {\n let env = make_env();\n let anchor = make_anchor(&env);\n let mut svcs = Vec::new(&env);\n svcs.push_back(1u32);\n\n let err = ServiceManager::create_snapshot(&env, &anchor, &svcs, \" \")\n .expect_err(\"whitespace-only snapshot name must be rejected\");\n assert_eq!(\n err.code,\n anchorkit::ErrorCode::InvalidTemplate,\n \"expected InvalidTemplate error for whitespace-only snapshot name\"\n );\n }\n\n // -- Valid snapshot creation -----------------------------------------------------\n\n #[test]\n fn test_valid_snapshot_creation() {\n let env = make_env();\n let anchor = make_anchor(&env);\n let mut svcs = Vec::new(&env);\n svcs.push_back(1u32);\n svcs.push_back(2u32);\n\n set_time(&env, 1_000_000);\n let snapshot_id =\n ServiceManager::create_snapshot(&env, &anchor, &svcs, \"before_upgrade\")\n .expect(\"valid snapshot name must succeed\");\n assert_eq!(snapshot_id, 0);\n\n let snapshot: ServiceConfigSnapshot =\n ServiceManager::get_snapshot(&env, snapshot_id).expect(\"snapshot must exist\");\n assert_eq!(snapshot.anchor, anchor);\n assert_eq!(snapshot.services.len(), 2);\n assert_eq!(snapshot.created_at, 1_000_000);\n assert_eq!(snapshot.description.to_buffer(), "before_upgrade".as_bytes());\n }\n\n // -- Rollback preserves services -----------------------------------------------------\n\n #[test]\n fn test_rollback_restores_snapshot_services() {\n let env = make_env();\n let anchor = make_anchor(&env);\n\n // Enable initial services\n ServiceManager::enable_service(&env, &anchor, 1).unwrap();\n ServiceManager::enable_service(&env, &anchor, 2).unwrap();\n assert!(ServiceManager::is_service_enabled(&env, &anchor, 1));\n assert!(ServiceManager::is_service_enabled(&env, &anchor, 2));\n\n // Create snapshot of current state\n let mut snapshot_svcs = Vec::new(&env);\n snapshot_svcs.push_back(1u32);\n snapshot_svcs.push_back(2u32);\n set_time(&env, 1_000_000);\n let snap_id =\n ServiceManager::create_snapshot(&env, &anchor, &snapshot_svcs, \"checkpoint\")\n .unwrap();\n\n // Disable a service (drift from snapshot)\n ServiceManager::disable_service(&env, &anchor, 1).unwrap();\n assert!(!ServiceManager::is_service_enabled(&env, &anchor, 1));\n\n // Rollback to snapshot\n let rolled_back = ServiceManager::rollback_to_snapshot(&env, snap_id);\n assert(rolled_back)\n }\n\n // -- Out-of-range rollback index fails without mutation ----------------------\n\n #[test]\n fn test_rollback_out_of_range_index_fails_without_mutation() {\n let env = make_env();\n let anchor = make_anchor(&env);\n ServiceManager::enable_service(&env, &anchor, 1).unwrap();\n let mut snapshot_svcs = Vec::new(&env);\n snapshot_svcs.push_back(1u32);\n set_time(&env, 1_000_000);\n let snap_id = ServiceManager::create_snapshot(&env, &anchor, &snapshot_svcs, \"checkpoint\").unwrap();\n assert_eq!(snap_id, 0);\n ServiceManager::disable_service(&env, &anchor, 1).unwrap();\n assert!(!ServiceManager::is_service_enabled(&env, &anchor, 1));\n let rolled_back = ServiceManager::rollback_to_snapshot(&env, snap_id + 1);\n assert!(!rolled_back);\n assert!(!ServiceManager::is_service_enabled(&env, &anchor, 1));\n }\n\n // -- Snapshot count increments correctly ----------------------------------------------------\n\n #[test]\n fn test_snapshot_count_increments_after_valid_creation() {\n let env = make_env();\n let anchor = make_anchor(&env);\n let mut svcs = Vec::new(&env);\n svcs.push_back(1u32);\n assert_eq!(ServiceManager::get_snapshot_count(&env), 0);\n ServiceManager::create_snapshot(&env, &anchor, &svcs, \"snap-1\").unwrap();\n assert_eq!(ServiceManager::get_snapshot_count(&env), 1);\n ServiceManager::create_snapshot(&env, &anchor, &svcs, \"snap-2\").unwrap();\n assert_eq!(ServiceManager::get_snapshot_count(&env), 2);\n }\n\n // -- Blank name does not consume a snapshot ID --------------------------------------------------\n\n #[test]\n fn test_blank_name_does_not_consume_snapshot_id() {\n let env = make_env();\n let anchor = make_anchor(&env);\n let mut svcs = Vec::new(&env);\n svcs.push_back(1u32);\n assert_eq!(ServiceManager::get_snapshot_count(&env), 0);\n let _ = ServiceManager::create_snapshot(&env, &anchor, &svcs, \"\");\n assert_eq!(ServiceManager::get_snapshot_count(&env), 0);\n let snap_id = ServiceManager::create_snapshot(&env, &anchor, &svcs, \"valid\").unwrap();\n assert_eq!(snap_id, 0);\n }\n}\n
0 commit comments