this repo has no description
at main 6.1 kB view raw
1open Swim.Types 2open Swim.Codec 3 4let clamp_int32 n = n land 0x7FFFFFFF 5 6let clamp_incarnation inc = 7 incarnation_of_int (clamp_int32 (incarnation_to_int inc)) 8 9let normalize_msg msg = 10 match msg with 11 | Ping { seq; target; sender } -> 12 Ping { seq = clamp_int32 seq; target; sender } 13 | Ping_req { seq; target; sender } -> 14 Ping_req { seq = clamp_int32 seq; target; sender } 15 | Ack { seq; responder; payload } -> 16 Ack { seq = clamp_int32 seq; responder; payload } 17 | Alive { node; incarnation } -> 18 Alive { node; incarnation = clamp_incarnation incarnation } 19 | Suspect { node; incarnation; suspector } -> 20 Suspect { node; incarnation = clamp_incarnation incarnation; suspector } 21 | Dead { node; incarnation; declarator } -> 22 Dead { node; incarnation = clamp_incarnation incarnation; declarator } 23 | User_msg _ as msg -> msg 24 25let normalize_packet packet = 26 let primary = normalize_msg packet.primary in 27 let piggyback = List.map normalize_msg packet.piggyback in 28 { packet with primary; piggyback } 29 30let test_roundtrip_packet = 31 QCheck.Test.make ~count:500 ~name:"codec packet roundtrip" 32 Generators.arb_packet (fun packet -> 33 let packet = normalize_packet packet in 34 let size = 8192 in 35 let buf = Cstruct.create size in 36 match encode_packet packet ~buf with 37 | Error _ -> true 38 | Ok len -> ( 39 let encoded = Cstruct.sub buf 0 len in 40 match decode_packet encoded with 41 | Ok decoded -> 42 List.length decoded.piggyback = List.length packet.piggyback 43 | Error _ -> true)) 44 45let test_empty_piggyback () = 46 let node = 47 make_node_info 48 ~id:(node_id_of_string "node1") 49 ~addr:(`Udp (Eio.Net.Ipaddr.of_raw "\127\000\000\001", 7946)) 50 ~meta:"" 51 in 52 let packet = 53 { 54 cluster = "test"; 55 primary = 56 Ping { seq = 1; target = node_id_of_string "target"; sender = node }; 57 piggyback = []; 58 } 59 in 60 let buf = Cstruct.create 1000 in 61 match encode_packet packet ~buf with 62 | Error _ -> Alcotest.fail "encode failed" 63 | Ok len -> ( 64 let encoded = Cstruct.sub buf 0 len in 65 match decode_packet encoded with 66 | Ok decoded -> 67 Alcotest.(check int) 68 "piggyback count" 0 69 (List.length decoded.piggyback) 70 | Error e -> Alcotest.failf "decode failed: %s" (decode_error_to_string e) 71 ) 72 73let test_multiple_piggyback () = 74 let node = 75 make_node_info 76 ~id:(node_id_of_string "node1") 77 ~addr:(`Udp (Eio.Net.Ipaddr.of_raw "\127\000\000\001", 7946)) 78 ~meta:"" 79 in 80 let alive_state : member_state = Alive in 81 let _ = alive_state in 82 let piggyback = 83 [ 84 Alive { node; incarnation = incarnation_of_int 1 }; 85 Suspect 86 { 87 node = node_id_of_string "node2"; 88 incarnation = incarnation_of_int 2; 89 suspector = node_id_of_string "node1"; 90 }; 91 Dead 92 { 93 node = node_id_of_string "node3"; 94 incarnation = incarnation_of_int 3; 95 declarator = node_id_of_string "node1"; 96 }; 97 ] 98 in 99 let packet = 100 { 101 cluster = "test"; 102 primary = 103 Ping { seq = 1; target = node_id_of_string "target"; sender = node }; 104 piggyback; 105 } 106 in 107 let buf = Cstruct.create 2000 in 108 match encode_packet packet ~buf with 109 | Error _ -> Alcotest.fail "encode failed" 110 | Ok len -> ( 111 let encoded = Cstruct.sub buf 0 len in 112 match decode_packet encoded with 113 | Ok decoded -> 114 Alcotest.(check int) 115 "piggyback count" 3 116 (List.length decoded.piggyback) 117 | Error e -> Alcotest.failf "decode failed: %s" (decode_error_to_string e) 118 ) 119 120let test_crc_roundtrip () = 121 let data = "hello world" in 122 let with_crc = add_crc data in 123 match verify_and_strip_crc_string with_crc with 124 | Ok stripped -> Alcotest.(check string) "stripped" data stripped 125 | Error _ -> Alcotest.fail "CRC verification failed" 126 127let test_crc_corruption_detected () = 128 let data = "hello world" in 129 let with_crc = add_crc data in 130 let corrupted = Bytes.of_string with_crc in 131 Bytes.set corrupted 6 '\xFF'; 132 match verify_and_strip_crc_string (Bytes.to_string corrupted) with 133 | Error Invalid_crc -> () 134 | _ -> Alcotest.fail "expected CRC error" 135 136let test_label_roundtrip () = 137 let label = "my-label" in 138 let data = "payload data" in 139 let with_label = add_label label data in 140 match strip_label_string with_label with 141 | Ok (stripped, extracted_label) -> 142 Alcotest.(check string) "payload" data stripped; 143 Alcotest.(check string) "label" label extracted_label 144 | Error _ -> Alcotest.fail "label extraction failed" 145 146let test_empty_label () = 147 let data = "payload data" in 148 let with_label = add_label "" data in 149 Alcotest.(check string) "no change" data with_label 150 151let test_compound_msg_roundtrip () = 152 let msgs = [ "msg1"; "msg2"; "msg3" ] in 153 let compound = make_compound_msg msgs in 154 let payload = String.sub compound 1 (String.length compound - 1) in 155 match decode_compound_msg payload with 156 | Ok (decoded, trunc) -> 157 Alcotest.(check int) "no truncation" 0 trunc; 158 Alcotest.(check int) "msg count" 3 (List.length decoded); 159 Alcotest.(check string) "msg1" "msg1" (List.nth decoded 0); 160 Alcotest.(check string) "msg2" "msg2" (List.nth decoded 1); 161 Alcotest.(check string) "msg3" "msg3" (List.nth decoded 2) 162 | Error _ -> Alcotest.fail "compound decode failed" 163 164let qcheck_tests = 165 List.map QCheck_alcotest.to_alcotest [ test_roundtrip_packet ] 166 167let unit_tests = 168 [ 169 ("empty_piggyback", `Quick, test_empty_piggyback); 170 ("multiple_piggyback", `Quick, test_multiple_piggyback); 171 ("crc_roundtrip", `Quick, test_crc_roundtrip); 172 ("crc_corruption_detected", `Quick, test_crc_corruption_detected); 173 ("label_roundtrip", `Quick, test_label_roundtrip); 174 ("empty_label", `Quick, test_empty_label); 175 ("compound_msg_roundtrip", `Quick, test_compound_msg_roundtrip); 176 ] 177 178let () = 179 Alcotest.run "codec" [ ("property", qcheck_tests); ("unit", unit_tests) ]