oras.land/oras-go/v2@v2.5.1-0.20240520045656-aef90e4d04c4/content/graph_test.go (about) 1 /* 2 Copyright The ORAS Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package content_test 17 18 import ( 19 "bytes" 20 "context" 21 "encoding/json" 22 "reflect" 23 "testing" 24 25 "github.com/opencontainers/go-digest" 26 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 27 "oras.land/oras-go/v2/content" 28 "oras.land/oras-go/v2/internal/cas" 29 "oras.land/oras-go/v2/internal/docker" 30 "oras.land/oras-go/v2/internal/spec" 31 ) 32 33 func TestSuccessors_dockerManifest(t *testing.T) { 34 storage := cas.NewMemory() 35 36 // generate test content 37 var blobs [][]byte 38 var descs []ocispec.Descriptor 39 appendBlob := func(mediaType string, blob []byte) { 40 blobs = append(blobs, blob) 41 descs = append(descs, ocispec.Descriptor{ 42 MediaType: mediaType, 43 Digest: digest.FromBytes(blob), 44 Size: int64(len(blob)), 45 }) 46 } 47 generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) { 48 manifest := ocispec.Manifest{ 49 Config: config, 50 Layers: layers, 51 } 52 manifestJSON, err := json.Marshal(manifest) 53 if err != nil { 54 t.Fatal(err) 55 } 56 appendBlob(docker.MediaTypeManifest, manifestJSON) 57 } 58 59 appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0 60 appendBlob(ocispec.MediaTypeImageLayer, []byte("foo")) // Blob 1 61 appendBlob(ocispec.MediaTypeImageLayer, []byte("bar")) // Blob 2 62 appendBlob(ocispec.MediaTypeImageLayer, []byte("hello")) // Blob 3 63 generateManifest(descs[0], descs[1:4]...) // Blob 4 64 65 ctx := context.Background() 66 for i := range blobs { 67 err := storage.Push(ctx, descs[i], bytes.NewReader(blobs[i])) 68 if err != nil { 69 t.Fatalf("failed to push test content to src: %d: %v", i, err) 70 } 71 } 72 73 // test Successors 74 manifestDesc := descs[4] 75 got, err := content.Successors(ctx, storage, manifestDesc) 76 if err != nil { 77 t.Fatal("Successors() error =", err) 78 } 79 if want := descs[0:4]; !reflect.DeepEqual(got, want) { 80 t.Errorf("Successors() = %v, want %v", got, want) 81 } 82 } 83 84 func TestSuccessors_imageManifest(t *testing.T) { 85 storage := cas.NewMemory() 86 87 // generate test content 88 var blobs [][]byte 89 var descs []ocispec.Descriptor 90 appendBlob := func(mediaType string, blob []byte) { 91 blobs = append(blobs, blob) 92 descs = append(descs, ocispec.Descriptor{ 93 MediaType: mediaType, 94 Digest: digest.FromBytes(blob), 95 Size: int64(len(blob)), 96 }) 97 } 98 generateManifest := func(subject *ocispec.Descriptor, config ocispec.Descriptor, layers ...ocispec.Descriptor) { 99 manifest := ocispec.Manifest{ 100 Subject: subject, 101 Config: config, 102 Layers: layers, 103 } 104 manifestJSON, err := json.Marshal(manifest) 105 if err != nil { 106 t.Fatal(err) 107 } 108 appendBlob(ocispec.MediaTypeImageManifest, manifestJSON) 109 } 110 111 appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0 112 appendBlob(ocispec.MediaTypeImageLayer, []byte("foo")) // Blob 1 113 appendBlob(ocispec.MediaTypeImageLayer, []byte("bar")) // Blob 2 114 appendBlob(ocispec.MediaTypeImageLayer, []byte("hello")) // Blob 3 115 generateManifest(nil, descs[0], descs[1:4]...) // Blob 4 116 appendBlob(ocispec.MediaTypeImageConfig, []byte("{}")) // Blob 5 117 appendBlob("test/sig", []byte("sig")) // Blob 6 118 generateManifest(&descs[4], descs[5], descs[6]) // Blob 7 119 120 ctx := context.Background() 121 for i := range blobs { 122 err := storage.Push(ctx, descs[i], bytes.NewReader(blobs[i])) 123 if err != nil { 124 t.Fatalf("failed to push test content to src: %d: %v", i, err) 125 } 126 } 127 128 // test Successors: image manifest without a subject 129 manifestDesc := descs[4] 130 got, err := content.Successors(ctx, storage, manifestDesc) 131 if err != nil { 132 t.Fatal("Successors() error =", err) 133 } 134 if want := descs[0:4]; !reflect.DeepEqual(got, want) { 135 t.Errorf("Successors() = %v, want %v", got, want) 136 } 137 138 // test Successors: image manifest with a subject 139 manifestDesc = descs[7] 140 got, err = content.Successors(ctx, storage, manifestDesc) 141 if err != nil { 142 t.Fatal("Successors() error =", err) 143 } 144 if want := descs[4:7]; !reflect.DeepEqual(got, want) { 145 t.Errorf("Successors() = %v, want %v", got, want) 146 } 147 } 148 149 func TestSuccessors_dockerManifestList(t *testing.T) { 150 storage := cas.NewMemory() 151 152 // generate test content 153 var blobs [][]byte 154 var descs []ocispec.Descriptor 155 appendBlob := func(mediaType string, blob []byte) { 156 blobs = append(blobs, blob) 157 descs = append(descs, ocispec.Descriptor{ 158 MediaType: mediaType, 159 Digest: digest.FromBytes(blob), 160 Size: int64(len(blob)), 161 }) 162 } 163 generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) { 164 manifest := ocispec.Manifest{ 165 Config: config, 166 Layers: layers, 167 } 168 manifestJSON, err := json.Marshal(manifest) 169 if err != nil { 170 t.Fatal(err) 171 } 172 appendBlob(docker.MediaTypeManifest, manifestJSON) 173 } 174 generateIndex := func(manifests ...ocispec.Descriptor) { 175 index := ocispec.Index{ 176 Manifests: manifests, 177 } 178 indexJSON, err := json.Marshal(index) 179 if err != nil { 180 t.Fatal(err) 181 } 182 appendBlob(docker.MediaTypeManifestList, indexJSON) 183 } 184 185 appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0 186 appendBlob(ocispec.MediaTypeImageLayer, []byte("foo")) // Blob 1 187 appendBlob(ocispec.MediaTypeImageLayer, []byte("bar")) // Blob 2 188 appendBlob(ocispec.MediaTypeImageLayer, []byte("hello")) // Blob 3 189 generateManifest(descs[0], descs[1:3]...) // Blob 4 190 generateManifest(descs[0], descs[3]) // Blob 5 191 generateIndex(descs[4:6]...) // Blob 6 192 193 ctx := context.Background() 194 for i := range blobs { 195 err := storage.Push(ctx, descs[i], bytes.NewReader(blobs[i])) 196 if err != nil { 197 t.Fatalf("failed to push test content to src: %d: %v", i, err) 198 } 199 } 200 201 // test Successors 202 manifestDesc := descs[6] 203 got, err := content.Successors(ctx, storage, manifestDesc) 204 if err != nil { 205 t.Fatal("Successors() error =", err) 206 } 207 if want := descs[4:6]; !reflect.DeepEqual(got, want) { 208 t.Errorf("Successors() = %v, want %v", got, want) 209 } 210 } 211 212 func TestSuccessors_imageIndex(t *testing.T) { 213 storage := cas.NewMemory() 214 215 // generate test content 216 var blobs [][]byte 217 var descs []ocispec.Descriptor 218 appendBlob := func(mediaType string, blob []byte) { 219 blobs = append(blobs, blob) 220 descs = append(descs, ocispec.Descriptor{ 221 MediaType: mediaType, 222 Digest: digest.FromBytes(blob), 223 Size: int64(len(blob)), 224 }) 225 } 226 generateManifest := func(subject *ocispec.Descriptor, config ocispec.Descriptor, layers ...ocispec.Descriptor) { 227 manifest := ocispec.Manifest{ 228 Subject: subject, 229 Config: config, 230 Layers: layers, 231 } 232 manifestJSON, err := json.Marshal(manifest) 233 if err != nil { 234 t.Fatal(err) 235 } 236 appendBlob(ocispec.MediaTypeImageManifest, manifestJSON) 237 } 238 generateIndex := func(subject *ocispec.Descriptor, manifests ...ocispec.Descriptor) { 239 index := ocispec.Index{ 240 Subject: subject, 241 Manifests: manifests, 242 } 243 indexJSON, err := json.Marshal(index) 244 if err != nil { 245 t.Fatal(err) 246 } 247 appendBlob(ocispec.MediaTypeImageIndex, indexJSON) 248 } 249 250 appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0 251 appendBlob(ocispec.MediaTypeImageLayer, []byte("foo")) // Blob 1 252 appendBlob(ocispec.MediaTypeImageLayer, []byte("bar")) // Blob 2 253 appendBlob(ocispec.MediaTypeImageLayer, []byte("hello")) // Blob 3 254 generateManifest(nil, descs[0], descs[1:3]...) // Blob 4 255 generateManifest(nil, descs[0], descs[3]) // Blob 5 256 appendBlob(ocispec.MediaTypeImageConfig, []byte("{}")) // Blob 6 257 appendBlob("test/sig", []byte("sig")) // Blob 7 258 generateManifest(&descs[4], descs[5], descs[6]) // Blob 8 259 generateIndex(&descs[8], descs[4:6]...) // Blob 9 260 261 ctx := context.Background() 262 for i := range blobs { 263 err := storage.Push(ctx, descs[i], bytes.NewReader(blobs[i])) 264 if err != nil { 265 t.Fatalf("failed to push test content to src: %d: %v", i, err) 266 } 267 } 268 269 // test Successors 270 manifestDesc := descs[9] 271 got, err := content.Successors(ctx, storage, manifestDesc) 272 if err != nil { 273 t.Fatal("Successors() error =", err) 274 } 275 if want := append([]ocispec.Descriptor{descs[8]}, descs[4:6]...); !reflect.DeepEqual(got, want) { 276 t.Errorf("Successors() = %v, want %v", got, want) 277 } 278 } 279 280 func TestSuccessors_artifactManifest(t *testing.T) { 281 storage := cas.NewMemory() 282 283 // generate test content 284 var blobs [][]byte 285 var descs []ocispec.Descriptor 286 appendBlob := func(mediaType string, blob []byte) { 287 blobs = append(blobs, blob) 288 descs = append(descs, ocispec.Descriptor{ 289 MediaType: mediaType, 290 Digest: digest.FromBytes(blob), 291 Size: int64(len(blob)), 292 }) 293 } 294 generateArtifactManifest := func(subject *ocispec.Descriptor, blobs ...ocispec.Descriptor) { 295 manifest := spec.Artifact{ 296 Subject: subject, 297 Blobs: blobs, 298 } 299 manifestJSON, err := json.Marshal(manifest) 300 if err != nil { 301 t.Fatal(err) 302 } 303 appendBlob(spec.MediaTypeArtifactManifest, manifestJSON) 304 } 305 306 appendBlob(ocispec.MediaTypeImageLayer, []byte("foo")) // Blob 0 307 appendBlob(ocispec.MediaTypeImageLayer, []byte("bar")) // Blob 1 308 appendBlob(ocispec.MediaTypeImageLayer, []byte("hello")) // Blob 2 309 generateArtifactManifest(nil, descs[0:3]...) // Blob 3 310 appendBlob("test/sig", []byte("sig")) // Blob 4 311 generateArtifactManifest(&descs[3], descs[4]) // Blob 5 312 313 ctx := context.Background() 314 for i := range blobs { 315 err := storage.Push(ctx, descs[i], bytes.NewReader(blobs[i])) 316 if err != nil { 317 t.Fatalf("failed to push test content to src: %d: %v", i, err) 318 } 319 } 320 321 // test Successors: image manifest without a subject 322 manifestDesc := descs[3] 323 got, err := content.Successors(ctx, storage, manifestDesc) 324 if err != nil { 325 t.Fatal("Successors() error =", err) 326 } 327 if want := descs[0:3]; !reflect.DeepEqual(got, want) { 328 t.Errorf("Successors() = %v, want %v", got, want) 329 } 330 331 // test Successors: image manifest with a subject 332 manifestDesc = descs[5] 333 got, err = content.Successors(ctx, storage, manifestDesc) 334 if err != nil { 335 t.Fatal("Successors() error =", err) 336 } 337 if want := descs[3:5]; !reflect.DeepEqual(got, want) { 338 t.Errorf("Successors() = %v, want %v", got, want) 339 } 340 } 341 342 func TestSuccessors_otherMediaType(t *testing.T) { 343 storage := cas.NewMemory() 344 345 // generate test content 346 var blobs [][]byte 347 var descs []ocispec.Descriptor 348 appendBlob := func(mediaType string, blob []byte) { 349 blobs = append(blobs, blob) 350 descs = append(descs, ocispec.Descriptor{ 351 MediaType: mediaType, 352 Digest: digest.FromBytes(blob), 353 Size: int64(len(blob)), 354 }) 355 } 356 generateManifest := func(mediaType string, config ocispec.Descriptor, layers ...ocispec.Descriptor) { 357 manifest := ocispec.Manifest{ 358 Config: config, 359 Layers: layers, 360 } 361 manifestJSON, err := json.Marshal(manifest) 362 if err != nil { 363 t.Fatal(err) 364 } 365 appendBlob(mediaType, manifestJSON) 366 } 367 368 appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0 369 appendBlob(ocispec.MediaTypeImageLayer, []byte("foo")) // Blob 1 370 appendBlob(ocispec.MediaTypeImageLayer, []byte("bar")) // Blob 2 371 appendBlob(ocispec.MediaTypeImageLayer, []byte("hello")) // Blob 3 372 generateManifest("whatever", descs[0], descs[1:4]...) // Blob 4 373 374 ctx := context.Background() 375 for i := range blobs { 376 err := storage.Push(ctx, descs[i], bytes.NewReader(blobs[i])) 377 if err != nil { 378 t.Fatalf("failed to push test content to src: %d: %v", i, err) 379 } 380 } 381 382 // test Successors: other media type 383 manifestDesc := descs[4] 384 got, err := content.Successors(ctx, storage, manifestDesc) 385 if err != nil { 386 t.Fatal("Successors() error =", err) 387 } 388 if got != nil { 389 t.Errorf("Successors() = %v, want nil", got) 390 } 391 }