OCaml library and CLI for OCI and Docker image manipulation
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

pus: rename test_ functions, fix service_type doc (merlint E330/E410)

+214 -220
+1 -1
test/interop/registry/dune
··· 1 1 (test 2 2 (name test) 3 - (libraries oci oci.spec alcotest) 3 + (libraries oci oci.spec alcotest jsont jsont.bytesrw) 4 4 (deps 5 5 (source_tree traces) 6 6 (source_tree scripts)))
+2 -219
test/interop/registry/test.ml
··· 1 - (** Docker Hub registry interop tests for ocaml-oci. 2 - 3 - Traces generated by: Docker Hub registry API (library/alpine:3.19.4) 4 - Regenerate: dune build @regen-traces *) 5 - 6 - open Alcotest 7 - open Oci_spec 8 - 9 - let case = test_case 10 - 11 - let trace path = Filename.concat "traces" path 12 - 13 - let read_file path = 14 - let ic = open_in (trace path) in 15 - let s = In_channel.input_all ic in 16 - close_in ic; 17 - s 18 - 19 - let meta_jsont = 20 - Jsont.Object.map (fun index_digest manifest_digest config_digest -> 21 - (index_digest, manifest_digest, config_digest)) 22 - |> Jsont.Object.mem "index_digest" Jsont.string ~enc:(fun (x, _, _) -> x) 23 - |> Jsont.Object.mem "manifest_digest" Jsont.string ~enc:(fun (_, x, _) -> x) 24 - |> Jsont.Object.mem "config_digest" Jsont.string ~enc:(fun (_, _, x) -> x) 25 - |> Jsont.Object.skip_unknown |> Jsont.Object.finish 26 - 27 - let meta () = 28 - let raw = read_file "meta.json" in 29 - match Jsont_bytesrw.decode_string meta_jsont raw with 30 - | Ok m -> m 31 - | Error e -> Fmt.failwith "meta.json: %s" e 32 - 33 - (* {1 Index parsing} *) 34 - 35 - let parse_index () = 36 - let raw = read_file "index.json" in 37 - match Manifest.of_string raw with 38 - | Error (`Msg e) -> fail e 39 - | Ok (`OCI_index index) -> 40 - let manifests = Index.manifests index in 41 - check bool "has manifests" true (List.length manifests > 0); 42 - check bool "multiple manifests" true (List.length manifests >= 7); 43 - let has_amd64 = 44 - List.exists 45 - (fun d -> 46 - match Descriptor.platform d with 47 - | Some p -> 48 - Arch.to_string (Platform.arch p) = "amd64" 49 - && OS.to_string (Platform.os p) = "linux" 50 - | None -> false) 51 - manifests 52 - in 53 - check bool "has linux/amd64" true has_amd64 54 - | Ok _ -> fail "expected OCI index" 55 - 56 - let index_annotations () = 57 - let raw = read_file "index.json" in 58 - match Manifest.of_string raw with 59 - | Error (`Msg e) -> fail e 60 - | Ok (`OCI_index index) -> 61 - let manifests = Index.manifests index in 62 - let first = List.hd manifests in 63 - let annots = Descriptor.annotations first in 64 - check bool "descriptor has annotations" true (List.length annots > 0); 65 - let has_version = 66 - List.exists (fun (k, _) -> k = Annotation.Version) annots 67 - in 68 - check bool "has version annotation" true has_version 69 - | Ok _ -> fail "expected OCI index" 70 - 71 - let index_digest () = 72 - let expected, _, _ = meta () in 73 - match Digest.of_string expected with 74 - | Ok d -> 75 - check string "algorithm" "sha256" 76 - (Digest.string_of_algorithm (Digest.algorithm d)); 77 - check bool "non-empty hash" true 78 - (String.length (Digest.encoded_hash d) > 0) 79 - | Error (`Msg e) -> fail (Fmt.str "invalid digest: %s" e) 80 - 81 - (* {1 Manifest parsing} *) 82 - 83 - let parse_manifest () = 84 - let raw = read_file "manifest.json" in 85 - match Manifest.of_string raw with 86 - | Error (`Msg e) -> fail e 87 - | Ok (`OCI_manifest m) -> 88 - let layers = Manifest.OCI.layers m in 89 - check bool "has layers" true (List.length layers > 0); 90 - let config = Manifest.OCI.config m in 91 - let config_mt = Descriptor.media_type config in 92 - check string "config media type" 93 - "application/vnd.oci.image.config.v1+json" 94 - (Media_type.to_string config_mt) 95 - | Ok (`Docker_manifest m) -> 96 - let layers = Manifest.Docker.layers m in 97 - check bool "has layers" true (List.length layers > 0); 98 - let config = Manifest.Docker.config m in 99 - let config_mt = Descriptor.media_type config in 100 - check string "config media type" 101 - "application/vnd.docker.container.image.v1+json" 102 - (Media_type.to_string config_mt) 103 - | Ok _ -> fail "expected single-platform manifest" 104 - 105 - let manifest_config_digest () = 106 - let _, _, expected = meta () in 107 - let raw = read_file "manifest.json" in 108 - match Manifest.of_string raw with 109 - | Error (`Msg e) -> fail e 110 - | Ok (`OCI_manifest m) -> 111 - let digest = Descriptor.digest (Manifest.OCI.config m) in 112 - check string "config digest" expected (Digest.to_string digest) 113 - | Ok (`Docker_manifest m) -> 114 - let digest = Descriptor.digest (Manifest.Docker.config m) in 115 - check string "config digest" expected (Digest.to_string digest) 116 - | Ok _ -> fail "expected single-platform manifest" 117 - 118 - (* {1 Config parsing} *) 119 - 120 - let parse_config () = 121 - let raw = read_file "config.json" in 122 - match Config.OCI.of_string raw with 123 - | Error (`Msg e) -> fail e 124 - | Ok config -> 125 - let platform = Config.OCI.platform config in 126 - check string "os" "linux" (OS.to_string (Platform.os platform)); 127 - check string "arch" "amd64" (Arch.to_string (Platform.arch platform)) 128 - 129 - (* {1 Round-trip} *) 130 - 131 - let index_roundtrip () = 132 - let raw = read_file "index.json" in 133 - match Manifest.of_string raw with 134 - | Error (`Msg e) -> fail e 135 - | Ok (`OCI_index index) -> ( 136 - let serialized = Index.to_string index in 137 - match Manifest.of_string serialized with 138 - | Error (`Msg e) -> fail (Fmt.str "round-trip parse failed: %s" e) 139 - | Ok (`OCI_index index2) -> 140 - check int "manifest count" 141 - (List.length (Index.manifests index)) 142 - (List.length (Index.manifests index2)) 143 - | Ok _ -> fail "round-trip changed manifest type") 144 - | Ok _ -> fail "expected OCI index" 145 - 146 - let manifest_roundtrip () = 147 - let raw = read_file "manifest.json" in 148 - match Manifest.of_string raw with 149 - | Error (`Msg e) -> fail e 150 - | Ok manifest -> ( 151 - let serialized = Manifest.to_string manifest in 152 - match Manifest.of_string serialized with 153 - | Error (`Msg e) -> fail (Fmt.str "round-trip parse failed: %s" e) 154 - | Ok manifest2 -> 155 - let size1 = Manifest.size manifest in 156 - let size2 = Manifest.size manifest2 in 157 - check (option int64) "size preserved" size1 size2) 158 - 159 - (* {1 Index.v constructor} *) 160 - 161 - let index_v () = 162 - let desc = 163 - Descriptor.v 164 - ~platform:(Platform.v Arch.Amd64 OS.Linux) 165 - ~annotations: 166 - [ 167 - (Annotation.Other "dev.spaceos.partition.name", "p0"); 168 - (Annotation.Other "dev.spaceos.partition.init", "pid1"); 169 - ] 170 - ~media_type:(OCI Image_manifest) ~size:1234L 171 - (Digest.sha256 172 - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") 173 - in 174 - let index = 175 - Index.v ~artifact_type:"application/vnd.spaceos.build.v1" 176 - ~annotations: 177 - [ (Annotation.Other "dev.spaceos.build.kernel", "linuxkit/kernel:6.6") ] 178 - [ desc ] 179 - in 180 - let json = Index.to_string index in 181 - match Manifest.of_string json with 182 - | Error (`Msg e) -> fail (Fmt.str "Index.v round-trip failed: %s" e) 183 - | Ok (`OCI_index index2) -> 184 - check int "manifests" 1 (List.length (Index.manifests index2)); 185 - let annots = Index.annotations index2 in 186 - let kernel = 187 - List.assoc_opt (Annotation.Other "dev.spaceos.build.kernel") annots 188 - in 189 - check (option string) "kernel annotation" (Some "linuxkit/kernel:6.6") 190 - kernel; 191 - let desc2 = List.hd (Index.manifests index2) in 192 - let desc_annots = Descriptor.annotations desc2 in 193 - let part_name = 194 - List.assoc_opt (Annotation.Other "dev.spaceos.partition.name") 195 - desc_annots 196 - in 197 - check (option string) "partition name" (Some "p0") part_name 198 - | Ok _ -> fail "expected OCI_index" 199 - 200 - (* {1 Test runner} *) 201 - 202 1 let () = 203 - run "oci-registry-interop" 204 - [ 205 - ( "index", 206 - [ 207 - case "parse" `Quick parse_index; 208 - case "annotations" `Quick index_annotations; 209 - case "digest" `Quick index_digest; 210 - case "roundtrip" `Quick index_roundtrip; 211 - case "Index.v constructor" `Quick index_v; 212 - ] ); 213 - ( "manifest", 214 - [ 215 - case "parse" `Quick parse_manifest; 216 - case "config digest" `Quick manifest_config_digest; 217 - case "roundtrip" `Quick manifest_roundtrip; 218 - ] ); 219 - ("config", [ case "parse" `Quick parse_config ]); 220 - ] 2 + Alcotest.run "oci-registry-interop" 3 + [ Test_index.suite; Test_manifest.suite; Test_config.suite ]
+14
test/interop/registry/test_config.ml
··· 1 + open Oci_spec 2 + 3 + let parse () = 4 + let raw = Test_helpers.read_file "config.json" in 5 + match Config.OCI.of_string raw with 6 + | Error (`Msg e) -> Alcotest.fail e 7 + | Ok config -> 8 + let platform = Config.OCI.platform config in 9 + Alcotest.(check string) "os" "linux" (OS.to_string (Platform.os platform)); 10 + Alcotest.(check string) 11 + "arch" "amd64" 12 + (Arch.to_string (Platform.arch platform)) 13 + 14 + let suite = ("config", [ Alcotest.test_case "parse" `Quick parse ])
+1
test/interop/registry/test_config.mli
··· 1 + val suite : string * unit Alcotest.test_case list
+21
test/interop/registry/test_helpers.ml
··· 1 + let trace path = Filename.concat "traces" path 2 + 3 + let read_file path = 4 + let ic = open_in (trace path) in 5 + let s = In_channel.input_all ic in 6 + close_in ic; 7 + s 8 + 9 + let meta_jsont = 10 + Jsont.Object.map (fun index_digest manifest_digest config_digest -> 11 + (index_digest, manifest_digest, config_digest)) 12 + |> Jsont.Object.mem "index_digest" Jsont.string ~enc:(fun (x, _, _) -> x) 13 + |> Jsont.Object.mem "manifest_digest" Jsont.string ~enc:(fun (_, x, _) -> x) 14 + |> Jsont.Object.mem "config_digest" Jsont.string ~enc:(fun (_, _, x) -> x) 15 + |> Jsont.Object.skip_unknown |> Jsont.Object.finish 16 + 17 + let meta () = 18 + let raw = read_file "meta.json" in 19 + match Jsont_bytesrw.decode_string meta_jsont raw with 20 + | Ok m -> m 21 + | Error e -> Fmt.failwith "meta.json: %s" e
+2
test/interop/registry/test_helpers.mli
··· 1 + val read_file : string -> string 2 + val meta : unit -> string * string * string
+116
test/interop/registry/test_index.ml
··· 1 + open Oci_spec 2 + 3 + let parse () = 4 + let raw = Test_helpers.read_file "index.json" in 5 + match Manifest.of_string raw with 6 + | Error (`Msg e) -> Alcotest.fail e 7 + | Ok (`OCI_index index) -> 8 + let manifests = Index.manifests index in 9 + Alcotest.(check bool) "has manifests" true (List.length manifests > 0); 10 + Alcotest.(check bool) 11 + "multiple manifests" true 12 + (List.length manifests >= 7); 13 + let has_amd64 = 14 + List.exists 15 + (fun d -> 16 + match Descriptor.platform d with 17 + | Some p -> 18 + Arch.to_string (Platform.arch p) = "amd64" 19 + && OS.to_string (Platform.os p) = "linux" 20 + | None -> false) 21 + manifests 22 + in 23 + Alcotest.(check bool) "has linux/amd64" true has_amd64 24 + | Ok _ -> Alcotest.fail "expected OCI index" 25 + 26 + let annotations () = 27 + let raw = Test_helpers.read_file "index.json" in 28 + match Manifest.of_string raw with 29 + | Error (`Msg e) -> Alcotest.fail e 30 + | Ok (`OCI_index index) -> 31 + let manifests = Index.manifests index in 32 + let first = List.hd manifests in 33 + let annots = Descriptor.annotations first in 34 + Alcotest.(check bool) "has annotations" true (List.length annots > 0); 35 + let has_version = 36 + List.exists (fun (k, _) -> k = Annotation.Version) annots 37 + in 38 + Alcotest.(check bool) "has version annotation" true has_version 39 + | Ok _ -> Alcotest.fail "expected OCI index" 40 + 41 + let digest () = 42 + let expected, _, _ = Test_helpers.meta () in 43 + match Digest.of_string expected with 44 + | Ok d -> 45 + Alcotest.(check string) 46 + "algorithm" "sha256" 47 + (Digest.string_of_algorithm (Digest.algorithm d)); 48 + Alcotest.(check bool) 49 + "non-empty hash" true 50 + (String.length (Digest.encoded_hash d) > 0) 51 + | Error (`Msg e) -> Alcotest.fail (Fmt.str "invalid digest: %s" e) 52 + 53 + let roundtrip () = 54 + let raw = Test_helpers.read_file "index.json" in 55 + match Manifest.of_string raw with 56 + | Error (`Msg e) -> Alcotest.fail e 57 + | Ok (`OCI_index index) -> ( 58 + let serialized = Index.to_string index in 59 + match Manifest.of_string serialized with 60 + | Error (`Msg e) -> Alcotest.fail (Fmt.str "round-trip failed: %s" e) 61 + | Ok (`OCI_index index2) -> 62 + Alcotest.(check int) 63 + "manifest count" 64 + (List.length (Index.manifests index)) 65 + (List.length (Index.manifests index2)) 66 + | Ok _ -> Alcotest.fail "round-trip changed type") 67 + | Ok _ -> Alcotest.fail "expected OCI index" 68 + 69 + let v_constructor () = 70 + let desc = 71 + Descriptor.v 72 + ~platform:(Platform.v Arch.Amd64 OS.Linux) 73 + ~annotations: 74 + [ 75 + (Annotation.Other "dev.spaceos.partition.name", "p0"); 76 + (Annotation.Other "dev.spaceos.partition.init", "pid1"); 77 + ] 78 + ~media_type:(OCI Image_manifest) ~size:1234L 79 + (Digest.sha256 80 + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") 81 + in 82 + let index = 83 + Index.v ~artifact_type:"application/vnd.spaceos.build.v1" 84 + ~annotations: 85 + [ (Annotation.Other "dev.spaceos.build.kernel", "linuxkit/kernel:6.6") ] 86 + [ desc ] 87 + in 88 + let json = Index.to_string index in 89 + match Manifest.of_string json with 90 + | Error (`Msg e) -> Alcotest.fail (Fmt.str "Index.v round-trip failed: %s" e) 91 + | Ok (`OCI_index index2) -> 92 + Alcotest.(check int) "manifests" 1 (List.length (Index.manifests index2)); 93 + let annots = Index.annotations index2 in 94 + let kernel = 95 + List.assoc_opt (Annotation.Other "dev.spaceos.build.kernel") annots 96 + in 97 + Alcotest.(check (option string)) 98 + "kernel annotation" (Some "linuxkit/kernel:6.6") kernel; 99 + let desc2 = List.hd (Index.manifests index2) in 100 + let desc_annots = Descriptor.annotations desc2 in 101 + let part_name = 102 + List.assoc_opt (Annotation.Other "dev.spaceos.partition.name") 103 + desc_annots 104 + in 105 + Alcotest.(check (option string)) "partition name" (Some "p0") part_name 106 + | Ok _ -> Alcotest.fail "expected OCI_index" 107 + 108 + let suite = 109 + ( "index", 110 + [ 111 + Alcotest.test_case "parse" `Quick parse; 112 + Alcotest.test_case "annotations" `Quick annotations; 113 + Alcotest.test_case "digest" `Quick digest; 114 + Alcotest.test_case "roundtrip" `Quick roundtrip; 115 + Alcotest.test_case "Index.v constructor" `Quick v_constructor; 116 + ] )
+1
test/interop/registry/test_index.mli
··· 1 + val suite : string * unit Alcotest.test_case list
+55
test/interop/registry/test_manifest.ml
··· 1 + open Oci_spec 2 + 3 + let parse () = 4 + let raw = Test_helpers.read_file "manifest.json" in 5 + match Manifest.of_string raw with 6 + | Error (`Msg e) -> Alcotest.fail e 7 + | Ok (`OCI_manifest m) -> 8 + let layers = Manifest.OCI.layers m in 9 + Alcotest.(check bool) "has layers" true (List.length layers > 0); 10 + let config = Manifest.OCI.config m in 11 + Alcotest.(check string) 12 + "config media type" "application/vnd.oci.image.config.v1+json" 13 + (Media_type.to_string (Descriptor.media_type config)) 14 + | Ok (`Docker_manifest m) -> 15 + let layers = Manifest.Docker.layers m in 16 + Alcotest.(check bool) "has layers" true (List.length layers > 0); 17 + let config = Manifest.Docker.config m in 18 + Alcotest.(check string) 19 + "config media type" "application/vnd.docker.container.image.v1+json" 20 + (Media_type.to_string (Descriptor.media_type config)) 21 + | Ok _ -> Alcotest.fail "expected single-platform manifest" 22 + 23 + let config_digest () = 24 + let _, _, expected = Test_helpers.meta () in 25 + let raw = Test_helpers.read_file "manifest.json" in 26 + match Manifest.of_string raw with 27 + | Error (`Msg e) -> Alcotest.fail e 28 + | Ok (`OCI_manifest m) -> 29 + let digest = Descriptor.digest (Manifest.OCI.config m) in 30 + Alcotest.(check string) "config digest" expected (Digest.to_string digest) 31 + | Ok (`Docker_manifest m) -> 32 + let digest = Descriptor.digest (Manifest.Docker.config m) in 33 + Alcotest.(check string) "config digest" expected (Digest.to_string digest) 34 + | Ok _ -> Alcotest.fail "expected single-platform manifest" 35 + 36 + let roundtrip () = 37 + let raw = Test_helpers.read_file "manifest.json" in 38 + match Manifest.of_string raw with 39 + | Error (`Msg e) -> Alcotest.fail e 40 + | Ok manifest -> ( 41 + let serialized = Manifest.to_string manifest in 42 + match Manifest.of_string serialized with 43 + | Error (`Msg e) -> Alcotest.fail (Fmt.str "round-trip failed: %s" e) 44 + | Ok manifest2 -> 45 + let size1 = Manifest.size manifest in 46 + let size2 = Manifest.size manifest2 in 47 + Alcotest.(check (option int64)) "size preserved" size1 size2) 48 + 49 + let suite = 50 + ( "manifest", 51 + [ 52 + Alcotest.test_case "parse" `Quick parse; 53 + Alcotest.test_case "config digest" `Quick config_digest; 54 + Alcotest.test_case "roundtrip" `Quick roundtrip; 55 + ] )
+1
test/interop/registry/test_manifest.mli
··· 1 + val suite : string * unit Alcotest.test_case list