OCI-oriented build engine
2.6 kB
71 lines
1open Alcobar
2open Builder
3
4let clamp n s = if String.length s <= n then s else String.sub s 0 n
5
6(* A short, key-safe token: the cache key is a flat string, so restricting fuzz
7 inputs to [a-zA-Z0-9_-] keeps substring checks meaningful (no separator chars
8 smuggled in) while still exercising the keying logic. *)
9let atom s =
10 let s = clamp 12 s in
11 let b = Bytes.of_string s in
12 for i = 0 to Bytes.length b - 1 do
13 match Bytes.get b i with
14 | 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' | '-' -> ()
15 | _ -> Bytes.set b i 'x'
16 done;
17 let s = Bytes.to_string b in
18 if s = "" then "x" else s
19
20let run ?(argv = [ "true" ]) ?(manager = None) () : Plan.run =
21 {
22 Plan.id = "";
23 cwd = "/";
24 command = String.concat " " argv;
25 shell = [];
26 argv;
27 env = [];
28 user = Builder_spec.root;
29 cache = [];
30 network = [];
31 secrets = [];
32 manager;
33 }
34
35let contains ~needle haystack = Re.execp (Re.compile (Re.str needle)) haystack
36
37(* A plain RUN step's command key always contains its full space-joined argv, so
38 two RUN steps that differ in any argument are distinct steps. *)
39let test_plain_run_keeps_argv a b =
40 let argv = [ atom a; atom b ] in
41 let key = Cache_key.command_key (run ~argv ~manager:None ()) in
42 check (contains ~needle:(String.concat " " argv) key)
43
44(* A package-manager step keys ONLY on its manager tag, independent of the
45 command words: its identity is the resolved layer, carried elsewhere. So two
46 pkg steps sharing a manager have the same command key whatever their argv. *)
47let test_pkg_key_ignores_command m a b =
48 let manager = Some (atom m) in
49 let ka = Cache_key.command_key (run ~manager ~argv:[ atom a ] ()) in
50 let kb = Cache_key.command_key (run ~manager ~argv:[ atom b ] ()) in
51 check (String.equal ka kb)
52
53(* The step id is deterministic and collision-resistant in its op key for a fixed
54 parent (and vice versa). *)
55let test_step_id_injective p o1 o2 =
56 let p = atom p and o1 = atom o1 and o2 = atom o2 in
57 let id po o = Cache_key.step_id ~parent_id:po ~op_key:o in
58 check (String.equal (id p o1) (id p o1));
59 if String.compare o1 o2 <> 0 then
60 check (String.compare (id p o1) (id p o2) <> 0)
61
62let suite =
63 ( "cache_key",
64 [
65 test_case "plain run keeps the full argv" [ bytes; bytes ]
66 test_plain_run_keeps_argv;
67 test_case "pkg key ignores the command words" [ bytes; bytes; bytes ]
68 test_pkg_key_ignores_command;
69 test_case "step id injective in op and parent" [ bytes; bytes; bytes ]
70 test_step_id_injective;
71 ] )