A fork of mtelver's day10 project
at main 207 lines 7.7 kB view raw
1(** Unit tests for Day10_lib.Atomic_swap module. 2 3 These tests verify the atomic swap mechanism for graceful degradation: 4 - Successful swaps replace old docs with new 5 - Failed builds preserve existing docs 6 - Interrupted swaps are recovered on startup *) 7 8let test_dir = ref "" 9 10let setup () = 11 let dir = Filename.temp_dir "test-atomic-swap-" "" in 12 test_dir := dir; 13 (* Create html/p structure *) 14 let html_dir = Filename.concat dir "html" in 15 let p_dir = Filename.concat html_dir "p" in 16 Unix.mkdir html_dir 0o755; 17 Unix.mkdir p_dir 0o755; 18 html_dir 19 20let teardown () = 21 if !test_dir <> "" then begin 22 ignore (Sys.command (Printf.sprintf "rm -rf %s" !test_dir)); 23 test_dir := "" 24 end 25 26let write_file path content = 27 let oc = open_out path in 28 output_string oc content; 29 close_out oc 30 31let read_file path = 32 let ic = open_in path in 33 let content = really_input_string ic (in_channel_length ic) in 34 close_in ic; 35 content 36 37let file_exists path = Sys.file_exists path 38 39(** Test: cleanup_stale_dirs removes .new directories *) 40let test_cleanup_stale_new () = 41 let html_dir = setup () in 42 let pkg_dir = Filename.concat (Filename.concat html_dir "p") "test-pkg" in 43 Unix.mkdir pkg_dir 0o755; 44 let stale_new = Filename.concat pkg_dir "1.0.0.new" in 45 Unix.mkdir stale_new 0o755; 46 write_file (Filename.concat stale_new "index.html") "stale content"; 47 48 assert (file_exists stale_new); 49 Day10_lib.Atomic_swap.cleanup_stale_dirs ~html_dir; 50 assert (not (file_exists stale_new)); 51 52 teardown (); 53 Printf.printf "PASS: test_cleanup_stale_new\n%!" 54 55(** Test: cleanup_stale_dirs removes .old directories *) 56let test_cleanup_stale_old () = 57 let html_dir = setup () in 58 let pkg_dir = Filename.concat (Filename.concat html_dir "p") "test-pkg" in 59 Unix.mkdir pkg_dir 0o755; 60 let stale_old = Filename.concat pkg_dir "1.0.0.old" in 61 Unix.mkdir stale_old 0o755; 62 write_file (Filename.concat stale_old "index.html") "stale old content"; 63 64 assert (file_exists stale_old); 65 Day10_lib.Atomic_swap.cleanup_stale_dirs ~html_dir; 66 assert (not (file_exists stale_old)); 67 68 teardown (); 69 Printf.printf "PASS: test_cleanup_stale_old\n%!" 70 71(** Test: cleanup_stale_dirs preserves normal directories *) 72let test_cleanup_preserves_normal () = 73 let html_dir = setup () in 74 let pkg_dir = Filename.concat (Filename.concat html_dir "p") "test-pkg" in 75 Unix.mkdir pkg_dir 0o755; 76 let normal_dir = Filename.concat pkg_dir "1.0.0" in 77 Unix.mkdir normal_dir 0o755; 78 write_file (Filename.concat normal_dir "index.html") "good content"; 79 80 Day10_lib.Atomic_swap.cleanup_stale_dirs ~html_dir; 81 assert (file_exists normal_dir); 82 assert (read_file (Filename.concat normal_dir "index.html") = "good content"); 83 84 teardown (); 85 Printf.printf "PASS: test_cleanup_preserves_normal\n%!" 86 87(** Test: get_swap_paths returns correct paths for blessed packages *) 88let test_swap_paths_blessed () = 89 let html_dir = "/test/html" in 90 let staging, final, old = Day10_lib.Atomic_swap.get_swap_paths 91 ~html_dir ~pkg:"my-pkg" ~version:"2.0.0" ~blessed:true ~universe:"ignored" in 92 assert (staging = "/test/html/p/my-pkg/2.0.0.new"); 93 assert (final = "/test/html/p/my-pkg/2.0.0"); 94 assert (old = "/test/html/p/my-pkg/2.0.0.old"); 95 Printf.printf "PASS: test_swap_paths_blessed\n%!" 96 97(** Test: get_swap_paths returns correct paths for universe packages *) 98let test_swap_paths_universe () = 99 let html_dir = "/test/html" in 100 let staging, final, old = Day10_lib.Atomic_swap.get_swap_paths 101 ~html_dir ~pkg:"my-pkg" ~version:"2.0.0" ~blessed:false ~universe:"abc123" in 102 assert (staging = "/test/html/u/abc123/my-pkg/2.0.0.new"); 103 assert (final = "/test/html/u/abc123/my-pkg/2.0.0"); 104 assert (old = "/test/html/u/abc123/my-pkg/2.0.0.old"); 105 Printf.printf "PASS: test_swap_paths_universe\n%!" 106 107(** Test: commit swaps staging to final *) 108let test_commit_success () = 109 let html_dir = setup () in 110 let pkg_dir = Filename.concat (Filename.concat html_dir "p") "test-pkg" in 111 Unix.mkdir pkg_dir 0o755; 112 113 (* Create staging directory with new content *) 114 let staging_dir = Filename.concat pkg_dir "1.0.0.new" in 115 Unix.mkdir staging_dir 0o755; 116 write_file (Filename.concat staging_dir "index.html") "new content"; 117 118 let result = Day10_lib.Atomic_swap.commit ~html_dir ~pkg:"test-pkg" ~version:"1.0.0" ~blessed:true ~universe:"" in 119 assert result; 120 121 (* Verify staging was moved to final *) 122 let final_dir = Filename.concat pkg_dir "1.0.0" in 123 assert (file_exists final_dir); 124 assert (read_file (Filename.concat final_dir "index.html") = "new content"); 125 assert (not (file_exists staging_dir)); 126 127 teardown (); 128 Printf.printf "PASS: test_commit_success\n%!" 129 130(** Test: commit replaces existing with atomic swap *) 131let test_commit_replaces_existing () = 132 let html_dir = setup () in 133 let pkg_dir = Filename.concat (Filename.concat html_dir "p") "test-pkg" in 134 Unix.mkdir pkg_dir 0o755; 135 136 (* Create existing final directory with old content *) 137 let final_dir = Filename.concat pkg_dir "1.0.0" in 138 Unix.mkdir final_dir 0o755; 139 write_file (Filename.concat final_dir "index.html") "old content"; 140 141 (* Create staging directory with new content *) 142 let staging_dir = Filename.concat pkg_dir "1.0.0.new" in 143 Unix.mkdir staging_dir 0o755; 144 write_file (Filename.concat staging_dir "index.html") "new content"; 145 146 let result = Day10_lib.Atomic_swap.commit ~html_dir ~pkg:"test-pkg" ~version:"1.0.0" ~blessed:true ~universe:"" in 147 assert result; 148 149 (* Verify old was replaced with new *) 150 assert (read_file (Filename.concat final_dir "index.html") = "new content"); 151 assert (not (file_exists staging_dir)); 152 (* .old should be cleaned up *) 153 assert (not (file_exists (Filename.concat pkg_dir "1.0.0.old"))); 154 155 teardown (); 156 Printf.printf "PASS: test_commit_replaces_existing\n%!" 157 158(** Test: rollback removes staging, preserves existing *) 159let test_rollback_preserves_existing () = 160 let html_dir = setup () in 161 let pkg_dir = Filename.concat (Filename.concat html_dir "p") "test-pkg" in 162 Unix.mkdir pkg_dir 0o755; 163 164 (* Create existing final directory *) 165 let final_dir = Filename.concat pkg_dir "1.0.0" in 166 Unix.mkdir final_dir 0o755; 167 write_file (Filename.concat final_dir "index.html") "original content"; 168 169 (* Create staging directory (simulating failed build) *) 170 let staging_dir = Filename.concat pkg_dir "1.0.0.new" in 171 Unix.mkdir staging_dir 0o755; 172 write_file (Filename.concat staging_dir "index.html") "incomplete content"; 173 174 Day10_lib.Atomic_swap.rollback ~html_dir ~pkg:"test-pkg" ~version:"1.0.0" ~blessed:true ~universe:""; 175 176 (* Verify staging was removed but original preserved *) 177 assert (not (file_exists staging_dir)); 178 assert (file_exists final_dir); 179 assert (read_file (Filename.concat final_dir "index.html") = "original content"); 180 181 teardown (); 182 Printf.printf "PASS: test_rollback_preserves_existing\n%!" 183 184(** Test: commit returns false when staging doesn't exist *) 185let test_commit_no_staging () = 186 let html_dir = setup () in 187 let pkg_dir = Filename.concat (Filename.concat html_dir "p") "test-pkg" in 188 Unix.mkdir pkg_dir 0o755; 189 190 let result = Day10_lib.Atomic_swap.commit ~html_dir ~pkg:"test-pkg" ~version:"1.0.0" ~blessed:true ~universe:"" in 191 assert (not result); 192 193 teardown (); 194 Printf.printf "PASS: test_commit_no_staging\n%!" 195 196let () = 197 Printf.printf "Running atomic swap tests...\n%!"; 198 test_cleanup_stale_new (); 199 test_cleanup_stale_old (); 200 test_cleanup_preserves_normal (); 201 test_swap_paths_blessed (); 202 test_swap_paths_universe (); 203 test_commit_success (); 204 test_commit_replaces_existing (); 205 test_rollback_preserves_existing (); 206 test_commit_no_staging (); 207 Printf.printf "\nAll atomic swap tests passed!\n%!"