oras.land/oras-go/v2@v2.5.1-0.20240520045656-aef90e4d04c4/internal/graph/memory_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 graph 17 18 import ( 19 "bytes" 20 "context" 21 "encoding/json" 22 "io" 23 "reflect" 24 "testing" 25 26 "github.com/opencontainers/go-digest" 27 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 28 "oras.land/oras-go/v2/internal/cas" 29 "oras.land/oras-go/v2/internal/descriptor" 30 ) 31 32 // +------------------------------+ 33 // | | 34 // | +-----------+ | 35 // | |A(manifest)| | 36 // | +-----+-----+ | 37 // | | | 38 // | +------------+ | 39 // | | | | 40 // | v v | 41 // | +-----+-----+ +---+----+ | 42 // | |B(manifest)| |C(layer)| | 43 // | +-----+-----+ +--------+ | 44 // | | | 45 // | v | 46 // | +---+----+ | 47 // | |D(layer)| | 48 // | +--------+ | 49 // | | 50 // |------------------------------+ 51 func TestMemory_IndexAndRemove(t *testing.T) { 52 testFetcher := cas.NewMemory() 53 testMemory := NewMemory() 54 ctx := context.Background() 55 56 // generate test content 57 var blobs [][]byte 58 var descs []ocispec.Descriptor 59 appendBlob := func(mediaType string, blob []byte) ocispec.Descriptor { 60 blobs = append(blobs, blob) 61 descs = append(descs, ocispec.Descriptor{ 62 MediaType: mediaType, 63 Digest: digest.FromBytes(blob), 64 Size: int64(len(blob)), 65 }) 66 return descs[len(descs)-1] 67 } 68 generateManifest := func(layers ...ocispec.Descriptor) ocispec.Descriptor { 69 manifest := ocispec.Manifest{ 70 Config: ocispec.Descriptor{MediaType: "test config"}, 71 Layers: layers, 72 } 73 manifestJSON, err := json.Marshal(manifest) 74 if err != nil { 75 t.Fatal(err) 76 } 77 return appendBlob(ocispec.MediaTypeImageManifest, manifestJSON) 78 } 79 descC := appendBlob("layer node C", []byte("Node C is a layer")) // blobs[0], layer "C" 80 descD := appendBlob("layer node D", []byte("Node D is a layer")) // blobs[1], layer "D" 81 descB := generateManifest(descs[0:2]...) // blobs[2], manifest "B" 82 descA := generateManifest(descs[1:3]...) // blobs[3], manifest "A" 83 84 // prepare the content in the fetcher, so that it can be used to test Index 85 testContents := []ocispec.Descriptor{descC, descD, descB, descA} 86 for i := 0; i < len(blobs); i++ { 87 testFetcher.Push(ctx, testContents[i], bytes.NewReader(blobs[i])) 88 } 89 90 // make sure that testFetcher works 91 rc, err := testFetcher.Fetch(ctx, descA) 92 if err != nil { 93 t.Errorf("testFetcher.Fetch() error = %v", err) 94 } 95 got, err := io.ReadAll(rc) 96 if err != nil { 97 t.Errorf("testFetcher.Fetch().Read() error = %v", err) 98 } 99 err = rc.Close() 100 if err != nil { 101 t.Errorf("testFetcher.Fetch().Close() error = %v", err) 102 } 103 if !bytes.Equal(got, blobs[3]) { 104 t.Errorf("testFetcher.Fetch() = %v, want %v", got, blobs[4]) 105 } 106 107 nodeKeyA := descriptor.FromOCI(descA) 108 nodeKeyB := descriptor.FromOCI(descB) 109 nodeKeyC := descriptor.FromOCI(descC) 110 nodeKeyD := descriptor.FromOCI(descD) 111 112 // index and check the information of node D 113 testMemory.Index(ctx, testFetcher, descD) 114 // 1. verify its existence in testMemory.nodes 115 if _, exists := testMemory.nodes[nodeKeyD]; !exists { 116 t.Errorf("nodes entry of %s should exist", "D") 117 } 118 // 2. verify that the entry of D exists in testMemory.successors and it's empty 119 successorsD, exists := testMemory.successors[nodeKeyD] 120 if !exists { 121 t.Errorf("successor entry of %s should exist", "D") 122 } 123 if successorsD == nil { 124 t.Errorf("successors of %s should be an empty set, not nil", "D") 125 } 126 if len(successorsD) != 0 { 127 t.Errorf("successors of %s should be empty", "D") 128 } 129 // 3. there should be no entry of D in testMemory.predecessors yet 130 _, exists = testMemory.predecessors[nodeKeyD] 131 if exists { 132 t.Errorf("predecessor entry of %s should not exist yet", "D") 133 } 134 135 // index and check the information of node C 136 testMemory.Index(ctx, testFetcher, descC) 137 // 1. verify its existence in memory.nodes 138 if _, exists := testMemory.nodes[nodeKeyC]; !exists { 139 t.Errorf("nodes entry of %s should exist", "C") 140 } 141 // 2. verify that the entry of C exists in testMemory.successors and it's empty 142 successorsC, exists := testMemory.successors[nodeKeyC] 143 if !exists { 144 t.Errorf("successor entry of %s should exist", "C") 145 } 146 if successorsC == nil { 147 t.Errorf("successors of %s should be an empty set, not nil", "C") 148 } 149 if len(successorsC) != 0 { 150 t.Errorf("successors of %s should be empty", "C") 151 } 152 // 3. there should be no entry of C in testMemory.predecessors yet 153 _, exists = testMemory.predecessors[nodeKeyC] 154 if exists { 155 t.Errorf("predecessor entry of %s should not exist yet", "C") 156 } 157 158 // index and check the information of node A 159 testMemory.Index(ctx, testFetcher, descA) 160 // 1. verify its existence in testMemory.nodes 161 if _, exists := testMemory.nodes[nodeKeyA]; !exists { 162 t.Errorf("nodes entry of %s should exist", "A") 163 } 164 // 2. verify that the entry of A exists in testMemory.successors and it contains 165 // node B and node D 166 successorsA, exists := testMemory.successors[nodeKeyA] 167 if !exists { 168 t.Errorf("successor entry of %s should exist", "A") 169 } 170 if successorsA == nil { 171 t.Errorf("successors of %s should be a set, not nil", "A") 172 } 173 if !successorsA.Contains(nodeKeyB) { 174 t.Errorf("successors of %s should contain %s", "A", "B") 175 } 176 if !successorsA.Contains(nodeKeyD) { 177 t.Errorf("successors of %s should contain %s", "A", "D") 178 } 179 // 3. verify that node A exists in the predecessors lists of its successors. 180 // there should be an entry of D in testMemory.predecessors by now and it 181 // should contain A but not B 182 predecessorsD, exists := testMemory.predecessors[nodeKeyD] 183 if !exists { 184 t.Errorf("predecessor entry of %s should exist by now", "D") 185 } 186 if !predecessorsD.Contains(nodeKeyA) { 187 t.Errorf("predecessors of %s should contain %s", "D", "A") 188 } 189 if predecessorsD.Contains(nodeKeyB) { 190 t.Errorf("predecessors of %s should not contain %s yet", "D", "B") 191 } 192 // there should be an entry of B in testMemory.predecessors now 193 // and it should contain A 194 predecessorsB, exists := testMemory.predecessors[nodeKeyB] 195 if !exists { 196 t.Errorf("predecessor entry of %s should exist by now", "B") 197 } 198 if !predecessorsB.Contains(nodeKeyA) { 199 t.Errorf("predecessors of %s should contain %s", "B", "A") 200 } 201 // 4. there should be no entry of A in testMemory.predecessors 202 _, exists = testMemory.predecessors[nodeKeyA] 203 if exists { 204 t.Errorf("predecessor entry of %s should not exist", "A") 205 } 206 207 // index and check the information of node B 208 testMemory.Index(ctx, testFetcher, descB) 209 // 1. verify its existence in testMemory.nodes 210 if _, exists := testMemory.nodes[nodeKeyB]; !exists { 211 t.Errorf("nodes entry of %s should exist", "B") 212 } 213 // 2. verify that the entry of B exists in testMemory.successors and it contains 214 // node C and node D 215 successorsB, exists := testMemory.successors[nodeKeyB] 216 if !exists { 217 t.Errorf("successor entry of %s should exist", "B") 218 } 219 if successorsB == nil { 220 t.Errorf("successors of %s should be a set, not nil", "B") 221 } 222 if !successorsB.Contains(nodeKeyC) { 223 t.Errorf("successors of %s should contain %s", "B", "C") 224 } 225 if !successorsB.Contains(nodeKeyD) { 226 t.Errorf("successors of %s should contain %s", "B", "D") 227 } 228 // 3. verify that node B exists in the predecessors lists of its successors. 229 // there should be an entry of C in testMemory.predecessors by now 230 // and it should contain B 231 predecessorsC, exists := testMemory.predecessors[nodeKeyC] 232 if !exists { 233 t.Errorf("predecessor entry of %s should exist by now", "C") 234 } 235 if !predecessorsC.Contains(nodeKeyB) { 236 t.Errorf("predecessors of %s should contain %s", "C", "B") 237 } 238 // predecessors of D should have been updated now to have node A and B 239 if !predecessorsD.Contains(nodeKeyB) { 240 t.Errorf("predecessors of %s should contain %s", "D", "B") 241 } 242 if !predecessorsD.Contains(nodeKeyA) { 243 t.Errorf("predecessors of %s should contain %s", "D", "A") 244 } 245 246 // remove node B and check the stored information 247 testMemory.Remove(descB) 248 // 1. verify that node B no longer exists in testMemory.nodes 249 if _, exists := testMemory.nodes[nodeKeyB]; exists { 250 t.Errorf("nodes entry of %s should no longer exist", "B") 251 } 252 // 2. verify B' predecessors info: B's entry in testMemory.predecessors should 253 // still exist, since its predecessor A still exists 254 predecessorsB, exists = testMemory.predecessors[nodeKeyB] 255 if !exists { 256 t.Errorf("testDeletableMemory.predecessors should still contain the entry of %s", "B") 257 } 258 if !predecessorsB.Contains(nodeKeyA) { 259 t.Errorf("predecessors of %s should still contain %s", "B", "A") 260 } 261 // 3. verify B' successors info: B's entry in testMemory.successors should no 262 // longer exist 263 if _, exists := testMemory.successors[nodeKeyB]; exists { 264 t.Errorf("testDeletableMemory.successors should not contain the entry of %s", "B") 265 } 266 // 4. verify B' predecessors' successors info: B should still exist in A's 267 // successors 268 if !successorsA.Contains(nodeKeyB) { 269 t.Errorf("successors of %s should still contain %s", "A", "B") 270 } 271 // 5. verify B' successors' predecessors info: C's entry in testMemory.predecessors 272 // should no longer exist, since C's only predecessor B is already deleted 273 if _, exists = testMemory.predecessors[nodeKeyC]; exists { 274 t.Errorf("predecessor entry of %s should no longer exist by now, since all its predecessors have been deleted", "C") 275 } 276 // B should no longer exist in D's predecessors 277 if predecessorsD.Contains(nodeKeyB) { 278 t.Errorf("predecessors of %s should not contain %s", "D", "B") 279 } 280 // but A still exists in D's predecessors 281 if !predecessorsD.Contains(nodeKeyA) { 282 t.Errorf("predecessors of %s should still contain %s", "D", "A") 283 } 284 285 // remove node A and check the stored information 286 testMemory.Remove(descA) 287 // 1. verify that node A no longer exists in testMemory.nodes 288 if _, exists := testMemory.nodes[nodeKeyA]; exists { 289 t.Errorf("nodes entry of %s should no longer exist", "A") 290 } 291 // 2. verify A' successors info: A's entry in testMemory.successors should no 292 // longer exist 293 if _, exists := testMemory.successors[nodeKeyA]; exists { 294 t.Errorf("testDeletableMemory.successors should not contain the entry of %s", "A") 295 } 296 // 3. verify A' successors' predecessors info: D's entry in testMemory.predecessors 297 // should no longer exist, since all predecessors of D are already deleted 298 if _, exists = testMemory.predecessors[nodeKeyD]; exists { 299 t.Errorf("predecessor entry of %s should no longer exist by now, since all its predecessors have been deleted", "D") 300 } 301 // B's entry in testMemory.predecessors should no longer exist, since B's only 302 // predecessor A is already deleted 303 if _, exists = testMemory.predecessors[nodeKeyB]; exists { 304 t.Errorf("predecessor entry of %s should no longer exist by now, since all its predecessors have been deleted", "B") 305 } 306 } 307 308 // +-----------------------------------------------+ 309 // | | 310 // | +--------+ | 311 // | |A(index)| | 312 // | +---+----+ | 313 // | | | 314 // | -+--------------+--------------+- | 315 // | | | | | 316 // | +-----v-----+ +-----v-----+ +-----v-----+ | 317 // | |B(manifest)| |C(manifest)| |D(manifest)| | 318 // | +--------+--+ ++---------++ +--+--------+ | 319 // | | | | | | 320 // | | | | | | 321 // | v v v v | 322 // | ++------++ ++------++ | 323 // | |E(layer)| |F(layer)| | 324 // | +--------+ +--------+ | 325 // | | 326 // +-----------------------------------------------+ 327 func TestMemory_IndexAllAndPredecessors(t *testing.T) { 328 testFetcher := cas.NewMemory() 329 testMemory := NewMemory() 330 ctx := context.Background() 331 332 // generate test content 333 var blobs [][]byte 334 var descriptors []ocispec.Descriptor 335 appendBlob := func(mediaType string, blob []byte) ocispec.Descriptor { 336 blobs = append(blobs, blob) 337 descriptors = append(descriptors, ocispec.Descriptor{ 338 MediaType: mediaType, 339 Digest: digest.FromBytes(blob), 340 Size: int64(len(blob)), 341 }) 342 return descriptors[len(descriptors)-1] 343 } 344 generateManifest := func(layers ...ocispec.Descriptor) ocispec.Descriptor { 345 manifest := ocispec.Manifest{ 346 Config: ocispec.Descriptor{MediaType: "test config"}, 347 Layers: layers, 348 } 349 manifestJSON, err := json.Marshal(manifest) 350 if err != nil { 351 t.Fatal(err) 352 } 353 return appendBlob(ocispec.MediaTypeImageManifest, manifestJSON) 354 } 355 generateIndex := func(manifests ...ocispec.Descriptor) ocispec.Descriptor { 356 index := ocispec.Index{ 357 Manifests: manifests, 358 } 359 indexJSON, err := json.Marshal(index) 360 if err != nil { 361 t.Fatal(err) 362 } 363 return appendBlob(ocispec.MediaTypeImageIndex, indexJSON) 364 } 365 descE := appendBlob("layer node E", []byte("Node E is a layer")) // blobs[0], layer "E" 366 descF := appendBlob("layer node F", []byte("Node F is a layer")) // blobs[1], layer "F" 367 descB := generateManifest(descriptors[0:1]...) // blobs[2], manifest "B" 368 descC := generateManifest(descriptors[0:2]...) // blobs[3], manifest "C" 369 descD := generateManifest(descriptors[1:2]...) // blobs[4], manifest "D" 370 descA := generateIndex(descriptors[2:5]...) // blobs[5], index "A" 371 372 // prepare the content in the fetcher, so that it can be used to test IndexAll 373 testContents := []ocispec.Descriptor{descE, descF, descB, descC, descD, descA} 374 for i := 0; i < len(blobs); i++ { 375 testFetcher.Push(ctx, testContents[i], bytes.NewReader(blobs[i])) 376 } 377 378 // make sure that testFetcher works 379 rc, err := testFetcher.Fetch(ctx, descA) 380 if err != nil { 381 t.Errorf("testFetcher.Fetch() error = %v", err) 382 } 383 got, err := io.ReadAll(rc) 384 if err != nil { 385 t.Errorf("testFetcher.Fetch().Read() error = %v", err) 386 } 387 err = rc.Close() 388 if err != nil { 389 t.Errorf("testFetcher.Fetch().Close() error = %v", err) 390 } 391 if !bytes.Equal(got, blobs[5]) { 392 t.Errorf("testFetcher.Fetch() = %v, want %v", got, blobs[4]) 393 } 394 395 nodeKeyA := descriptor.FromOCI(descA) 396 nodeKeyB := descriptor.FromOCI(descB) 397 nodeKeyC := descriptor.FromOCI(descC) 398 nodeKeyD := descriptor.FromOCI(descD) 399 nodeKeyE := descriptor.FromOCI(descE) 400 nodeKeyF := descriptor.FromOCI(descF) 401 402 // index node A into testMemory using IndexAll 403 testMemory.IndexAll(ctx, testFetcher, descA) 404 405 // check the information of node A 406 // 1. verify that node A exists in testMemory.nodes 407 if _, exists := testMemory.nodes[nodeKeyA]; !exists { 408 t.Errorf("nodes entry of %s should exist", "A") 409 } 410 // 2. verify that there is no entry of A in predecessors 411 if _, exists := testMemory.predecessors[nodeKeyA]; exists { 412 t.Errorf("there should be no entry of %s in predecessors", "A") 413 } 414 // 3. verify that A has successors B, C, D 415 successorsA, exists := testMemory.successors[nodeKeyA] 416 if !exists { 417 t.Errorf("there should be an entry of %s in successors", "A") 418 } 419 if !successorsA.Contains(nodeKeyB) { 420 t.Errorf("successors of %s should contain %s", "A", "B") 421 } 422 if !successorsA.Contains(nodeKeyC) { 423 t.Errorf("successors of %s should contain %s", "A", "C") 424 } 425 if !successorsA.Contains(nodeKeyD) { 426 t.Errorf("successors of %s should contain %s", "A", "D") 427 } 428 429 // check the information of node B 430 // 1. verify that node B exists in testMemory.nodes 431 if _, exists := testMemory.nodes[nodeKeyB]; !exists { 432 t.Errorf("nodes entry of %s should exist", "B") 433 } 434 // 2. verify that B has node A in its predecessors 435 predecessorsB := testMemory.predecessors[nodeKeyB] 436 if !predecessorsB.Contains(nodeKeyA) { 437 t.Errorf("predecessors of %s should contain %s", "B", "A") 438 } 439 // 3. verify that B has node E in its successors 440 successorsB := testMemory.successors[nodeKeyB] 441 if !successorsB.Contains(nodeKeyE) { 442 t.Errorf("successors of %s should contain %s", "B", "E") 443 } 444 445 // check the information of node C 446 // 1. verify that node C exists in testMemory.nodes 447 if _, exists := testMemory.nodes[nodeKeyC]; !exists { 448 t.Errorf("nodes entry of %s should exist", "C") 449 } 450 // 2. verify that C has node A in its predecessors 451 predecessorsC := testMemory.predecessors[nodeKeyC] 452 if !predecessorsC.Contains(nodeKeyA) { 453 t.Errorf("predecessors of %s should contain %s", "C", "A") 454 } 455 // 3. verify that C has node E and F in its successors 456 successorsC := testMemory.successors[nodeKeyC] 457 if !successorsC.Contains(nodeKeyE) { 458 t.Errorf("successors of %s should contain %s", "C", "E") 459 } 460 if !successorsC.Contains(nodeKeyF) { 461 t.Errorf("successors of %s should contain %s", "C", "F") 462 } 463 464 // check the information of node D 465 // 1. verify that node D exists in testMemory.nodes 466 if _, exists := testMemory.nodes[nodeKeyD]; !exists { 467 t.Errorf("nodes entry of %s should exist", "D") 468 } 469 // 2. verify that D has node A in its predecessors 470 predecessorsD := testMemory.predecessors[nodeKeyD] 471 if !predecessorsD.Contains(nodeKeyA) { 472 t.Errorf("predecessors of %s should contain %s", "D", "A") 473 } 474 // 3. verify that D has node F in its successors 475 successorsD := testMemory.successors[nodeKeyD] 476 if !successorsD.Contains(nodeKeyF) { 477 t.Errorf("successors of %s should contain %s", "D", "F") 478 } 479 480 // check the information of node E 481 // 1. verify that node E exists in testMemory.nodes 482 if _, exists := testMemory.nodes[nodeKeyE]; !exists { 483 t.Errorf("nodes entry of %s should exist", "E") 484 } 485 // 2. verify that E has node B and C in its predecessors 486 predecessorsE := testMemory.predecessors[nodeKeyE] 487 if !predecessorsE.Contains(nodeKeyB) { 488 t.Errorf("predecessors of %s should contain %s", "E", "B") 489 } 490 if !predecessorsE.Contains(nodeKeyC) { 491 t.Errorf("predecessors of %s should contain %s", "E", "C") 492 } 493 // 3. verify that E has an entry in successors and it's empty 494 successorsE, exists := testMemory.successors[nodeKeyE] 495 if !exists { 496 t.Errorf("entry %s should exist in testMemory.successors", "E") 497 } 498 if successorsE == nil { 499 t.Errorf("successors of %s should be an empty set, not nil", "E") 500 } 501 if len(successorsE) != 0 { 502 t.Errorf("successors of %s should be empty", "E") 503 } 504 505 // check the information of node F 506 // 1. verify that node F exists in testMemory.nodes 507 if _, exists := testMemory.nodes[nodeKeyF]; !exists { 508 t.Errorf("nodes entry of %s should exist", "F") 509 } 510 // 2. verify that F has node C and D in its predecessors 511 predecessorsF := testMemory.predecessors[nodeKeyF] 512 if !predecessorsF.Contains(nodeKeyC) { 513 t.Errorf("predecessors of %s should contain %s", "F", "C") 514 } 515 if !predecessorsF.Contains(nodeKeyD) { 516 t.Errorf("predecessors of %s should contain %s", "F", "D") 517 } 518 // 3. verify that F has an entry in successors and it's empty 519 successorsF, exists := testMemory.successors[nodeKeyF] 520 if !exists { 521 t.Errorf("entry %s should exist in testMemory.successors", "F") 522 } 523 if successorsF == nil { 524 t.Errorf("successors of %s should be an empty set, not nil", "F") 525 } 526 if len(successorsF) != 0 { 527 t.Errorf("successors of %s should be empty", "F") 528 } 529 530 // check that the Predecessors of node C is node A 531 predsC, err := testMemory.Predecessors(ctx, descC) 532 if err != nil { 533 t.Errorf("testFetcher.Predecessors() error = %v", err) 534 } 535 expectedLength := 1 536 if len(predsC) != expectedLength { 537 t.Errorf("%s should have length %d", "predsC", expectedLength) 538 } 539 if !reflect.DeepEqual(predsC[0], descA) { 540 t.Errorf("incorrect predecessor result") 541 } 542 543 // check that the Predecessors of node F are node C and node D 544 predsF, err := testMemory.Predecessors(ctx, descF) 545 if err != nil { 546 t.Errorf("testFetcher.Predecessors() error = %v", err) 547 } 548 expectedLength = 2 549 if len(predsF) != expectedLength { 550 t.Errorf("%s should have length %d", "predsF", expectedLength) 551 } 552 for _, pred := range predsF { 553 if !reflect.DeepEqual(pred, descC) && !reflect.DeepEqual(pred, descD) { 554 t.Errorf("incorrect predecessor results") 555 } 556 } 557 558 // remove node C and check the stored information 559 testMemory.Remove(descC) 560 if predecessorsE.Contains(nodeKeyC) { 561 t.Errorf("predecessors of %s should not contain %s", "E", "C") 562 } 563 if predecessorsF.Contains(nodeKeyC) { 564 t.Errorf("predecessors of %s should not contain %s", "F", "C") 565 } 566 if !successorsA.Contains(nodeKeyC) { 567 t.Errorf("successors of %s should still contain %s", "A", "C") 568 } 569 if _, exists := testMemory.successors[nodeKeyC]; exists { 570 t.Errorf("testMemory.successors should not contain the entry of %s", "C") 571 } 572 if _, exists := testMemory.predecessors[nodeKeyC]; !exists { 573 t.Errorf("entry %s in predecessors should still exists since it still has at least one predecessor node present", "C") 574 } 575 576 // remove node A and check the stored information 577 testMemory.Remove(descA) 578 if _, exists := testMemory.predecessors[nodeKeyB]; exists { 579 t.Errorf("entry %s in predecessors should no longer exists", "B") 580 } 581 if _, exists := testMemory.predecessors[nodeKeyC]; exists { 582 t.Errorf("entry %s in predecessors should no longer exists", "C") 583 } 584 if _, exists := testMemory.predecessors[nodeKeyD]; exists { 585 t.Errorf("entry %s in predecessors should no longer exists", "D") 586 } 587 if _, exists := testMemory.successors[nodeKeyA]; exists { 588 t.Errorf("testDeletableMemory.successors should not contain the entry of %s", "A") 589 } 590 591 // check that the Predecessors of node D is empty 592 predsD, err := testMemory.Predecessors(ctx, descD) 593 if err != nil { 594 t.Errorf("testFetcher.Predecessors() error = %v", err) 595 } 596 if predsD != nil { 597 t.Errorf("%s should be nil", "predsD") 598 } 599 600 // check that the Predecessors of node E is node B 601 predsE, err := testMemory.Predecessors(ctx, descE) 602 if err != nil { 603 t.Errorf("testFetcher.Predecessors() error = %v", err) 604 } 605 expectedLength = 1 606 if len(predsE) != expectedLength { 607 t.Errorf("%s should have length %d", "predsE", expectedLength) 608 } 609 if !reflect.DeepEqual(predsE[0], descB) { 610 t.Errorf("incorrect predecessor result") 611 } 612 } 613 614 func TestMemory_DigestSet(t *testing.T) { 615 testFetcher := cas.NewMemory() 616 testMemory := NewMemory() 617 ctx := context.Background() 618 619 // generate test content 620 var blobs [][]byte 621 var descriptors []ocispec.Descriptor 622 appendBlob := func(mediaType string, blob []byte) ocispec.Descriptor { 623 blobs = append(blobs, blob) 624 descriptors = append(descriptors, ocispec.Descriptor{ 625 MediaType: mediaType, 626 Digest: digest.FromBytes(blob), 627 Size: int64(len(blob)), 628 }) 629 return descriptors[len(descriptors)-1] 630 } 631 generateManifest := func(layers ...ocispec.Descriptor) ocispec.Descriptor { 632 manifest := ocispec.Manifest{ 633 Config: ocispec.Descriptor{MediaType: "test config"}, 634 Layers: layers, 635 } 636 manifestJSON, err := json.Marshal(manifest) 637 if err != nil { 638 t.Fatal(err) 639 } 640 return appendBlob(ocispec.MediaTypeImageManifest, manifestJSON) 641 } 642 generateIndex := func(manifests ...ocispec.Descriptor) ocispec.Descriptor { 643 index := ocispec.Index{ 644 Manifests: manifests, 645 } 646 indexJSON, err := json.Marshal(index) 647 if err != nil { 648 t.Fatal(err) 649 } 650 return appendBlob(ocispec.MediaTypeImageIndex, indexJSON) 651 } 652 descE := appendBlob("layer node E", []byte("Node E is a layer")) // blobs[0], layer "E" 653 descF := appendBlob("layer node F", []byte("Node F is a layer")) // blobs[1], layer "F" 654 descB := generateManifest(descriptors[0:1]...) // blobs[2], manifest "B" 655 descC := generateManifest(descriptors[0:2]...) // blobs[3], manifest "C" 656 descD := generateManifest(descriptors[1:2]...) // blobs[4], manifest "D" 657 descA := generateIndex(descriptors[2:5]...) // blobs[5], index "A" 658 659 // prepare the content in the fetcher, so that it can be used to test IndexAll 660 testContents := []ocispec.Descriptor{descE, descF, descB, descC, descD, descA} 661 for i := 0; i < len(blobs); i++ { 662 testFetcher.Push(ctx, testContents[i], bytes.NewReader(blobs[i])) 663 } 664 665 // make sure that testFetcher works 666 rc, err := testFetcher.Fetch(ctx, descA) 667 if err != nil { 668 t.Errorf("testFetcher.Fetch() error = %v", err) 669 } 670 got, err := io.ReadAll(rc) 671 if err != nil { 672 t.Errorf("testFetcher.Fetch().Read() error = %v", err) 673 } 674 err = rc.Close() 675 if err != nil { 676 t.Errorf("testFetcher.Fetch().Close() error = %v", err) 677 } 678 if !bytes.Equal(got, blobs[5]) { 679 t.Errorf("testFetcher.Fetch() = %v, want %v", got, blobs[4]) 680 } 681 682 // index node A into testMemory using IndexAll 683 testMemory.IndexAll(ctx, testFetcher, descA) 684 digestSet := testMemory.DigestSet() 685 for i := 0; i < len(blobs); i++ { 686 if exists := digestSet.Contains(descriptors[i].Digest); exists != true { 687 t.Errorf("digest of blob[%d] should exist in digestSet", i) 688 } 689 } 690 } 691 692 func TestMemory_Exists(t *testing.T) { 693 testFetcher := cas.NewMemory() 694 testMemory := NewMemory() 695 ctx := context.Background() 696 697 // generate test content 698 var blobs [][]byte 699 var descriptors []ocispec.Descriptor 700 appendBlob := func(mediaType string, blob []byte) ocispec.Descriptor { 701 blobs = append(blobs, blob) 702 descriptors = append(descriptors, ocispec.Descriptor{ 703 MediaType: mediaType, 704 Digest: digest.FromBytes(blob), 705 Size: int64(len(blob)), 706 }) 707 return descriptors[len(descriptors)-1] 708 } 709 generateManifest := func(layers ...ocispec.Descriptor) ocispec.Descriptor { 710 manifest := ocispec.Manifest{ 711 Config: ocispec.Descriptor{MediaType: "test config"}, 712 Layers: layers, 713 } 714 manifestJSON, err := json.Marshal(manifest) 715 if err != nil { 716 t.Fatal(err) 717 } 718 return appendBlob(ocispec.MediaTypeImageManifest, manifestJSON) 719 } 720 generateIndex := func(manifests ...ocispec.Descriptor) ocispec.Descriptor { 721 index := ocispec.Index{ 722 Manifests: manifests, 723 } 724 indexJSON, err := json.Marshal(index) 725 if err != nil { 726 t.Fatal(err) 727 } 728 return appendBlob(ocispec.MediaTypeImageIndex, indexJSON) 729 } 730 descE := appendBlob("layer node E", []byte("Node E is a layer")) // blobs[0], layer "E" 731 descF := appendBlob("layer node F", []byte("Node F is a layer")) // blobs[1], layer "F" 732 descB := generateManifest(descriptors[0:1]...) // blobs[2], manifest "B" 733 descC := generateManifest(descriptors[0:2]...) // blobs[3], manifest "C" 734 descD := generateManifest(descriptors[1:2]...) // blobs[4], manifest "D" 735 descA := generateIndex(descriptors[2:5]...) // blobs[5], index "A" 736 737 // prepare the content in the fetcher, so that it can be used to test IndexAll 738 testContents := []ocispec.Descriptor{descE, descF, descB, descC, descD, descA} 739 for i := 0; i < len(blobs); i++ { 740 testFetcher.Push(ctx, testContents[i], bytes.NewReader(blobs[i])) 741 } 742 743 // make sure that testFetcher works 744 rc, err := testFetcher.Fetch(ctx, descA) 745 if err != nil { 746 t.Errorf("testFetcher.Fetch() error = %v", err) 747 } 748 got, err := io.ReadAll(rc) 749 if err != nil { 750 t.Errorf("testFetcher.Fetch().Read() error = %v", err) 751 } 752 err = rc.Close() 753 if err != nil { 754 t.Errorf("testFetcher.Fetch().Close() error = %v", err) 755 } 756 if !bytes.Equal(got, blobs[5]) { 757 t.Errorf("testFetcher.Fetch() = %v, want %v", got, blobs[4]) 758 } 759 760 // index node A into testMemory using IndexAll 761 testMemory.IndexAll(ctx, testFetcher, descA) 762 for i := 0; i < len(blobs); i++ { 763 if exists := testMemory.Exists(descriptors[i]); exists != true { 764 t.Errorf("digest of blob[%d] should exist in digestSet", i) 765 } 766 } 767 }