github.com/dtroyer-salad/og2/v2@v2.0.0-20240412154159-c47231610877/content/oci/oci_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 oci
    17  
    18  import (
    19  	"bytes"
    20  	"context"
    21  	_ "crypto/sha256"
    22  	"encoding/json"
    23  	"errors"
    24  	"fmt"
    25  	"io"
    26  	"os"
    27  	"path"
    28  	"path/filepath"
    29  	"reflect"
    30  	"strconv"
    31  	"strings"
    32  	"sync/atomic"
    33  	"testing"
    34  
    35  	"github.com/opencontainers/go-digest"
    36  	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
    37  	"golang.org/x/sync/errgroup"
    38  	"oras.land/oras-go/v2"
    39  	"oras.land/oras-go/v2/content"
    40  	"oras.land/oras-go/v2/content/memory"
    41  	"oras.land/oras-go/v2/errdef"
    42  	"oras.land/oras-go/v2/internal/cas"
    43  	"oras.land/oras-go/v2/internal/descriptor"
    44  	"oras.land/oras-go/v2/internal/spec"
    45  	"oras.land/oras-go/v2/registry"
    46  )
    47  
    48  // storageTracker tracks storage API counts.
    49  type storageTracker struct {
    50  	content.Storage
    51  	fetch  int64
    52  	push   int64
    53  	exists int64
    54  }
    55  
    56  func (t *storageTracker) Fetch(ctx context.Context, target ocispec.Descriptor) (io.ReadCloser, error) {
    57  	atomic.AddInt64(&t.fetch, 1)
    58  	return t.Storage.Fetch(ctx, target)
    59  }
    60  
    61  func (t *storageTracker) Push(ctx context.Context, expected ocispec.Descriptor, content io.Reader) error {
    62  	atomic.AddInt64(&t.push, 1)
    63  	return t.Storage.Push(ctx, expected, content)
    64  }
    65  
    66  func (t *storageTracker) Exists(ctx context.Context, target ocispec.Descriptor) (bool, error) {
    67  	atomic.AddInt64(&t.exists, 1)
    68  	return t.Storage.Exists(ctx, target)
    69  }
    70  
    71  func TestStoreInterface(t *testing.T) {
    72  	var store interface{} = &Store{}
    73  	if _, ok := store.(oras.GraphTarget); !ok {
    74  		t.Error("&Store{} does not conform oras.Target")
    75  	}
    76  	if _, ok := store.(registry.TagLister); !ok {
    77  		t.Error("&Store{} does not conform registry.TagLister")
    78  	}
    79  }
    80  
    81  func TestStore_Success(t *testing.T) {
    82  	blob := []byte("test")
    83  	blobDesc := content.NewDescriptorFromBytes("test", blob)
    84  	manifest := []byte(`{"layers":[]}`)
    85  	manifestDesc := content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest)
    86  	ref := "foobar"
    87  
    88  	tempDir := t.TempDir()
    89  	s, err := New(tempDir)
    90  	if err != nil {
    91  		t.Fatal("New() error =", err)
    92  	}
    93  	ctx := context.Background()
    94  
    95  	// validate layout
    96  	layoutFilePath := filepath.Join(tempDir, ocispec.ImageLayoutFile)
    97  	layoutFile, err := os.Open(layoutFilePath)
    98  	if err != nil {
    99  		t.Errorf("error opening layout file, error = %v", err)
   100  	}
   101  	defer layoutFile.Close()
   102  
   103  	var layout *ocispec.ImageLayout
   104  	err = json.NewDecoder(layoutFile).Decode(&layout)
   105  	if err != nil {
   106  		t.Fatal("error decoding layout, error =", err)
   107  	}
   108  	if want := ocispec.ImageLayoutVersion; layout.Version != want {
   109  		t.Errorf("layout.Version = %s, want %s", layout.Version, want)
   110  	}
   111  
   112  	// validate index.json
   113  	indexFilePath := filepath.Join(tempDir, "index.json")
   114  	indexFile, err := os.Open(indexFilePath)
   115  	if err != nil {
   116  		t.Errorf("error opening layout file, error = %v", err)
   117  	}
   118  	defer indexFile.Close()
   119  
   120  	var index *ocispec.Index
   121  	err = json.NewDecoder(indexFile).Decode(&index)
   122  	if err != nil {
   123  		t.Fatal("error decoding index.json, error =", err)
   124  	}
   125  	if want := 2; index.SchemaVersion != want {
   126  		t.Errorf("index.SchemaVersion = %v, want %v", index.SchemaVersion, want)
   127  	}
   128  
   129  	// test push blob
   130  	err = s.Push(ctx, blobDesc, bytes.NewReader(blob))
   131  	if err != nil {
   132  		t.Fatal("Store.Push() error =", err)
   133  	}
   134  	internalResolver := s.tagResolver
   135  	if got, want := len(internalResolver.Map()), 0; got != want {
   136  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   137  	}
   138  
   139  	// test push manifest
   140  	err = s.Push(ctx, manifestDesc, bytes.NewReader(manifest))
   141  	if err != nil {
   142  		t.Fatal("Store.Push() error =", err)
   143  	}
   144  	if got, want := len(internalResolver.Map()), 1; got != want {
   145  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   146  	}
   147  
   148  	// test resolving blob by digest
   149  	gotDesc, err := s.Resolve(ctx, blobDesc.Digest.String())
   150  	if err != nil {
   151  		t.Fatal("Store.Resolve() error =", err)
   152  	}
   153  	if want := blobDesc; gotDesc.Size != want.Size || gotDesc.Digest != want.Digest {
   154  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, blobDesc)
   155  	}
   156  
   157  	// test resolving manifest by digest
   158  	gotDesc, err = s.Resolve(ctx, manifestDesc.Digest.String())
   159  	if err != nil {
   160  		t.Fatal("Store.Resolve() error =", err)
   161  	}
   162  	if !reflect.DeepEqual(gotDesc, manifestDesc) {
   163  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, manifestDesc)
   164  	}
   165  
   166  	// test tag
   167  	err = s.Tag(ctx, manifestDesc, ref)
   168  	if err != nil {
   169  		t.Fatal("Store.Tag() error =", err)
   170  	}
   171  	if got, want := len(internalResolver.Map()), 2; got != want {
   172  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   173  	}
   174  
   175  	// test resolving manifest by tag
   176  	gotDesc, err = s.Resolve(ctx, ref)
   177  	if err != nil {
   178  		t.Fatal("Store.Resolve() error =", err)
   179  	}
   180  	if !reflect.DeepEqual(gotDesc, manifestDesc) {
   181  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, manifestDesc)
   182  	}
   183  
   184  	// test fetch
   185  	exists, err := s.Exists(ctx, manifestDesc)
   186  	if err != nil {
   187  		t.Fatal("Store.Exists() error =", err)
   188  	}
   189  	if !exists {
   190  		t.Errorf("Store.Exists() = %v, want %v", exists, true)
   191  	}
   192  
   193  	rc, err := s.Fetch(ctx, manifestDesc)
   194  	if err != nil {
   195  		t.Fatal("Store.Fetch() error =", err)
   196  	}
   197  	got, err := io.ReadAll(rc)
   198  	if err != nil {
   199  		t.Fatal("Store.Fetch().Read() error =", err)
   200  	}
   201  	err = rc.Close()
   202  	if err != nil {
   203  		t.Error("Store.Fetch().Close() error =", err)
   204  	}
   205  	if !bytes.Equal(got, manifest) {
   206  		t.Errorf("Store.Fetch() = %v, want %v", got, manifest)
   207  	}
   208  }
   209  
   210  func TestStore_RelativeRoot_Success(t *testing.T) {
   211  	blob := []byte("test")
   212  	blobDesc := content.NewDescriptorFromBytes("test", blob)
   213  	manifest := []byte(`{"layers":[]}`)
   214  	manifestDesc := content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest)
   215  	ref := "foobar"
   216  
   217  	tempDir, err := filepath.EvalSymlinks(t.TempDir())
   218  	if err != nil {
   219  		t.Fatal("error calling filepath.EvalSymlinks(), error =", err)
   220  	}
   221  	currDir, err := os.Getwd()
   222  	if err != nil {
   223  		t.Fatal("error calling Getwd(), error=", err)
   224  	}
   225  	if err := os.Chdir(tempDir); err != nil {
   226  		t.Fatal("error calling Chdir(), error=", err)
   227  	}
   228  	s, err := New(".")
   229  	if err != nil {
   230  		t.Fatal("New() error =", err)
   231  	}
   232  	if want := tempDir; s.root != want {
   233  		t.Errorf("Store.root = %s, want %s", s.root, want)
   234  	}
   235  	// cd back to allow the temp directory to be removed
   236  	if err := os.Chdir(currDir); err != nil {
   237  		t.Fatal("error calling Chdir(), error=", err)
   238  	}
   239  	ctx := context.Background()
   240  
   241  	// validate layout
   242  	layoutFilePath := filepath.Join(tempDir, ocispec.ImageLayoutFile)
   243  	layoutFile, err := os.Open(layoutFilePath)
   244  	if err != nil {
   245  		t.Errorf("error opening layout file, error = %v", err)
   246  	}
   247  	defer layoutFile.Close()
   248  
   249  	var layout *ocispec.ImageLayout
   250  	err = json.NewDecoder(layoutFile).Decode(&layout)
   251  	if err != nil {
   252  		t.Fatal("error decoding layout, error =", err)
   253  	}
   254  	if want := ocispec.ImageLayoutVersion; layout.Version != want {
   255  		t.Errorf("layout.Version = %s, want %s", layout.Version, want)
   256  	}
   257  
   258  	// test push blob
   259  	err = s.Push(ctx, blobDesc, bytes.NewReader(blob))
   260  	if err != nil {
   261  		t.Fatal("Store.Push() error =", err)
   262  	}
   263  	internalResolver := s.tagResolver
   264  	if got, want := len(internalResolver.Map()), 0; got != want {
   265  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   266  	}
   267  
   268  	// test push manifest
   269  	err = s.Push(ctx, manifestDesc, bytes.NewReader(manifest))
   270  	if err != nil {
   271  		t.Fatal("Store.Push() error =", err)
   272  	}
   273  	if got, want := len(internalResolver.Map()), 1; got != want {
   274  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   275  	}
   276  
   277  	// test resolving blob by digest
   278  	gotDesc, err := s.Resolve(ctx, blobDesc.Digest.String())
   279  	if err != nil {
   280  		t.Fatal("Store.Resolve() error =", err)
   281  	}
   282  	if want := blobDesc; gotDesc.Size != want.Size || gotDesc.Digest != want.Digest {
   283  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, blobDesc)
   284  	}
   285  
   286  	// test resolving manifest by digest
   287  	gotDesc, err = s.Resolve(ctx, manifestDesc.Digest.String())
   288  	if err != nil {
   289  		t.Fatal("Store.Resolve() error =", err)
   290  	}
   291  	if !reflect.DeepEqual(gotDesc, manifestDesc) {
   292  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, manifestDesc)
   293  	}
   294  
   295  	// test tag
   296  	err = s.Tag(ctx, manifestDesc, ref)
   297  	if err != nil {
   298  		t.Fatal("Store.Tag() error =", err)
   299  	}
   300  	if got, want := len(internalResolver.Map()), 2; got != want {
   301  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   302  	}
   303  
   304  	// test resolving manifest by tag
   305  	gotDesc, err = s.Resolve(ctx, ref)
   306  	if err != nil {
   307  		t.Fatal("Store.Resolve() error =", err)
   308  	}
   309  	if !reflect.DeepEqual(gotDesc, manifestDesc) {
   310  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, manifestDesc)
   311  	}
   312  
   313  	// test fetch
   314  	exists, err := s.Exists(ctx, manifestDesc)
   315  	if err != nil {
   316  		t.Fatal("Store.Exists() error =", err)
   317  	}
   318  	if !exists {
   319  		t.Errorf("Store.Exists() = %v, want %v", exists, true)
   320  	}
   321  
   322  	rc, err := s.Fetch(ctx, manifestDesc)
   323  	if err != nil {
   324  		t.Fatal("Store.Fetch() error =", err)
   325  	}
   326  	got, err := io.ReadAll(rc)
   327  	if err != nil {
   328  		t.Fatal("Store.Fetch().Read() error =", err)
   329  	}
   330  	err = rc.Close()
   331  	if err != nil {
   332  		t.Error("Store.Fetch().Close() error =", err)
   333  	}
   334  	if !bytes.Equal(got, manifest) {
   335  		t.Errorf("Store.Fetch() = %v, want %v", got, manifest)
   336  	}
   337  }
   338  
   339  func TestStore_NotExistingRoot(t *testing.T) {
   340  	tempDir := t.TempDir()
   341  	root := filepath.Join(tempDir, "rootDir")
   342  	_, err := New(root)
   343  	if err != nil {
   344  		t.Fatal("New() error =", err)
   345  	}
   346  
   347  	// validate layout
   348  	layoutFilePath := filepath.Join(root, ocispec.ImageLayoutFile)
   349  	layoutFile, err := os.Open(layoutFilePath)
   350  	if err != nil {
   351  		t.Errorf("error opening layout file, error = %v", err)
   352  	}
   353  	defer layoutFile.Close()
   354  
   355  	var layout *ocispec.ImageLayout
   356  	err = json.NewDecoder(layoutFile).Decode(&layout)
   357  	if err != nil {
   358  		t.Fatal("error decoding layout, error =", err)
   359  	}
   360  	if want := ocispec.ImageLayoutVersion; layout.Version != want {
   361  		t.Errorf("layout.Version = %s, want %s", layout.Version, want)
   362  	}
   363  
   364  	// validate index.json
   365  	indexFilePath := filepath.Join(root, "index.json")
   366  	indexFile, err := os.Open(indexFilePath)
   367  	if err != nil {
   368  		t.Errorf("error opening layout file, error = %v", err)
   369  	}
   370  	defer indexFile.Close()
   371  
   372  	var index *ocispec.Index
   373  	err = json.NewDecoder(indexFile).Decode(&index)
   374  	if err != nil {
   375  		t.Fatal("error decoding index.json, error =", err)
   376  	}
   377  	if want := 2; index.SchemaVersion != want {
   378  		t.Errorf("index.SchemaVersion = %v, want %v", index.SchemaVersion, want)
   379  	}
   380  }
   381  
   382  func TestStore_ContentNotFound(t *testing.T) {
   383  	content := []byte("hello world")
   384  	desc := ocispec.Descriptor{
   385  		MediaType: "test",
   386  		Digest:    digest.FromBytes(content),
   387  		Size:      int64(len(content)),
   388  	}
   389  
   390  	tempDir := t.TempDir()
   391  	s, err := New(tempDir)
   392  	if err != nil {
   393  		t.Fatal("New() error =", err)
   394  	}
   395  	ctx := context.Background()
   396  
   397  	exists, err := s.Exists(ctx, desc)
   398  	if err != nil {
   399  		t.Error("Store.Exists() error =", err)
   400  	}
   401  	if exists {
   402  		t.Errorf("Store.Exists() = %v, want %v", exists, false)
   403  	}
   404  
   405  	_, err = s.Fetch(ctx, desc)
   406  	if !errors.Is(err, errdef.ErrNotFound) {
   407  		t.Errorf("Store.Fetch() error = %v, want %v", err, errdef.ErrNotFound)
   408  	}
   409  }
   410  
   411  func TestStore_ContentAlreadyExists(t *testing.T) {
   412  	content := []byte("hello world")
   413  	desc := ocispec.Descriptor{
   414  		MediaType: "test",
   415  		Digest:    digest.FromBytes(content),
   416  		Size:      int64(len(content)),
   417  	}
   418  
   419  	tempDir := t.TempDir()
   420  	s, err := New(tempDir)
   421  	if err != nil {
   422  		t.Fatal("New() error =", err)
   423  	}
   424  	ctx := context.Background()
   425  
   426  	err = s.Push(ctx, desc, bytes.NewReader(content))
   427  	if err != nil {
   428  		t.Fatal("Store.Push() error =", err)
   429  	}
   430  
   431  	err = s.Push(ctx, desc, bytes.NewReader(content))
   432  	if !errors.Is(err, errdef.ErrAlreadyExists) {
   433  		t.Errorf("Store.Push() error = %v, want %v", err, errdef.ErrAlreadyExists)
   434  	}
   435  }
   436  
   437  func TestStore_ContentBadPush(t *testing.T) {
   438  	content := []byte("hello world")
   439  	desc := ocispec.Descriptor{
   440  		MediaType: "test",
   441  		Digest:    digest.FromBytes(content),
   442  		Size:      int64(len(content)),
   443  	}
   444  
   445  	tempDir := t.TempDir()
   446  	s, err := New(tempDir)
   447  	if err != nil {
   448  		t.Fatal("New() error =", err)
   449  	}
   450  	ctx := context.Background()
   451  
   452  	err = s.Push(ctx, desc, strings.NewReader("foobar"))
   453  	if err == nil {
   454  		t.Errorf("Store.Push() error = %v, wantErr %v", err, true)
   455  	}
   456  }
   457  
   458  func TestStore_ResolveByTagReturnsFullDescriptor(t *testing.T) {
   459  	content := []byte("hello world")
   460  	ref := "hello-world:0.0.1"
   461  	annotations := map[string]string{"name": "Hello"}
   462  	desc := ocispec.Descriptor{
   463  		MediaType:   "test",
   464  		Digest:      digest.FromBytes(content),
   465  		Size:        int64(len(content)),
   466  		Annotations: annotations,
   467  	}
   468  
   469  	tempDir := t.TempDir()
   470  	s, err := New(tempDir)
   471  	if err != nil {
   472  		t.Fatal("New() error =", err)
   473  	}
   474  	ctx := context.Background()
   475  
   476  	err = s.Push(ctx, desc, bytes.NewReader(content))
   477  	if err != nil {
   478  		t.Errorf("Store.Push() error = %v, wantErr %v", err, false)
   479  	}
   480  
   481  	err = s.Tag(ctx, desc, ref)
   482  	if err != nil {
   483  		t.Errorf("error tagging descriptor error = %v, wantErr %v", err, false)
   484  	}
   485  
   486  	resolvedDescr, err := s.Resolve(ctx, ref)
   487  	if err != nil {
   488  		t.Errorf("error resolving descriptor error = %v, wantErr %v", err, false)
   489  	}
   490  
   491  	if !reflect.DeepEqual(resolvedDescr, desc) {
   492  		t.Errorf("Store.Resolve() = %v, want %v", resolvedDescr, desc)
   493  	}
   494  }
   495  
   496  func TestStore_ResolveByDigestReturnsPlainDescriptor(t *testing.T) {
   497  	content := []byte("hello world")
   498  	ref := "hello-world:0.0.1"
   499  	desc := ocispec.Descriptor{
   500  		MediaType:   "test",
   501  		Digest:      digest.FromBytes(content),
   502  		Size:        int64(len(content)),
   503  		Annotations: map[string]string{"name": "Hello"},
   504  	}
   505  	plainDescriptor := descriptor.Plain(desc)
   506  
   507  	tempDir := t.TempDir()
   508  	s, err := New(tempDir)
   509  	if err != nil {
   510  		t.Fatal("New() error =", err)
   511  	}
   512  	ctx := context.Background()
   513  
   514  	err = s.Push(ctx, desc, bytes.NewReader(content))
   515  	if err != nil {
   516  		t.Errorf("Store.Push() error = %v, wantErr %v", err, false)
   517  	}
   518  
   519  	err = s.Tag(ctx, desc, ref)
   520  	if err != nil {
   521  		t.Errorf("error tagging descriptor error = %v, wantErr %v", err, false)
   522  	}
   523  
   524  	resolvedDescr, err := s.Resolve(ctx, string(desc.Digest))
   525  	if err != nil {
   526  		t.Errorf("error resolving descriptor error = %v, wantErr %v", err, false)
   527  	}
   528  
   529  	if !reflect.DeepEqual(resolvedDescr, plainDescriptor) {
   530  		t.Errorf("Store.Resolve() = %v, want %v", resolvedDescr, plainDescriptor)
   531  	}
   532  }
   533  
   534  func TestStore_TagNotFound(t *testing.T) {
   535  	ref := "foobar"
   536  
   537  	tempDir := t.TempDir()
   538  	s, err := New(tempDir)
   539  	if err != nil {
   540  		t.Fatal("New() error =", err)
   541  	}
   542  	ctx := context.Background()
   543  
   544  	_, err = s.Resolve(ctx, ref)
   545  	if !errors.Is(err, errdef.ErrNotFound) {
   546  		t.Errorf("Store.Resolve() error = %v, want %v", err, errdef.ErrNotFound)
   547  	}
   548  }
   549  
   550  func TestStore_TagUnknownContent(t *testing.T) {
   551  	content := []byte("hello world")
   552  	desc := ocispec.Descriptor{
   553  		MediaType: "test",
   554  		Digest:    digest.FromBytes(content),
   555  		Size:      int64(len(content)),
   556  	}
   557  	ref := "foobar"
   558  
   559  	tempDir := t.TempDir()
   560  	s, err := New(tempDir)
   561  	if err != nil {
   562  		t.Fatal("New() error =", err)
   563  	}
   564  	ctx := context.Background()
   565  
   566  	err = s.Tag(ctx, desc, ref)
   567  	if !errors.Is(err, errdef.ErrNotFound) {
   568  		t.Errorf("Store.Resolve() error = %v, want %v", err, errdef.ErrNotFound)
   569  	}
   570  }
   571  
   572  func TestStore_DisableAutoSaveIndex(t *testing.T) {
   573  	content := []byte(`{"layers":[]}`)
   574  	desc := ocispec.Descriptor{
   575  		MediaType: ocispec.MediaTypeImageManifest,
   576  		Digest:    digest.FromBytes(content),
   577  		Size:      int64(len(content)),
   578  	}
   579  	ref0 := "foobar"
   580  	ref1 := "barfoo"
   581  
   582  	tempDir := t.TempDir()
   583  	s, err := New(tempDir)
   584  	if err != nil {
   585  		t.Fatal("New() error =", err)
   586  	}
   587  	// disable auto save
   588  	s.AutoSaveIndex = false
   589  	ctx := context.Background()
   590  
   591  	// validate layout
   592  	layoutFilePath := filepath.Join(tempDir, ocispec.ImageLayoutFile)
   593  	layoutFile, err := os.Open(layoutFilePath)
   594  	if err != nil {
   595  		t.Errorf("error opening layout file, error = %v", err)
   596  	}
   597  	defer layoutFile.Close()
   598  
   599  	var layout *ocispec.ImageLayout
   600  	err = json.NewDecoder(layoutFile).Decode(&layout)
   601  	if err != nil {
   602  		t.Fatal("error decoding layout, error =", err)
   603  	}
   604  	if want := ocispec.ImageLayoutVersion; layout.Version != want {
   605  		t.Errorf("layout.Version = %s, want %s", layout.Version, want)
   606  	}
   607  
   608  	// test push
   609  	err = s.Push(ctx, desc, bytes.NewReader(content))
   610  	if err != nil {
   611  		t.Fatal("Store.Push() error =", err)
   612  	}
   613  	internalResolver := s.tagResolver
   614  	if got, want := len(internalResolver.Map()), 1; got != want {
   615  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   616  	}
   617  
   618  	// test resolving by digest
   619  	gotDesc, err := s.Resolve(ctx, desc.Digest.String())
   620  	if err != nil {
   621  		t.Fatal("Store.Resolve() error =", err)
   622  	}
   623  	if !reflect.DeepEqual(gotDesc, desc) {
   624  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   625  	}
   626  
   627  	// test tag
   628  	err = s.Tag(ctx, desc, ref0)
   629  	if err != nil {
   630  		t.Fatal("Store.Tag() error =", err)
   631  	}
   632  	err = s.Tag(ctx, desc, ref1)
   633  	if err != nil {
   634  		t.Fatal("Store.Tag() error =", err)
   635  	}
   636  	if got, want := len(internalResolver.Map()), 3; got != want {
   637  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   638  	}
   639  
   640  	// test resolving by digest
   641  	gotDesc, err = s.Resolve(ctx, ref0)
   642  	if err != nil {
   643  		t.Fatal("Store.Resolve() error =", err)
   644  	}
   645  	if !reflect.DeepEqual(gotDesc, desc) {
   646  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   647  	}
   648  
   649  	// test index file
   650  	if got, want := len(s.index.Manifests), 0; got != want {
   651  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   652  	}
   653  	if err := s.saveIndex(); err != nil {
   654  		t.Fatal("Store.SaveIndex() error =", err)
   655  	}
   656  	// test index file again
   657  	if got, want := len(s.index.Manifests), 2; got != want {
   658  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   659  	}
   660  	if _, err := os.Stat(s.indexPath); err != nil {
   661  		t.Errorf("error: %s does not exist", s.indexPath)
   662  	}
   663  
   664  	// test untag
   665  	err = s.Untag(ctx, ref0)
   666  	if err != nil {
   667  		t.Fatal("Store.Untag() error =", err)
   668  	}
   669  	if got, want := len(internalResolver.Map()), 2; got != want {
   670  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   671  	}
   672  	if got, want := len(s.index.Manifests), 2; got != want {
   673  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   674  	}
   675  	if err := s.saveIndex(); err != nil {
   676  		t.Fatal("Store.SaveIndex() error =", err)
   677  	}
   678  	// test index file again
   679  	if got, want := len(s.index.Manifests), 1; got != want {
   680  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   681  	}
   682  }
   683  
   684  func TestStore_RepeatTag(t *testing.T) {
   685  	tempDir := t.TempDir()
   686  	s, err := New(tempDir)
   687  	if err != nil {
   688  		t.Fatal("New() error =", err)
   689  	}
   690  	ctx := context.Background()
   691  	ref := "foobar"
   692  
   693  	// get internal resolver
   694  	internalResolver := s.tagResolver
   695  
   696  	// first tag a manifest
   697  	manifest := []byte(`{"layers":[]}`)
   698  	desc := content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest)
   699  	err = s.Push(ctx, desc, bytes.NewReader(manifest))
   700  	if err != nil {
   701  		t.Fatal("Store.Push() error =", err)
   702  	}
   703  	if got, want := len(internalResolver.Map()), 1; got != want {
   704  		t.Errorf("len(resolver.Map()) = %v, want %v", got, want)
   705  	}
   706  	if got, want := len(s.index.Manifests), 1; got != want {
   707  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   708  	}
   709  
   710  	err = s.Tag(ctx, desc, ref)
   711  	if err != nil {
   712  		t.Fatal("Store.Tag() error =", err)
   713  	}
   714  	if got, want := len(internalResolver.Map()), 2; got != want {
   715  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   716  	}
   717  	if got, want := len(s.index.Manifests), 1; got != want {
   718  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   719  	}
   720  
   721  	gotDesc, err := s.Resolve(ctx, desc.Digest.String())
   722  	if err != nil {
   723  		t.Fatal("Store.Resolve() error =", err)
   724  	}
   725  	if !reflect.DeepEqual(gotDesc, desc) {
   726  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   727  	}
   728  
   729  	gotDesc, err = s.Resolve(ctx, ref)
   730  	if err != nil {
   731  		t.Fatal("Store.Resolve() error =", err)
   732  	}
   733  	if !reflect.DeepEqual(gotDesc, desc) {
   734  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   735  	}
   736  
   737  	// tag another manifest
   738  	manifest = []byte(`{"layers":[], "annotations":{}}`)
   739  	desc = content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest)
   740  	err = s.Push(ctx, desc, bytes.NewReader(manifest))
   741  	if err != nil {
   742  		t.Fatal("Store.Push() error =", err)
   743  	}
   744  	if got, want := len(internalResolver.Map()), 3; got != want {
   745  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   746  	}
   747  	if got, want := len(s.index.Manifests), 2; got != want {
   748  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   749  	}
   750  
   751  	err = s.Tag(ctx, desc, ref)
   752  	if err != nil {
   753  		t.Fatal("Store.Tag() error =", err)
   754  	}
   755  	if got, want := len(internalResolver.Map()), 3; got != want {
   756  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   757  	}
   758  	if got, want := len(s.index.Manifests), 2; got != want {
   759  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   760  	}
   761  
   762  	gotDesc, err = s.Resolve(ctx, desc.Digest.String())
   763  	if err != nil {
   764  		t.Fatal("Store.Resolve() error =", err)
   765  	}
   766  	if !reflect.DeepEqual(gotDesc, desc) {
   767  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   768  	}
   769  
   770  	gotDesc, err = s.Resolve(ctx, ref)
   771  	if err != nil {
   772  		t.Fatal("Store.Resolve() error =", err)
   773  	}
   774  	if !reflect.DeepEqual(gotDesc, desc) {
   775  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   776  	}
   777  
   778  	// tag a blob
   779  	blob := []byte("foobar")
   780  	desc = content.NewDescriptorFromBytes("test", blob)
   781  	err = s.Push(ctx, desc, bytes.NewReader(blob))
   782  	if err != nil {
   783  		t.Fatal("Store.Push() error =", err)
   784  	}
   785  	if got, want := len(internalResolver.Map()), 3; got != want {
   786  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   787  	}
   788  	if got, want := len(s.index.Manifests), 2; got != want {
   789  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   790  	}
   791  
   792  	err = s.Tag(ctx, desc, ref)
   793  	if err != nil {
   794  		t.Fatal("Store.Tag() error =", err)
   795  	}
   796  	if got, want := len(internalResolver.Map()), 4; got != want {
   797  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   798  	}
   799  	if got, want := len(s.index.Manifests), 3; got != want {
   800  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   801  	}
   802  
   803  	gotDesc, err = s.Resolve(ctx, desc.Digest.String())
   804  	if err != nil {
   805  		t.Fatal("Store.Resolve() error =", err)
   806  	}
   807  	if !reflect.DeepEqual(gotDesc, desc) {
   808  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   809  	}
   810  
   811  	gotDesc, err = s.Resolve(ctx, ref)
   812  	if err != nil {
   813  		t.Fatal("Store.Resolve() error =", err)
   814  	}
   815  	if !reflect.DeepEqual(gotDesc, desc) {
   816  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   817  	}
   818  
   819  	// tag another blob
   820  	blob = []byte("barfoo")
   821  	desc = content.NewDescriptorFromBytes("test", blob)
   822  	err = s.Push(ctx, desc, bytes.NewReader(blob))
   823  	if err != nil {
   824  		t.Fatal("Store.Push() error =", err)
   825  	}
   826  	if got, want := len(internalResolver.Map()), 4; got != want {
   827  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   828  	}
   829  	if got, want := len(s.index.Manifests), 3; got != want {
   830  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   831  	}
   832  
   833  	err = s.Tag(ctx, desc, ref)
   834  	if err != nil {
   835  		t.Fatal("Store.Tag() error =", err)
   836  	}
   837  	if got, want := len(internalResolver.Map()), 5; got != want {
   838  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   839  	}
   840  	if got, want := len(s.index.Manifests), 4; got != want {
   841  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   842  	}
   843  
   844  	gotDesc, err = s.Resolve(ctx, desc.Digest.String())
   845  	if err != nil {
   846  		t.Fatal("Store.Resolve() error =", err)
   847  	}
   848  	if !reflect.DeepEqual(gotDesc, desc) {
   849  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   850  	}
   851  
   852  	gotDesc, err = s.Resolve(ctx, ref)
   853  	if err != nil {
   854  		t.Fatal("Store.Resolve() error =", err)
   855  	}
   856  	if !reflect.DeepEqual(gotDesc, desc) {
   857  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   858  	}
   859  }
   860  
   861  // Related bug: https://github.com/oras-project/oras-go/issues/461
   862  func TestStore_TagByDigest(t *testing.T) {
   863  	tempDir := t.TempDir()
   864  	s, err := New(tempDir)
   865  	if err != nil {
   866  		t.Fatal("New() error =", err)
   867  	}
   868  	ctx := context.Background()
   869  
   870  	// get internal resolver
   871  	internalResolver := s.tagResolver
   872  
   873  	manifest := []byte(`{"layers":[]}`)
   874  	manifestDesc := content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest)
   875  
   876  	// push a manifest
   877  	err = s.Push(ctx, manifestDesc, bytes.NewReader(manifest))
   878  	if err != nil {
   879  		t.Fatal("Store.Push() error =", err)
   880  	}
   881  	if got, want := len(internalResolver.Map()), 1; got != want {
   882  		t.Errorf("len(resolver.Map()) = %v, want %v", got, want)
   883  	}
   884  	if got, want := len(s.index.Manifests), 1; got != want {
   885  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   886  	}
   887  	gotDesc, err := s.Resolve(ctx, manifestDesc.Digest.String())
   888  	if err != nil {
   889  		t.Fatal("Store.Resolve() error =", err)
   890  	}
   891  	if !reflect.DeepEqual(gotDesc, manifestDesc) {
   892  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, manifestDesc)
   893  	}
   894  
   895  	// tag manifest by digest
   896  	err = s.Tag(ctx, manifestDesc, manifestDesc.Digest.String())
   897  	if err != nil {
   898  		t.Fatal("Store.Tag() error =", err)
   899  	}
   900  	if got, want := len(internalResolver.Map()), 1; got != want {
   901  		t.Errorf("len(resolver.Map()) = %v, want %v", got, want)
   902  	}
   903  	if got, want := len(s.index.Manifests), 1; got != want {
   904  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   905  	}
   906  	gotDesc, err = s.Resolve(ctx, manifestDesc.Digest.String())
   907  	if err != nil {
   908  		t.Fatal("Store.Resolve() error =", err)
   909  	}
   910  	if !reflect.DeepEqual(gotDesc, manifestDesc) {
   911  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, manifestDesc)
   912  	}
   913  
   914  	// push a blob
   915  	blob := []byte("foobar")
   916  	blobDesc := content.NewDescriptorFromBytes("test", blob)
   917  	err = s.Push(ctx, blobDesc, bytes.NewReader(blob))
   918  	if err != nil {
   919  		t.Fatal("Store.Push() error =", err)
   920  	}
   921  	if got, want := len(internalResolver.Map()), 1; got != want {
   922  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   923  	}
   924  	if got, want := len(s.index.Manifests), 1; got != want {
   925  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   926  	}
   927  	gotDesc, err = s.Resolve(ctx, blobDesc.Digest.String())
   928  	if err != nil {
   929  		t.Fatal("Store.Resolve() error =", err)
   930  	}
   931  	if gotDesc.Digest != blobDesc.Digest || gotDesc.Size != blobDesc.Size {
   932  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, blobDesc)
   933  	}
   934  
   935  	// tag blob by digest
   936  	err = s.Tag(ctx, blobDesc, blobDesc.Digest.String())
   937  	if err != nil {
   938  		t.Fatal("Store.Tag() error =", err)
   939  	}
   940  	if got, want := len(internalResolver.Map()), 2; got != want {
   941  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   942  	}
   943  	if got, want := len(s.index.Manifests), 2; got != want {
   944  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   945  	}
   946  	gotDesc, err = s.Resolve(ctx, blobDesc.Digest.String())
   947  	if err != nil {
   948  		t.Fatal("Store.Resolve() error =", err)
   949  	}
   950  	if !reflect.DeepEqual(gotDesc, blobDesc) {
   951  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, blobDesc)
   952  	}
   953  }
   954  
   955  func TestStore_BadIndex(t *testing.T) {
   956  	tempDir := t.TempDir()
   957  	content := []byte("whatever")
   958  	path := filepath.Join(tempDir, "index.json")
   959  	os.WriteFile(path, content, 0666)
   960  
   961  	_, err := New(tempDir)
   962  	if err == nil {
   963  		t.Errorf("New() error = nil, want: error")
   964  	}
   965  }
   966  
   967  func TestStore_BadLayout(t *testing.T) {
   968  	tempDir := t.TempDir()
   969  	content := []byte("whatever")
   970  	path := filepath.Join(tempDir, ocispec.ImageLayoutFile)
   971  	os.WriteFile(path, content, 0666)
   972  
   973  	_, err := New(tempDir)
   974  	if err == nil {
   975  		t.Errorf("New() error = nil, want: error")
   976  	}
   977  }
   978  
   979  func TestStore_Predecessors(t *testing.T) {
   980  	tempDir := t.TempDir()
   981  	s, err := New(tempDir)
   982  	if err != nil {
   983  		t.Fatal("New() error =", err)
   984  	}
   985  	ctx := context.Background()
   986  
   987  	// generate test content
   988  	var blobs [][]byte
   989  	var descs []ocispec.Descriptor
   990  	appendBlob := func(mediaType string, blob []byte) {
   991  		blobs = append(blobs, blob)
   992  		descs = append(descs, ocispec.Descriptor{
   993  			MediaType: mediaType,
   994  			Digest:    digest.FromBytes(blob),
   995  			Size:      int64(len(blob)),
   996  		})
   997  	}
   998  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
   999  		manifest := ocispec.Manifest{
  1000  			Config: config,
  1001  			Layers: layers,
  1002  		}
  1003  		manifestJSON, err := json.Marshal(manifest)
  1004  		if err != nil {
  1005  			t.Fatal(err)
  1006  		}
  1007  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1008  	}
  1009  	generateIndex := func(manifests ...ocispec.Descriptor) {
  1010  		index := ocispec.Index{
  1011  			Manifests: manifests,
  1012  		}
  1013  		indexJSON, err := json.Marshal(index)
  1014  		if err != nil {
  1015  			t.Fatal(err)
  1016  		}
  1017  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  1018  	}
  1019  	generateArtifactManifest := func(subject ocispec.Descriptor, blobs ...ocispec.Descriptor) {
  1020  		var manifest spec.Artifact
  1021  		manifest.Subject = &subject
  1022  		manifest.Blobs = append(manifest.Blobs, blobs...)
  1023  		manifestJSON, err := json.Marshal(manifest)
  1024  		if err != nil {
  1025  			t.Fatal(err)
  1026  		}
  1027  		appendBlob(spec.MediaTypeArtifactManifest, manifestJSON)
  1028  	}
  1029  
  1030  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1031  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1032  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1033  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 3
  1034  	generateManifest(descs[0], descs[1:3]...)                  // Blob 4
  1035  	generateManifest(descs[0], descs[3])                       // Blob 5
  1036  	generateManifest(descs[0], descs[1:4]...)                  // Blob 6
  1037  	generateIndex(descs[4:6]...)                               // Blob 7
  1038  	generateIndex(descs[6])                                    // Blob 8
  1039  	generateIndex()                                            // Blob 9
  1040  	generateIndex(descs[7:10]...)                              // Blob 10
  1041  	appendBlob(ocispec.MediaTypeImageLayer, []byte("sig_1"))   // Blob 11
  1042  	generateArtifactManifest(descs[6], descs[11])              // Blob 12
  1043  	appendBlob(ocispec.MediaTypeImageLayer, []byte("sig_2"))   // Blob 13
  1044  	generateArtifactManifest(descs[10], descs[13])             // Blob 14
  1045  
  1046  	eg, egCtx := errgroup.WithContext(ctx)
  1047  	for i := range blobs {
  1048  		eg.Go(func(i int) func() error {
  1049  			return func() error {
  1050  				err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i]))
  1051  				if err != nil {
  1052  					return fmt.Errorf("failed to push test content to src: %d: %v", i, err)
  1053  				}
  1054  				return nil
  1055  			}
  1056  		}(i))
  1057  	}
  1058  	if err := eg.Wait(); err != nil {
  1059  		t.Fatal(err)
  1060  	}
  1061  
  1062  	// verify predecessors
  1063  	wants := [][]ocispec.Descriptor{
  1064  		descs[4:7],            // Blob 0
  1065  		{descs[4], descs[6]},  // Blob 1
  1066  		{descs[4], descs[6]},  // Blob 2
  1067  		{descs[5], descs[6]},  // Blob 3
  1068  		{descs[7]},            // Blob 4
  1069  		{descs[7]},            // Blob 5
  1070  		{descs[8], descs[12]}, // Blob 6
  1071  		{descs[10]},           // Blob 7
  1072  		{descs[10]},           // Blob 8
  1073  		{descs[10]},           // Blob 9
  1074  		{descs[14]},           // Blob 10
  1075  		{descs[12]},           // Blob 11
  1076  		nil,                   // Blob 12
  1077  		{descs[14]},           // Blob 13
  1078  		nil,                   // Blob 14
  1079  	}
  1080  	for i, want := range wants {
  1081  		predecessors, err := s.Predecessors(ctx, descs[i])
  1082  		if err != nil {
  1083  			t.Errorf("Store.Predecessors(%d) error = %v", i, err)
  1084  		}
  1085  		if !equalDescriptorSet(predecessors, want) {
  1086  			t.Errorf("Store.Predecessors(%d) = %v, want %v", i, predecessors, want)
  1087  		}
  1088  	}
  1089  }
  1090  
  1091  func TestStore_ExistingStore(t *testing.T) {
  1092  	tempDir := t.TempDir()
  1093  	s, err := New(tempDir)
  1094  	if err != nil {
  1095  		t.Fatal("New() error =", err)
  1096  	}
  1097  
  1098  	// generate test content
  1099  	var blobs [][]byte
  1100  	var descs []ocispec.Descriptor
  1101  	appendBlob := func(mediaType string, blob []byte) {
  1102  		blobs = append(blobs, blob)
  1103  		descs = append(descs, ocispec.Descriptor{
  1104  			MediaType: mediaType,
  1105  			Digest:    digest.FromBytes(blob),
  1106  			Size:      int64(len(blob)),
  1107  		})
  1108  	}
  1109  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1110  		manifest := ocispec.Manifest{
  1111  			Config: config,
  1112  			Layers: layers,
  1113  		}
  1114  		manifestJSON, err := json.Marshal(manifest)
  1115  		if err != nil {
  1116  			t.Fatal(err)
  1117  		}
  1118  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1119  	}
  1120  	generateIndex := func(manifests ...ocispec.Descriptor) {
  1121  		index := ocispec.Index{
  1122  			Manifests: manifests,
  1123  		}
  1124  		indexJSON, err := json.Marshal(index)
  1125  		if err != nil {
  1126  			t.Fatal(err)
  1127  		}
  1128  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  1129  	}
  1130  
  1131  	generateArtifactManifest := func(subject ocispec.Descriptor, blobs ...ocispec.Descriptor) {
  1132  		var manifest spec.Artifact
  1133  		manifest.Subject = &subject
  1134  		manifest.Blobs = append(manifest.Blobs, blobs...)
  1135  		manifestJSON, err := json.Marshal(manifest)
  1136  		if err != nil {
  1137  			t.Fatal(err)
  1138  		}
  1139  		appendBlob(spec.MediaTypeArtifactManifest, manifestJSON)
  1140  	}
  1141  
  1142  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1143  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1144  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1145  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 3
  1146  	generateManifest(descs[0], descs[1:3]...)                  // Blob 4
  1147  	generateManifest(descs[0], descs[3])                       // Blob 5
  1148  	generateManifest(descs[0], descs[1:4]...)                  // Blob 6
  1149  	generateIndex(descs[4:6]...)                               // Blob 7
  1150  	generateIndex(descs[6])                                    // Blob 8
  1151  	generateIndex()                                            // Blob 9
  1152  	generateIndex(descs[7:10]...)                              // Blob 10
  1153  	appendBlob(ocispec.MediaTypeImageLayer, []byte("sig_1"))   // Blob 11
  1154  	generateArtifactManifest(descs[6], descs[11])              // Blob 12
  1155  	appendBlob(ocispec.MediaTypeImageLayer, []byte("sig_2"))   // Blob 13
  1156  	generateArtifactManifest(descs[10], descs[13])             // Blob 14
  1157  
  1158  	ctx := context.Background()
  1159  	eg, egCtx := errgroup.WithContext(ctx)
  1160  	for i := range blobs {
  1161  		eg.Go(func(i int) func() error {
  1162  			return func() error {
  1163  				err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i]))
  1164  				if err != nil {
  1165  					return fmt.Errorf("failed to push test content to src: %d: %v", i, err)
  1166  				}
  1167  				return nil
  1168  			}
  1169  		}(i))
  1170  	}
  1171  	if err := eg.Wait(); err != nil {
  1172  		t.Fatal(err)
  1173  	}
  1174  
  1175  	// tag index root
  1176  	indexRoot := descs[10]
  1177  	tag := "latest"
  1178  	if err := s.Tag(ctx, indexRoot, tag); err != nil {
  1179  		t.Fatal("Tag() error =", err)
  1180  	}
  1181  	// tag index root by digest
  1182  	// related bug: https://github.com/oras-project/oras-go/issues/461
  1183  	if err := s.Tag(ctx, indexRoot, indexRoot.Digest.String()); err != nil {
  1184  		t.Fatal("Tag() error =", err)
  1185  	}
  1186  
  1187  	// test with another OCI store instance to mock loading from an existing store
  1188  	anotherS, err := New(tempDir)
  1189  	if err != nil {
  1190  		t.Fatal("New() error =", err)
  1191  	}
  1192  
  1193  	// test resolving index root by tag
  1194  	gotDesc, err := anotherS.Resolve(ctx, tag)
  1195  	if err != nil {
  1196  		t.Fatal("Store: Resolve() error =", err)
  1197  	}
  1198  	if !content.Equal(gotDesc, indexRoot) {
  1199  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, indexRoot)
  1200  	}
  1201  
  1202  	// test resolving index root by digest
  1203  	gotDesc, err = anotherS.Resolve(ctx, indexRoot.Digest.String())
  1204  	if err != nil {
  1205  		t.Fatal("Store: Resolve() error =", err)
  1206  	}
  1207  	if !reflect.DeepEqual(gotDesc, indexRoot) {
  1208  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, indexRoot)
  1209  	}
  1210  
  1211  	// test resolving artifact manifest by digest
  1212  	artifactRootDesc := descs[12]
  1213  	gotDesc, err = anotherS.Resolve(ctx, artifactRootDesc.Digest.String())
  1214  	if err != nil {
  1215  		t.Fatal("Store: Resolve() error =", err)
  1216  	}
  1217  	if !reflect.DeepEqual(gotDesc, artifactRootDesc) {
  1218  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, artifactRootDesc)
  1219  	}
  1220  
  1221  	// test resolving blob by digest
  1222  	gotDesc, err = anotherS.Resolve(ctx, descs[0].Digest.String())
  1223  	if err != nil {
  1224  		t.Fatal("Store.Resolve() error =", err)
  1225  	}
  1226  	if want := descs[0]; gotDesc.Size != want.Size || gotDesc.Digest != want.Digest {
  1227  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, want)
  1228  	}
  1229  
  1230  	// test fetching OCI root index
  1231  	exists, err := anotherS.Exists(ctx, indexRoot)
  1232  	if err != nil {
  1233  		t.Fatal("Store.Exists() error =", err)
  1234  	}
  1235  	if !exists {
  1236  		t.Errorf("Store.Exists() = %v, want %v", exists, true)
  1237  	}
  1238  
  1239  	// test fetching blobs
  1240  	for i := range blobs {
  1241  		eg.Go(func(i int) func() error {
  1242  			return func() error {
  1243  				rc, err := s.Fetch(egCtx, descs[i])
  1244  				if err != nil {
  1245  					return fmt.Errorf("Store.Fetch(%d) error = %v", i, err)
  1246  				}
  1247  				got, err := io.ReadAll(rc)
  1248  				if err != nil {
  1249  					return fmt.Errorf("Store.Fetch(%d).Read() error = %v", i, err)
  1250  				}
  1251  				err = rc.Close()
  1252  				if err != nil {
  1253  					return fmt.Errorf("Store.Fetch(%d).Close() error = %v", i, err)
  1254  				}
  1255  				if !bytes.Equal(got, blobs[i]) {
  1256  					return fmt.Errorf("Store.Fetch(%d) = %v, want %v", i, got, blobs[i])
  1257  				}
  1258  				return nil
  1259  			}
  1260  		}(i))
  1261  	}
  1262  	if err := eg.Wait(); err != nil {
  1263  		t.Fatal(err)
  1264  	}
  1265  
  1266  	// verify predecessors
  1267  	wants := [][]ocispec.Descriptor{
  1268  		descs[4:7],            // Blob 0
  1269  		{descs[4], descs[6]},  // Blob 1
  1270  		{descs[4], descs[6]},  // Blob 2
  1271  		{descs[5], descs[6]},  // Blob 3
  1272  		{descs[7]},            // Blob 4
  1273  		{descs[7]},            // Blob 5
  1274  		{descs[8], descs[12]}, // Blob 6
  1275  		{descs[10]},           // Blob 7
  1276  		{descs[10]},           // Blob 8
  1277  		{descs[10]},           // Blob 9
  1278  		{descs[14]},           // Blob 10
  1279  		{descs[12]},           // Blob 11
  1280  		nil,                   // Blob 12, no predecessors
  1281  		{descs[14]},           // Blob 13
  1282  		nil,                   // Blob 14, no predecessors
  1283  	}
  1284  	for i, want := range wants {
  1285  		predecessors, err := anotherS.Predecessors(ctx, descs[i])
  1286  		if err != nil {
  1287  			t.Errorf("Store.Predecessors(%d) error = %v", i, err)
  1288  		}
  1289  		if !equalDescriptorSet(predecessors, want) {
  1290  			t.Errorf("Store.Predecessors(%d) = %v, want %v", i, predecessors, want)
  1291  		}
  1292  	}
  1293  }
  1294  
  1295  func Test_ExistingStore_Retag(t *testing.T) {
  1296  	tempDir := t.TempDir()
  1297  	s, err := New(tempDir)
  1298  	if err != nil {
  1299  		t.Fatal("New() error =", err)
  1300  	}
  1301  	ctx := context.Background()
  1302  
  1303  	manifest_1 := []byte(`{"layers":[]}`)
  1304  	manifestDesc_1 := content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest_1)
  1305  	manifestDesc_1.Annotations = map[string]string{"key1": "val1"}
  1306  
  1307  	// push a manifest
  1308  	err = s.Push(ctx, manifestDesc_1, bytes.NewReader(manifest_1))
  1309  	if err != nil {
  1310  		t.Fatal("Store.Push() error =", err)
  1311  	}
  1312  	// tag manifest by digest
  1313  	err = s.Tag(ctx, manifestDesc_1, manifestDesc_1.Digest.String())
  1314  	if err != nil {
  1315  		t.Fatal("Store.Tag() error =", err)
  1316  	}
  1317  	// tag manifest by tag
  1318  	ref := "foobar"
  1319  	err = s.Tag(ctx, manifestDesc_1, ref)
  1320  	if err != nil {
  1321  		t.Fatal("Store.Tag() error =", err)
  1322  	}
  1323  
  1324  	// verify index
  1325  	want := []ocispec.Descriptor{
  1326  		{
  1327  			MediaType: manifestDesc_1.MediaType,
  1328  			Digest:    manifestDesc_1.Digest,
  1329  			Size:      manifestDesc_1.Size,
  1330  			Annotations: map[string]string{
  1331  				"key1":                    "val1",
  1332  				ocispec.AnnotationRefName: ref,
  1333  			},
  1334  		},
  1335  	}
  1336  	if got := s.index.Manifests; !equalDescriptorSet(got, want) {
  1337  		t.Errorf("index.Manifests = %v, want %v", got, want)
  1338  	}
  1339  
  1340  	// test with another OCI store instance to mock loading from an existing store
  1341  	anotherS, err := New(tempDir)
  1342  	if err != nil {
  1343  		t.Fatal("New() error =", err)
  1344  	}
  1345  	manifest_2 := []byte(`{"layers":[], "annotations":{}}`)
  1346  	manifestDesc_2 := content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest_2)
  1347  	manifestDesc_2.Annotations = map[string]string{"key2": "val2"}
  1348  
  1349  	err = anotherS.Push(ctx, manifestDesc_2, bytes.NewReader(manifest_2))
  1350  	if err != nil {
  1351  		t.Fatal("Store.Push() error =", err)
  1352  	}
  1353  	err = anotherS.Tag(ctx, manifestDesc_2, ref)
  1354  	if err != nil {
  1355  		t.Fatal("Store.Tag() error =", err)
  1356  	}
  1357  
  1358  	// verify index
  1359  	want = []ocispec.Descriptor{
  1360  		{
  1361  			MediaType: manifestDesc_1.MediaType,
  1362  			Digest:    manifestDesc_1.Digest,
  1363  			Size:      manifestDesc_1.Size,
  1364  			Annotations: map[string]string{
  1365  				"key1": "val1",
  1366  			},
  1367  		},
  1368  		{
  1369  			MediaType: manifestDesc_2.MediaType,
  1370  			Digest:    manifestDesc_2.Digest,
  1371  			Size:      manifestDesc_2.Size,
  1372  			Annotations: map[string]string{
  1373  				"key2":                    "val2",
  1374  				ocispec.AnnotationRefName: ref,
  1375  			},
  1376  		},
  1377  	}
  1378  	if got := anotherS.index.Manifests; !equalDescriptorSet(got, want) {
  1379  		t.Errorf("index.Manifests = %v, want %v", got, want)
  1380  	}
  1381  }
  1382  
  1383  func TestCopy_MemoryToOCI_FullCopy(t *testing.T) {
  1384  	src := memory.New()
  1385  
  1386  	tempDir := t.TempDir()
  1387  	dst, err := New(tempDir)
  1388  	if err != nil {
  1389  		t.Fatal("OCI.New() error =", err)
  1390  	}
  1391  
  1392  	// generate test content
  1393  	var blobs [][]byte
  1394  	var descs []ocispec.Descriptor
  1395  	appendBlob := func(mediaType string, blob []byte) {
  1396  		blobs = append(blobs, blob)
  1397  		descs = append(descs, ocispec.Descriptor{
  1398  			MediaType: mediaType,
  1399  			Digest:    digest.FromBytes(blob),
  1400  			Size:      int64(len(blob)),
  1401  		})
  1402  	}
  1403  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1404  		manifest := ocispec.Manifest{
  1405  			Config: config,
  1406  			Layers: layers,
  1407  		}
  1408  		manifestJSON, err := json.Marshal(manifest)
  1409  		if err != nil {
  1410  			t.Fatal(err)
  1411  		}
  1412  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1413  	}
  1414  
  1415  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1416  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1417  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1418  	generateManifest(descs[0], descs[1:3]...)                  // Blob 3
  1419  
  1420  	ctx := context.Background()
  1421  	for i := range blobs {
  1422  		err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  1423  		if err != nil {
  1424  			t.Fatalf("failed to push test content to src: %d: %v", i, err)
  1425  		}
  1426  	}
  1427  
  1428  	root := descs[3]
  1429  	ref := "foobar"
  1430  	err = src.Tag(ctx, root, ref)
  1431  	if err != nil {
  1432  		t.Fatal("fail to tag root node", err)
  1433  	}
  1434  
  1435  	// test copy
  1436  	gotDesc, err := oras.Copy(ctx, src, ref, dst, "", oras.CopyOptions{})
  1437  	if err != nil {
  1438  		t.Fatalf("Copy() error = %v, wantErr %v", err, false)
  1439  	}
  1440  	if !reflect.DeepEqual(gotDesc, root) {
  1441  		t.Errorf("Copy() = %v, want %v", gotDesc, root)
  1442  	}
  1443  
  1444  	// verify contents
  1445  	for i, desc := range descs {
  1446  		exists, err := dst.Exists(ctx, desc)
  1447  		if err != nil {
  1448  			t.Fatalf("dst.Exists(%d) error = %v", i, err)
  1449  		}
  1450  		if !exists {
  1451  			t.Errorf("dst.Exists(%d) = %v, want %v", i, exists, true)
  1452  		}
  1453  	}
  1454  
  1455  	// verify tag
  1456  	gotDesc, err = dst.Resolve(ctx, ref)
  1457  	if err != nil {
  1458  		t.Fatal("dst.Resolve() error =", err)
  1459  	}
  1460  	if !reflect.DeepEqual(gotDesc, root) {
  1461  		t.Errorf("dst.Resolve() = %v, want %v", gotDesc, root)
  1462  	}
  1463  }
  1464  
  1465  func TestCopyGraph_MemoryToOCI_FullCopy(t *testing.T) {
  1466  	src := cas.NewMemory()
  1467  
  1468  	tempDir := t.TempDir()
  1469  	dst, err := New(tempDir)
  1470  	if err != nil {
  1471  		t.Fatal("OCI.New() error =", err)
  1472  	}
  1473  
  1474  	// generate test content
  1475  	var blobs [][]byte
  1476  	var descs []ocispec.Descriptor
  1477  	appendBlob := func(mediaType string, blob []byte) {
  1478  		blobs = append(blobs, blob)
  1479  		descs = append(descs, ocispec.Descriptor{
  1480  			MediaType: mediaType,
  1481  			Digest:    digest.FromBytes(blob),
  1482  			Size:      int64(len(blob)),
  1483  		})
  1484  	}
  1485  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1486  		manifest := ocispec.Manifest{
  1487  			Config: config,
  1488  			Layers: layers,
  1489  		}
  1490  		manifestJSON, err := json.Marshal(manifest)
  1491  		if err != nil {
  1492  			t.Fatal(err)
  1493  		}
  1494  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1495  	}
  1496  	generateIndex := func(manifests ...ocispec.Descriptor) {
  1497  		index := ocispec.Index{
  1498  			Manifests: manifests,
  1499  		}
  1500  		indexJSON, err := json.Marshal(index)
  1501  		if err != nil {
  1502  			t.Fatal(err)
  1503  		}
  1504  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  1505  	}
  1506  
  1507  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1508  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1509  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1510  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 3
  1511  	generateManifest(descs[0], descs[1:3]...)                  // Blob 4
  1512  	generateManifest(descs[0], descs[3])                       // Blob 5
  1513  	generateManifest(descs[0], descs[1:4]...)                  // Blob 6
  1514  	generateIndex(descs[4:6]...)                               // Blob 7
  1515  	generateIndex(descs[6])                                    // Blob 8
  1516  	generateIndex()                                            // Blob 9
  1517  	generateIndex(descs[7:10]...)                              // Blob 10
  1518  
  1519  	ctx := context.Background()
  1520  	for i := range blobs {
  1521  		err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  1522  		if err != nil {
  1523  			t.Fatalf("failed to push test content to src: %d: %v", i, err)
  1524  		}
  1525  	}
  1526  
  1527  	// test copy
  1528  	srcTracker := &storageTracker{Storage: src}
  1529  	dstTracker := &storageTracker{Storage: dst}
  1530  	root := descs[len(descs)-1]
  1531  	if err := oras.CopyGraph(ctx, srcTracker, dstTracker, root, oras.CopyGraphOptions{}); err != nil {
  1532  		t.Fatalf("CopyGraph() error = %v, wantErr %v", err, false)
  1533  	}
  1534  
  1535  	// verify contents
  1536  	for i := range blobs {
  1537  		got, err := content.FetchAll(ctx, dst, descs[i])
  1538  		if err != nil {
  1539  			t.Errorf("content[%d] error = %v, wantErr %v", i, err, false)
  1540  			continue
  1541  		}
  1542  		if want := blobs[i]; !bytes.Equal(got, want) {
  1543  			t.Errorf("content[%d] = %v, want %v", i, got, want)
  1544  		}
  1545  	}
  1546  
  1547  	// verify API counts
  1548  	if got, want := srcTracker.fetch, int64(len(blobs)); got != want {
  1549  		t.Errorf("count(src.Fetch()) = %v, want %v", got, want)
  1550  	}
  1551  	if got, want := srcTracker.push, int64(0); got != want {
  1552  		t.Errorf("count(src.Push()) = %v, want %v", got, want)
  1553  	}
  1554  	if got, want := srcTracker.exists, int64(0); got != want {
  1555  		t.Errorf("count(src.Exists()) = %v, want %v", got, want)
  1556  	}
  1557  	if got, want := dstTracker.fetch, int64(0); got != want {
  1558  		t.Errorf("count(dst.Fetch()) = %v, want %v", got, want)
  1559  	}
  1560  	if got, want := dstTracker.push, int64(len(blobs)); got != want {
  1561  		t.Errorf("count(dst.Push()) = %v, want %v", got, want)
  1562  	}
  1563  	if got, want := dstTracker.exists, int64(len(blobs)); got != want {
  1564  		t.Errorf("count(dst.Exists()) = %v, want %v", got, want)
  1565  	}
  1566  }
  1567  
  1568  func TestCopyGraph_MemoryToOCI_PartialCopy(t *testing.T) {
  1569  	src := cas.NewMemory()
  1570  
  1571  	tempDir := t.TempDir()
  1572  	dst, err := New(tempDir)
  1573  	if err != nil {
  1574  		t.Fatal("OCI.New() error =", err)
  1575  	}
  1576  
  1577  	// generate test content
  1578  	var blobs [][]byte
  1579  	var descs []ocispec.Descriptor
  1580  	appendBlob := func(mediaType string, blob []byte) {
  1581  		blobs = append(blobs, blob)
  1582  		descs = append(descs, ocispec.Descriptor{
  1583  			MediaType: mediaType,
  1584  			Digest:    digest.FromBytes(blob),
  1585  			Size:      int64(len(blob)),
  1586  		})
  1587  	}
  1588  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1589  		manifest := ocispec.Manifest{
  1590  			Config: config,
  1591  			Layers: layers,
  1592  		}
  1593  		manifestJSON, err := json.Marshal(manifest)
  1594  		if err != nil {
  1595  			t.Fatal(err)
  1596  		}
  1597  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1598  	}
  1599  	generateIndex := func(manifests ...ocispec.Descriptor) {
  1600  		index := ocispec.Index{
  1601  			Manifests: manifests,
  1602  		}
  1603  		indexJSON, err := json.Marshal(index)
  1604  		if err != nil {
  1605  			t.Fatal(err)
  1606  		}
  1607  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  1608  	}
  1609  
  1610  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1611  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1612  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1613  	generateManifest(descs[0], descs[1:3]...)                  // Blob 3
  1614  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 4
  1615  	generateManifest(descs[0], descs[4])                       // Blob 5
  1616  	generateIndex(descs[3], descs[5])                          // Blob 6
  1617  
  1618  	ctx := context.Background()
  1619  	for i := range blobs {
  1620  		err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  1621  		if err != nil {
  1622  			t.Fatalf("failed to push test content to src: %d: %v", i, err)
  1623  		}
  1624  	}
  1625  
  1626  	// initial copy
  1627  	root := descs[3]
  1628  	if err := oras.CopyGraph(ctx, src, dst, root, oras.CopyGraphOptions{}); err != nil {
  1629  		t.Fatalf("CopyGraph() error = %v, wantErr %v", err, false)
  1630  	}
  1631  	// verify contents
  1632  	for i := range blobs[:4] {
  1633  		got, err := content.FetchAll(ctx, dst, descs[i])
  1634  		if err != nil {
  1635  			t.Fatalf("content[%d] error = %v, wantErr %v", i, err, false)
  1636  		}
  1637  		if want := blobs[i]; !bytes.Equal(got, want) {
  1638  			t.Fatalf("content[%d] = %v, want %v", i, got, want)
  1639  		}
  1640  	}
  1641  
  1642  	// test copy
  1643  	srcTracker := &storageTracker{Storage: src}
  1644  	dstTracker := &storageTracker{Storage: dst}
  1645  	root = descs[len(descs)-1]
  1646  	if err := oras.CopyGraph(ctx, srcTracker, dstTracker, root, oras.CopyGraphOptions{}); err != nil {
  1647  		t.Fatalf("CopyGraph() error = %v, wantErr %v", err, false)
  1648  	}
  1649  
  1650  	// verify contents
  1651  	for i := range blobs {
  1652  		got, err := content.FetchAll(ctx, dst, descs[i])
  1653  		if err != nil {
  1654  			t.Errorf("content[%d] error = %v, wantErr %v", i, err, false)
  1655  			continue
  1656  		}
  1657  		if want := blobs[i]; !bytes.Equal(got, want) {
  1658  			t.Errorf("content[%d] = %v, want %v", i, got, want)
  1659  		}
  1660  	}
  1661  
  1662  	// verify API counts
  1663  	if got, want := srcTracker.fetch, int64(3); got != want {
  1664  		t.Errorf("count(src.Fetch()) = %v, want %v", got, want)
  1665  	}
  1666  	if got, want := srcTracker.push, int64(0); got != want {
  1667  		t.Errorf("count(src.Push()) = %v, want %v", got, want)
  1668  	}
  1669  	if got, want := srcTracker.exists, int64(0); got != want {
  1670  		t.Errorf("count(src.Exists()) = %v, want %v", got, want)
  1671  	}
  1672  	if got, want := dstTracker.fetch, int64(0); got != want {
  1673  		t.Errorf("count(dst.Fetch()) = %v, want %v", got, want)
  1674  	}
  1675  	if got, want := dstTracker.push, int64(3); got != want {
  1676  		t.Errorf("count(dst.Push()) = %v, want %v", got, want)
  1677  	}
  1678  	if got, want := dstTracker.exists, int64(5); got != want {
  1679  		t.Errorf("count(dst.Exists()) = %v, want %v", got, want)
  1680  	}
  1681  }
  1682  
  1683  func TestCopyGraph_OCIToMemory_FullCopy(t *testing.T) {
  1684  	tempDir := t.TempDir()
  1685  	src, err := New(tempDir)
  1686  	if err != nil {
  1687  		t.Fatal("OCI.New() error =", err)
  1688  	}
  1689  
  1690  	dst := cas.NewMemory()
  1691  
  1692  	// generate test content
  1693  	var blobs [][]byte
  1694  	var descs []ocispec.Descriptor
  1695  	appendBlob := func(mediaType string, blob []byte) {
  1696  		blobs = append(blobs, blob)
  1697  		descs = append(descs, ocispec.Descriptor{
  1698  			MediaType: mediaType,
  1699  			Digest:    digest.FromBytes(blob),
  1700  			Size:      int64(len(blob)),
  1701  		})
  1702  	}
  1703  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1704  		manifest := ocispec.Manifest{
  1705  			Config: config,
  1706  			Layers: layers,
  1707  		}
  1708  		manifestJSON, err := json.Marshal(manifest)
  1709  		if err != nil {
  1710  			t.Fatal(err)
  1711  		}
  1712  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1713  	}
  1714  	generateIndex := func(manifests ...ocispec.Descriptor) {
  1715  		index := ocispec.Index{
  1716  			Manifests: manifests,
  1717  		}
  1718  		indexJSON, err := json.Marshal(index)
  1719  		if err != nil {
  1720  			t.Fatal(err)
  1721  		}
  1722  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  1723  	}
  1724  
  1725  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1726  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1727  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1728  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 3
  1729  	generateManifest(descs[0], descs[1:3]...)                  // Blob 4
  1730  	generateManifest(descs[0], descs[3])                       // Blob 5
  1731  	generateManifest(descs[0], descs[1:4]...)                  // Blob 6
  1732  	generateIndex(descs[4:6]...)                               // Blob 7
  1733  	generateIndex(descs[6])                                    // Blob 8
  1734  	generateIndex()                                            // Blob 9
  1735  	generateIndex(descs[7:10]...)                              // Blob 10
  1736  
  1737  	ctx := context.Background()
  1738  	for i := range blobs {
  1739  		err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  1740  		if err != nil {
  1741  			t.Fatalf("failed to push test content to src: %d: %v", i, err)
  1742  		}
  1743  	}
  1744  
  1745  	// test copy
  1746  	srcTracker := &storageTracker{Storage: src}
  1747  	dstTracker := &storageTracker{Storage: dst}
  1748  	root := descs[len(descs)-1]
  1749  	if err := oras.CopyGraph(ctx, srcTracker, dstTracker, root, oras.CopyGraphOptions{}); err != nil {
  1750  		t.Fatalf("CopyGraph() error = %v, wantErr %v", err, false)
  1751  	}
  1752  
  1753  	// verify contents
  1754  	for i := range blobs {
  1755  		got, err := content.FetchAll(ctx, dst, descs[i])
  1756  		if err != nil {
  1757  			t.Errorf("content[%d] error = %v, wantErr %v", i, err, false)
  1758  			continue
  1759  		}
  1760  		if want := blobs[i]; !bytes.Equal(got, want) {
  1761  			t.Errorf("content[%d] = %v, want %v", i, got, want)
  1762  		}
  1763  	}
  1764  
  1765  	// verify API counts
  1766  	if got, want := srcTracker.fetch, int64(len(blobs)); got != want {
  1767  		t.Errorf("count(src.Fetch()) = %v, want %v", got, want)
  1768  	}
  1769  	if got, want := srcTracker.push, int64(0); got != want {
  1770  		t.Errorf("count(src.Push()) = %v, want %v", got, want)
  1771  	}
  1772  	if got, want := srcTracker.exists, int64(0); got != want {
  1773  		t.Errorf("count(src.Exists()) = %v, want %v", got, want)
  1774  	}
  1775  	if got, want := dstTracker.fetch, int64(0); got != want {
  1776  		t.Errorf("count(dst.Fetch()) = %v, want %v", got, want)
  1777  	}
  1778  	if got, want := dstTracker.push, int64(len(blobs)); got != want {
  1779  		t.Errorf("count(dst.Push()) = %v, want %v", got, want)
  1780  	}
  1781  	if got, want := dstTracker.exists, int64(len(blobs)); got != want {
  1782  		t.Errorf("count(dst.Exists()) = %v, want %v", got, want)
  1783  	}
  1784  }
  1785  
  1786  func TestCopyGraph_OCIToMemory_PartialCopy(t *testing.T) {
  1787  	tempDir := t.TempDir()
  1788  	src, err := New(tempDir)
  1789  	if err != nil {
  1790  		t.Fatal("OCI.New() error =", err)
  1791  	}
  1792  
  1793  	dst := cas.NewMemory()
  1794  
  1795  	// generate test content
  1796  	var blobs [][]byte
  1797  	var descs []ocispec.Descriptor
  1798  	appendBlob := func(mediaType string, blob []byte) {
  1799  		blobs = append(blobs, blob)
  1800  		descs = append(descs, ocispec.Descriptor{
  1801  			MediaType: mediaType,
  1802  			Digest:    digest.FromBytes(blob),
  1803  			Size:      int64(len(blob)),
  1804  		})
  1805  	}
  1806  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1807  		manifest := ocispec.Manifest{
  1808  			Config: config,
  1809  			Layers: layers,
  1810  		}
  1811  		manifestJSON, err := json.Marshal(manifest)
  1812  		if err != nil {
  1813  			t.Fatal(err)
  1814  		}
  1815  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1816  	}
  1817  	generateIndex := func(manifests ...ocispec.Descriptor) {
  1818  		index := ocispec.Index{
  1819  			Manifests: manifests,
  1820  		}
  1821  		indexJSON, err := json.Marshal(index)
  1822  		if err != nil {
  1823  			t.Fatal(err)
  1824  		}
  1825  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  1826  	}
  1827  
  1828  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1829  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1830  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1831  	generateManifest(descs[0], descs[1:3]...)                  // Blob 3
  1832  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 4
  1833  	generateManifest(descs[0], descs[4])                       // Blob 5
  1834  	generateIndex(descs[3], descs[5])                          // Blob 6
  1835  
  1836  	ctx := context.Background()
  1837  	for i := range blobs {
  1838  		err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  1839  		if err != nil {
  1840  			t.Fatalf("failed to push test content to src: %d: %v", i, err)
  1841  		}
  1842  	}
  1843  
  1844  	// initial copy
  1845  	root := descs[3]
  1846  	if err := oras.CopyGraph(ctx, src, dst, root, oras.CopyGraphOptions{}); err != nil {
  1847  		t.Fatalf("CopyGraph() error = %v, wantErr %v", err, false)
  1848  	}
  1849  	// verify contents
  1850  	for i := range blobs[:4] {
  1851  		got, err := content.FetchAll(ctx, dst, descs[i])
  1852  		if err != nil {
  1853  			t.Fatalf("content[%d] error = %v, wantErr %v", i, err, false)
  1854  		}
  1855  		if want := blobs[i]; !bytes.Equal(got, want) {
  1856  			t.Fatalf("content[%d] = %v, want %v", i, got, want)
  1857  		}
  1858  	}
  1859  
  1860  	// test copy
  1861  	srcTracker := &storageTracker{Storage: src}
  1862  	dstTracker := &storageTracker{Storage: dst}
  1863  	root = descs[len(descs)-1]
  1864  	if err := oras.CopyGraph(ctx, srcTracker, dstTracker, root, oras.CopyGraphOptions{}); err != nil {
  1865  		t.Fatalf("CopyGraph() error = %v, wantErr %v", err, false)
  1866  	}
  1867  
  1868  	// verify contents
  1869  	for i := range blobs {
  1870  		got, err := content.FetchAll(ctx, dst, descs[i])
  1871  		if err != nil {
  1872  			t.Errorf("content[%d] error = %v, wantErr %v", i, err, false)
  1873  			continue
  1874  		}
  1875  		if want := blobs[i]; !bytes.Equal(got, want) {
  1876  			t.Errorf("content[%d] = %v, want %v", i, got, want)
  1877  		}
  1878  	}
  1879  
  1880  	// verify API counts
  1881  	if got, want := srcTracker.fetch, int64(3); got != want {
  1882  		t.Errorf("count(src.Fetch()) = %v, want %v", got, want)
  1883  	}
  1884  	if got, want := srcTracker.push, int64(0); got != want {
  1885  		t.Errorf("count(src.Push()) = %v, want %v", got, want)
  1886  	}
  1887  	if got, want := srcTracker.exists, int64(0); got != want {
  1888  		t.Errorf("count(src.Exists()) = %v, want %v", got, want)
  1889  	}
  1890  	if got, want := dstTracker.fetch, int64(0); got != want {
  1891  		t.Errorf("count(dst.Fetch()) = %v, want %v", got, want)
  1892  	}
  1893  	if got, want := dstTracker.push, int64(3); got != want {
  1894  		t.Errorf("count(dst.Push()) = %v, want %v", got, want)
  1895  	}
  1896  	if got, want := dstTracker.exists, int64(5); got != want {
  1897  		t.Errorf("count(dst.Exists()) = %v, want %v", got, want)
  1898  	}
  1899  }
  1900  
  1901  func TestStore_Tags(t *testing.T) {
  1902  	tempDir := t.TempDir()
  1903  	s, err := New(tempDir)
  1904  	if err != nil {
  1905  		t.Fatal("New() error =", err)
  1906  	}
  1907  	ctx := context.Background()
  1908  
  1909  	// generate test content
  1910  	var blobs [][]byte
  1911  	var descs []ocispec.Descriptor
  1912  	appendBlob := func(mediaType string, blob []byte) {
  1913  		blobs = append(blobs, blob)
  1914  		descs = append(descs, ocispec.Descriptor{
  1915  			MediaType: mediaType,
  1916  			Digest:    digest.FromBytes(blob),
  1917  			Size:      int64(len(blob)),
  1918  		})
  1919  	}
  1920  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1921  		manifest := ocispec.Manifest{
  1922  			Config: config,
  1923  			Layers: layers,
  1924  		}
  1925  		// add annotation to make each manifest unique
  1926  		manifest.Annotations = map[string]string{
  1927  			"blob_index": strconv.Itoa(len(blobs)),
  1928  		}
  1929  		manifestJSON, err := json.Marshal(manifest)
  1930  		if err != nil {
  1931  			t.Fatal(err)
  1932  		}
  1933  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1934  	}
  1935  	tagManifest := func(desc ocispec.Descriptor, ref string) {
  1936  		if err := s.Tag(ctx, desc, ref); err != nil {
  1937  			t.Fatal("Store.Tag() error =", err)
  1938  		}
  1939  	}
  1940  
  1941  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1942  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foobar"))  // Blob 1
  1943  	generateManifest(descs[0], descs[1])                       // Blob 2
  1944  	generateManifest(descs[0], descs[1])                       // Blob 3
  1945  	generateManifest(descs[0], descs[1])                       // Blob 4
  1946  	generateManifest(descs[0], descs[1])                       // Blob 5
  1947  	generateManifest(descs[0], descs[1])                       // Blob 6
  1948  
  1949  	for i := range blobs {
  1950  		err := s.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  1951  		if err != nil {
  1952  			t.Fatalf("failed to push test content: %d: %v", i, err)
  1953  		}
  1954  	}
  1955  
  1956  	tagManifest(descs[3], "v2")
  1957  	tagManifest(descs[4], "v3")
  1958  	tagManifest(descs[5], "v1")
  1959  	tagManifest(descs[6], "v4")
  1960  
  1961  	// test tags
  1962  	tests := []struct {
  1963  		name string
  1964  		last string
  1965  		want []string
  1966  	}{
  1967  		{
  1968  			name: "list all tags",
  1969  			want: []string{"v1", "v2", "v3", "v4"},
  1970  		},
  1971  		{
  1972  			name: "list from middle",
  1973  			last: "v2",
  1974  			want: []string{"v3", "v4"},
  1975  		},
  1976  		{
  1977  			name: "list from end",
  1978  			last: "v4",
  1979  			want: nil,
  1980  		},
  1981  	}
  1982  	for _, tt := range tests {
  1983  		t.Run(tt.name, func(t *testing.T) {
  1984  			if err := s.Tags(ctx, tt.last, func(got []string) error {
  1985  				if !reflect.DeepEqual(got, tt.want) {
  1986  					t.Errorf("Store.Tags() = %v, want %v", got, tt.want)
  1987  				}
  1988  				return nil
  1989  			}); err != nil {
  1990  				t.Errorf("Store.Tags() error = %v", err)
  1991  			}
  1992  		})
  1993  	}
  1994  
  1995  	wantErr := errors.New("expected error")
  1996  	if err := s.Tags(ctx, "", func(got []string) error {
  1997  		return wantErr
  1998  	}); err != wantErr {
  1999  		t.Errorf("Store.Tags() error = %v, wantErr %v", err, wantErr)
  2000  	}
  2001  }
  2002  
  2003  func TestStore_BasicDelete(t *testing.T) {
  2004  	content := []byte("test delete")
  2005  	desc := ocispec.Descriptor{
  2006  		MediaType: "test-delete",
  2007  		Digest:    digest.FromBytes(content),
  2008  		Size:      int64(len(content)),
  2009  	}
  2010  	ref := "latest"
  2011  
  2012  	tempDir := t.TempDir()
  2013  	s, err := New(tempDir)
  2014  	if err != nil {
  2015  		t.Fatal("NewDeletableStore() error =", err)
  2016  	}
  2017  	ctx := context.Background()
  2018  
  2019  	err = s.Push(ctx, desc, bytes.NewReader(content))
  2020  	if err != nil {
  2021  		t.Errorf("Store.Push() error = %v, wantErr %v", err, false)
  2022  	}
  2023  
  2024  	err = s.Tag(ctx, desc, ref)
  2025  	if err != nil {
  2026  		t.Errorf("error tagging descriptor error = %v, wantErr %v", err, false)
  2027  	}
  2028  
  2029  	exists, err := s.Exists(ctx, desc)
  2030  	if err != nil {
  2031  		t.Fatal("Store.Exists() error =", err)
  2032  	}
  2033  	if !exists {
  2034  		t.Errorf("Store.Exists() = %v, want %v", exists, true)
  2035  	}
  2036  
  2037  	resolvedDescr, err := s.Resolve(ctx, ref)
  2038  	if err != nil {
  2039  		t.Errorf("error resolving descriptor error = %v, wantErr %v", err, false)
  2040  	}
  2041  
  2042  	if !reflect.DeepEqual(resolvedDescr, desc) {
  2043  		t.Errorf("Store.Resolve() = %v, want %v", resolvedDescr, desc)
  2044  	}
  2045  
  2046  	err = s.Delete(ctx, desc)
  2047  	if err != nil {
  2048  		t.Errorf("Store.Delete() = %v, wantErr %v", err, nil)
  2049  	}
  2050  
  2051  	exists, err = s.Exists(ctx, desc)
  2052  	if err != nil {
  2053  		t.Fatal("Store.Exists() error =", err)
  2054  	}
  2055  	if exists {
  2056  		t.Errorf("Store.Exists() = %v, want %v", exists, false)
  2057  	}
  2058  }
  2059  
  2060  func TestStore_FetchAndDelete(t *testing.T) {
  2061  	// create a store
  2062  	tempDir := t.TempDir()
  2063  	s, err := New(tempDir)
  2064  	if err != nil {
  2065  		t.Fatal("error =", err)
  2066  	}
  2067  
  2068  	// push a content
  2069  	content := []byte("test delete")
  2070  	desc := ocispec.Descriptor{
  2071  		MediaType: "test-delete",
  2072  		Digest:    digest.FromBytes(content),
  2073  		Size:      int64(len(content)),
  2074  	}
  2075  	err = s.Push(context.Background(), desc, bytes.NewReader(content))
  2076  	if err != nil {
  2077  		t.Fatal("error =", err)
  2078  	}
  2079  
  2080  	// fetch a content
  2081  	rc, err := s.Fetch(context.Background(), desc)
  2082  	if err != nil {
  2083  		t.Fatal("error =", err)
  2084  	}
  2085  
  2086  	// read and verify the content
  2087  	got, err := io.ReadAll(rc)
  2088  	if err != nil {
  2089  		t.Fatal("error =", err)
  2090  	}
  2091  	if !bytes.Equal(got, content) {
  2092  		t.Errorf("Store.Fetch() = %v, want %v", string(got), string(content))
  2093  	}
  2094  	rc.Close()
  2095  
  2096  	// delete. If rc is not closed, Delete would fail on some systems.
  2097  	err = s.Delete(context.Background(), desc)
  2098  	if err != nil {
  2099  		t.Fatal("error =", err)
  2100  	}
  2101  }
  2102  
  2103  func TestStore_PredecessorsAndDelete(t *testing.T) {
  2104  	tempDir := t.TempDir()
  2105  	s, err := New(tempDir)
  2106  	if err != nil {
  2107  		t.Fatal("New() error =", err)
  2108  	}
  2109  	s.AutoGC = false
  2110  	ctx := context.Background()
  2111  
  2112  	// generate test content
  2113  	var blobs [][]byte
  2114  	var descs []ocispec.Descriptor
  2115  	appendBlob := func(mediaType string, blob []byte) {
  2116  		blobs = append(blobs, blob)
  2117  		descs = append(descs, ocispec.Descriptor{
  2118  			MediaType: mediaType,
  2119  			Digest:    digest.FromBytes(blob),
  2120  			Size:      int64(len(blob)),
  2121  		})
  2122  	}
  2123  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  2124  		manifest := ocispec.Manifest{
  2125  			Config: config,
  2126  			Layers: layers,
  2127  		}
  2128  		manifestJSON, err := json.Marshal(manifest)
  2129  		if err != nil {
  2130  			t.Fatal(err)
  2131  		}
  2132  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  2133  	}
  2134  	generateIndex := func(manifests ...ocispec.Descriptor) {
  2135  		index := ocispec.Index{
  2136  			Manifests: manifests,
  2137  		}
  2138  		indexJSON, err := json.Marshal(index)
  2139  		if err != nil {
  2140  			t.Fatal(err)
  2141  		}
  2142  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  2143  	}
  2144  
  2145  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  2146  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  2147  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  2148  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 3
  2149  	generateManifest(descs[0], descs[1:3]...)                  // Blob 4
  2150  	generateManifest(descs[0], descs[3])                       // Blob 5
  2151  	generateManifest(descs[0], descs[1:4]...)                  // Blob 6
  2152  	generateIndex(descs[4:6]...)                               // Blob 7
  2153  	generateIndex(descs[6])                                    // Blob 8
  2154  
  2155  	eg, egCtx := errgroup.WithContext(ctx)
  2156  	for i := range blobs {
  2157  		eg.Go(func(i int) func() error {
  2158  			return func() error {
  2159  				err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i]))
  2160  				if err != nil {
  2161  					return fmt.Errorf("failed to push test content to src: %d: %v", i, err)
  2162  				}
  2163  				return nil
  2164  			}
  2165  		}(i))
  2166  	}
  2167  	if err := eg.Wait(); err != nil {
  2168  		t.Fatal(err)
  2169  	}
  2170  
  2171  	// verify predecessors
  2172  	wants := [][]ocispec.Descriptor{
  2173  		descs[4:7],           // Blob 0
  2174  		{descs[4], descs[6]}, // Blob 1
  2175  		{descs[4], descs[6]}, // Blob 2
  2176  		{descs[5], descs[6]}, // Blob 3
  2177  		{descs[7]},           // Blob 4
  2178  		{descs[7]},           // Blob 5
  2179  		{descs[8]},           // Blob 6
  2180  		nil,                  // Blob 7
  2181  		nil,                  // Blob 8
  2182  	}
  2183  	for i, want := range wants {
  2184  		predecessors, err := s.Predecessors(ctx, descs[i])
  2185  		if err != nil {
  2186  			t.Errorf("Store.Predecessors(%d) error = %v", i, err)
  2187  		}
  2188  		if !equalDescriptorSet(predecessors, want) {
  2189  			t.Errorf("Store.Predecessors(%d) = %v, want %v", i, predecessors, want)
  2190  		}
  2191  	}
  2192  
  2193  	// delete a node and verify the result
  2194  	s.Delete(egCtx, descs[6])
  2195  	// verify predecessors
  2196  	wants = [][]ocispec.Descriptor{
  2197  		descs[4:6], // Blob 0
  2198  		{descs[4]}, // Blob 1
  2199  		{descs[4]}, // Blob 2
  2200  		{descs[5]}, // Blob 3
  2201  		{descs[7]}, // Blob 4
  2202  		{descs[7]}, // Blob 5
  2203  		{descs[8]}, // Blob 6
  2204  		nil,        // Blob 7
  2205  		nil,        // Blob 8
  2206  	}
  2207  	for i, want := range wants {
  2208  		predecessors, err := s.Predecessors(ctx, descs[i])
  2209  		if err != nil {
  2210  			t.Errorf("Store.Predecessors(%d) error = %v", i, err)
  2211  		}
  2212  		if !equalDescriptorSet(predecessors, want) {
  2213  			t.Errorf("Store.Predecessors(%d) = %v, want %v", i, predecessors, want)
  2214  		}
  2215  	}
  2216  
  2217  	// delete a node and verify the result
  2218  	s.Delete(egCtx, descs[8])
  2219  	// verify predecessors
  2220  	wants = [][]ocispec.Descriptor{
  2221  		descs[4:6], // Blob 0
  2222  		{descs[4]}, // Blob 1
  2223  		{descs[4]}, // Blob 2
  2224  		{descs[5]}, // Blob 3
  2225  		{descs[7]}, // Blob 4
  2226  		{descs[7]}, // Blob 5
  2227  		nil,        // Blob 6
  2228  		nil,        // Blob 7
  2229  		nil,        // Blob 8
  2230  	}
  2231  	for i, want := range wants {
  2232  		predecessors, err := s.Predecessors(ctx, descs[i])
  2233  		if err != nil {
  2234  			t.Errorf("Store.Predecessors(%d) error = %v", i, err)
  2235  		}
  2236  		if !equalDescriptorSet(predecessors, want) {
  2237  			t.Errorf("Store.Predecessors(%d) = %v, want %v", i, predecessors, want)
  2238  		}
  2239  	}
  2240  
  2241  	// delete a node and verify the result
  2242  	s.Delete(egCtx, descs[5])
  2243  	// verify predecessors
  2244  	wants = [][]ocispec.Descriptor{
  2245  		{descs[4]}, // Blob 0
  2246  		{descs[4]}, // Blob 1
  2247  		{descs[4]}, // Blob 2
  2248  		nil,        // Blob 3
  2249  		{descs[7]}, // Blob 4
  2250  		{descs[7]}, // Blob 5
  2251  		nil,        // Blob 6
  2252  		nil,        // Blob 7
  2253  		nil,        // Blob 8
  2254  	}
  2255  	for i, want := range wants {
  2256  		predecessors, err := s.Predecessors(ctx, descs[i])
  2257  		if err != nil {
  2258  			t.Errorf("Store.Predecessors(%d) error = %v", i, err)
  2259  		}
  2260  		if !equalDescriptorSet(predecessors, want) {
  2261  			t.Errorf("Store.Predecessors(%d) = %v, want %v", i, predecessors, want)
  2262  		}
  2263  	}
  2264  }
  2265  
  2266  func TestStore_DeleteWithAutoGC(t *testing.T) {
  2267  	tempDir := t.TempDir()
  2268  	s, err := New(tempDir)
  2269  	if err != nil {
  2270  		t.Fatal("New() error =", err)
  2271  	}
  2272  	ctx := context.Background()
  2273  
  2274  	// generate test content
  2275  	var blobs [][]byte
  2276  	var descs []ocispec.Descriptor
  2277  	appendBlob := func(mediaType string, blob []byte) {
  2278  		blobs = append(blobs, blob)
  2279  		descs = append(descs, ocispec.Descriptor{
  2280  			MediaType: mediaType,
  2281  			Digest:    digest.FromBytes(blob),
  2282  			Size:      int64(len(blob)),
  2283  		})
  2284  	}
  2285  	generateManifest := func(config ocispec.Descriptor, subject *ocispec.Descriptor, layers ...ocispec.Descriptor) {
  2286  		manifest := ocispec.Manifest{
  2287  			Config:  config,
  2288  			Subject: subject,
  2289  			Layers:  layers,
  2290  		}
  2291  		manifestJSON, err := json.Marshal(manifest)
  2292  		if err != nil {
  2293  			t.Fatal(err)
  2294  		}
  2295  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  2296  	}
  2297  	generateIndex := func(manifests ...ocispec.Descriptor) {
  2298  		index := ocispec.Index{
  2299  			Manifests: manifests,
  2300  		}
  2301  		indexJSON, err := json.Marshal(index)
  2302  		if err != nil {
  2303  			t.Fatal(err)
  2304  		}
  2305  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  2306  	}
  2307  
  2308  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  2309  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  2310  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  2311  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 3
  2312  	generateManifest(descs[0], nil, descs[1])                  // Blob 4
  2313  	generateManifest(descs[0], nil, descs[2])                  // Blob 5
  2314  	generateManifest(descs[0], nil, descs[3])                  // Blob 6
  2315  	generateIndex(descs[4:6]...)                               // Blob 7
  2316  	generateIndex(descs[6])                                    // Blob 8
  2317  	appendBlob(ocispec.MediaTypeImageLayer, []byte("world"))   // Blob 9
  2318  	generateManifest(descs[0], &descs[6], descs[9])            // Blob 10
  2319  	generateManifest(descs[0], &descs[10], descs[2])           // Blob 11
  2320  
  2321  	eg, egCtx := errgroup.WithContext(ctx)
  2322  	for i := range blobs {
  2323  		eg.Go(func(i int) func() error {
  2324  			return func() error {
  2325  				err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i]))
  2326  				if err != nil {
  2327  					return fmt.Errorf("failed to push test content to src: %d: %v", i, err)
  2328  				}
  2329  				return nil
  2330  			}
  2331  		}(i))
  2332  	}
  2333  	if err := eg.Wait(); err != nil {
  2334  		t.Fatal(err)
  2335  	}
  2336  
  2337  	// delete blob 4 and verify the result
  2338  	if err := s.Delete(egCtx, descs[4]); err != nil {
  2339  		t.Fatal(err)
  2340  	}
  2341  
  2342  	// blob 1 and 4 are now deleted, and other blobs are still present
  2343  	notPresent := []ocispec.Descriptor{descs[1], descs[4]}
  2344  	for _, node := range notPresent {
  2345  		if exists, _ := s.Exists(egCtx, node); exists {
  2346  			t.Errorf("%v should not exist in store", node)
  2347  		}
  2348  	}
  2349  	stillPresent := []ocispec.Descriptor{descs[0], descs[2], descs[3], descs[5], descs[6], descs[7], descs[8], descs[9], descs[10], descs[11]}
  2350  	for _, node := range stillPresent {
  2351  		if exists, _ := s.Exists(egCtx, node); !exists {
  2352  			t.Errorf("%v should exist in store", node)
  2353  		}
  2354  	}
  2355  
  2356  	// delete blob 8 and verify the result
  2357  	if err := s.Delete(egCtx, descs[8]); err != nil {
  2358  		t.Fatal(err)
  2359  	}
  2360  
  2361  	// blob 1, 4 and 8 are now deleted, and other blobs are still present
  2362  	notPresent = []ocispec.Descriptor{descs[1], descs[4], descs[8]}
  2363  	for _, node := range notPresent {
  2364  		if exists, _ := s.Exists(egCtx, node); exists {
  2365  			t.Errorf("%v should not exist in store", node)
  2366  		}
  2367  	}
  2368  	stillPresent = []ocispec.Descriptor{descs[0], descs[2], descs[3], descs[5], descs[6], descs[7], descs[9], descs[10], descs[11]}
  2369  	for _, node := range stillPresent {
  2370  		if exists, _ := s.Exists(egCtx, node); !exists {
  2371  			t.Errorf("%v should exist in store", node)
  2372  		}
  2373  	}
  2374  
  2375  	// delete blob 6 and verify the result
  2376  	if err := s.Delete(egCtx, descs[6]); err != nil {
  2377  		t.Fatal(err)
  2378  	}
  2379  
  2380  	// blob 1, 3, 4, 6, 8, 9, 10, 11 are now deleted, and other blobs are still present
  2381  	notPresent = []ocispec.Descriptor{descs[1], descs[3], descs[4], descs[6], descs[8], descs[9], descs[10], descs[11]}
  2382  	for _, node := range notPresent {
  2383  		if exists, _ := s.Exists(egCtx, node); exists {
  2384  			t.Errorf("%v should not exist in store", node)
  2385  		}
  2386  	}
  2387  	stillPresent = []ocispec.Descriptor{descs[0], descs[2], descs[5], descs[7]}
  2388  	for _, node := range stillPresent {
  2389  		if exists, _ := s.Exists(egCtx, node); !exists {
  2390  			t.Errorf("%v should exist in store", node)
  2391  		}
  2392  	}
  2393  
  2394  	// verify predecessors information
  2395  	wants := [][]ocispec.Descriptor{
  2396  		{descs[5]}, // Blob 0
  2397  		nil,        // Blob 1
  2398  		{descs[5]}, // Blob 2
  2399  		nil,        // Blob 3
  2400  		{descs[7]}, // Blob 4's predecessor is descs[7], even though blob 4 no longer exist
  2401  		{descs[7]}, // Blob 5
  2402  		nil,        // Blob 6
  2403  		nil,        // Blob 7
  2404  		nil,        // Blob 8
  2405  		nil,        // Blob 9
  2406  		nil,        // Blob 10
  2407  		nil,        // Blob 11
  2408  	}
  2409  	for i, want := range wants {
  2410  		predecessors, err := s.Predecessors(ctx, descs[i])
  2411  		if err != nil {
  2412  			t.Errorf("Store.Predecessors(%d) error = %v", i, err)
  2413  		}
  2414  		if !equalDescriptorSet(predecessors, want) {
  2415  			t.Errorf("Store.Predecessors(%d) = %v, want %v", i, predecessors, want)
  2416  		}
  2417  	}
  2418  }
  2419  
  2420  func TestStore_Untag(t *testing.T) {
  2421  	content := []byte("test delete")
  2422  	desc := ocispec.Descriptor{
  2423  		MediaType: "test-delete",
  2424  		Digest:    digest.FromBytes(content),
  2425  		Size:      int64(len(content)),
  2426  	}
  2427  	ref := "latest"
  2428  
  2429  	tempDir := t.TempDir()
  2430  	s, err := New(tempDir)
  2431  	if err != nil {
  2432  		t.Fatal("NewDeletableStore() error =", err)
  2433  	}
  2434  	ctx := context.Background()
  2435  
  2436  	err = s.Push(ctx, desc, bytes.NewReader(content))
  2437  	if err != nil {
  2438  		t.Errorf("Store.Push() error = %v, wantErr %v", err, false)
  2439  	}
  2440  
  2441  	err = s.Tag(ctx, desc, ref)
  2442  	if err != nil {
  2443  		t.Errorf("error tagging descriptor error = %v, wantErr %v", err, false)
  2444  	}
  2445  
  2446  	exists, err := s.Exists(ctx, desc)
  2447  	if err != nil {
  2448  		t.Fatal("Store.Exists() error =", err)
  2449  	}
  2450  	if !exists {
  2451  		t.Errorf("Store.Exists() = %v, want %v", exists, true)
  2452  	}
  2453  
  2454  	resolvedDescr, err := s.Resolve(ctx, ref)
  2455  	if err != nil {
  2456  		t.Errorf("error resolving descriptor error = %v, wantErr %v", err, false)
  2457  	}
  2458  
  2459  	if !reflect.DeepEqual(resolvedDescr, desc) {
  2460  		t.Errorf("Store.Resolve() = %v, want %v", resolvedDescr, desc)
  2461  	}
  2462  
  2463  	err = s.Untag(ctx, ref)
  2464  	if err != nil {
  2465  		t.Errorf("Store.Untag() = %v, wantErr %v", err, nil)
  2466  	}
  2467  
  2468  	_, err = s.Resolve(ctx, ref)
  2469  	if !errors.Is(err, errdef.ErrNotFound) {
  2470  		t.Errorf("error resolving descriptor error = %v, wantErr %v", err, errdef.ErrNotFound)
  2471  	}
  2472  
  2473  	exists, err = s.Exists(ctx, desc)
  2474  	if err != nil {
  2475  		t.Fatal("Store.Exists() error =", err)
  2476  	}
  2477  	if !exists {
  2478  		t.Errorf("Store.Exists() = %v, want %v", exists, true)
  2479  	}
  2480  }
  2481  
  2482  func TestStore_UntagErrorPath(t *testing.T) {
  2483  	content := []byte("test delete")
  2484  	desc := ocispec.Descriptor{
  2485  		MediaType: "test-delete",
  2486  		Digest:    digest.FromBytes(content),
  2487  		Size:      int64(len(content)),
  2488  	}
  2489  	ref := "latest"
  2490  
  2491  	tempDir := t.TempDir()
  2492  	s, err := New(tempDir)
  2493  	if err != nil {
  2494  		t.Fatal("NewDeletableStore() error =", err)
  2495  	}
  2496  	ctx := context.Background()
  2497  
  2498  	err = s.Untag(ctx, "")
  2499  	if !errors.Is(err, errdef.ErrMissingReference) {
  2500  		t.Errorf("Store.Untag() error = %v, wantErr %v", err, errdef.ErrMissingReference)
  2501  	}
  2502  
  2503  	err = s.Untag(ctx, "foobar")
  2504  	if !errors.Is(err, errdef.ErrNotFound) {
  2505  		t.Errorf("Store.Untag() error = %v, wantErr %v", err, errdef.ErrNotFound)
  2506  	}
  2507  
  2508  	err = s.Push(ctx, desc, bytes.NewReader(content))
  2509  	if err != nil {
  2510  		t.Errorf("Store.Push() error = %v, wantErr %v", err, false)
  2511  	}
  2512  
  2513  	err = s.Tag(ctx, desc, ref)
  2514  	if err != nil {
  2515  		t.Errorf("error tagging descriptor error = %v, wantErr %v", err, false)
  2516  	}
  2517  
  2518  	exists, err := s.Exists(ctx, desc)
  2519  	if err != nil {
  2520  		t.Fatal("Store.Exists() error =", err)
  2521  	}
  2522  	if !exists {
  2523  		t.Errorf("Store.Exists() = %v, want %v", exists, true)
  2524  	}
  2525  
  2526  	resolvedDescr, err := s.Resolve(ctx, ref)
  2527  	if err != nil {
  2528  		t.Errorf("error resolving descriptor error = %v, wantErr %v", err, false)
  2529  	}
  2530  
  2531  	err = s.Untag(ctx, resolvedDescr.Digest.String())
  2532  	if !errors.Is(err, errdef.ErrInvalidReference) {
  2533  		t.Errorf("Store.Untag() error = %v, wantErr %v", err, errdef.ErrInvalidReference)
  2534  	}
  2535  }
  2536  
  2537  func TestStore_GC(t *testing.T) {
  2538  	tempDir := t.TempDir()
  2539  	s, err := New(tempDir)
  2540  	if err != nil {
  2541  		t.Fatal("New() error =", err)
  2542  	}
  2543  	ctx := context.Background()
  2544  
  2545  	// generate test content
  2546  	var blobs [][]byte
  2547  	var descs []ocispec.Descriptor
  2548  	appendBlob := func(mediaType string, blob []byte) {
  2549  		blobs = append(blobs, blob)
  2550  		descs = append(descs, ocispec.Descriptor{
  2551  			MediaType: mediaType,
  2552  			Digest:    digest.FromBytes(blob),
  2553  			Size:      int64(len(blob)),
  2554  		})
  2555  	}
  2556  	generateManifest := func(config ocispec.Descriptor, subject *ocispec.Descriptor, layers ...ocispec.Descriptor) {
  2557  		manifest := ocispec.Manifest{
  2558  			Config:  config,
  2559  			Subject: subject,
  2560  			Layers:  layers,
  2561  		}
  2562  		manifestJSON, err := json.Marshal(manifest)
  2563  		if err != nil {
  2564  			t.Fatal(err)
  2565  		}
  2566  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  2567  	}
  2568  	generateImageIndex := func(manifests ...ocispec.Descriptor) {
  2569  		index := ocispec.Index{
  2570  			Manifests: manifests,
  2571  		}
  2572  		indexJSON, err := json.Marshal(index)
  2573  		if err != nil {
  2574  			t.Fatal(err)
  2575  		}
  2576  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  2577  	}
  2578  	generateArtifactManifest := func(blobs ...ocispec.Descriptor) {
  2579  		var manifest spec.Artifact
  2580  		manifest.Blobs = append(manifest.Blobs, blobs...)
  2581  		manifestJSON, err := json.Marshal(manifest)
  2582  		if err != nil {
  2583  			t.Fatal(err)
  2584  		}
  2585  		appendBlob(spec.MediaTypeArtifactManifest, manifestJSON)
  2586  	}
  2587  
  2588  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config"))          // Blob 0
  2589  	appendBlob(ocispec.MediaTypeImageLayer, []byte("blob"))             // Blob 1
  2590  	appendBlob(ocispec.MediaTypeImageLayer, []byte("dangling layer"))   // Blob 2, dangling layer
  2591  	generateManifest(descs[0], nil, descs[1])                           // Blob 3, valid manifest
  2592  	generateManifest(descs[0], &descs[3], descs[1])                     // Blob 4, referrer of a valid manifest
  2593  	appendBlob(ocispec.MediaTypeImageLayer, []byte("dangling layer 2")) // Blob 5, dangling layer
  2594  	generateArtifactManifest(descs[4])                                  // blob 6, dangling artifact
  2595  	generateManifest(descs[0], &descs[5], descs[1])                     // Blob 7, referrer of a dangling manifest
  2596  	appendBlob(ocispec.MediaTypeImageLayer, []byte("dangling layer 3")) // Blob 8, dangling layer
  2597  	generateArtifactManifest(descs[6])                                  // blob 9, dangling artifact
  2598  	generateImageIndex(descs[7], descs[5])                              // blob 10, dangling image index
  2599  	appendBlob(ocispec.MediaTypeImageLayer, []byte("garbage layer 1"))  // Blob 11, garbage layer 1
  2600  	generateManifest(descs[0], nil, descs[4])                           // Blob 12, garbage manifest 1
  2601  	appendBlob(ocispec.MediaTypeImageConfig, []byte("garbage config"))  // Blob 13, garbage config
  2602  	appendBlob(ocispec.MediaTypeImageLayer, []byte("garbage layer 2"))  // Blob 14, garbage layer 2
  2603  	generateManifest(descs[6], nil, descs[7])                           // Blob 15, garbage manifest 2
  2604  	generateManifest(descs[0], &descs[13], descs[1])                    // Blob 16, referrer of a garbage manifest
  2605  	appendBlob(ocispec.MediaTypeImageLayer, []byte("another layer"))    // Blob 17, untagged manifest
  2606  	generateManifest(descs[0], nil, descs[17])                          // Blob 18, valid untagged manifest
  2607  
  2608  	// push blobs 0 - blobs 10 into s
  2609  	for i := 0; i <= 10; i++ {
  2610  		err := s.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  2611  		if err != nil {
  2612  			t.Errorf("failed to push test content to src: %d: %v", i, err)
  2613  		}
  2614  	}
  2615  
  2616  	// push blobs 17 - blobs 18 into s
  2617  	for i := 17; i <= 18; i++ {
  2618  		err := s.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  2619  		if err != nil {
  2620  			t.Errorf("failed to push test content to src: %d: %v", i, err)
  2621  		}
  2622  	}
  2623  
  2624  	// remove blobs 5 - blobs 10 from index.json
  2625  	for i := 5; i <= 10; i++ {
  2626  		s.tagResolver.Untag(string(descs[i].Digest))
  2627  	}
  2628  	s.SaveIndex()
  2629  
  2630  	// push blobs 11 - blobs 16 into s.storage, making them garbage as their metadata
  2631  	// doesn't exist in s
  2632  	for i := 11; i < 17; i++ {
  2633  		err := s.storage.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  2634  		if err != nil {
  2635  			t.Errorf("failed to push test content to src: %d: %v", i, err)
  2636  		}
  2637  	}
  2638  
  2639  	// confirm that all the blobs are in the storage
  2640  	for i := 0; i < len(blobs); i++ {
  2641  		exists, err := s.Exists(ctx, descs[i])
  2642  		if err != nil {
  2643  			t.Fatal(err)
  2644  		}
  2645  		if !exists {
  2646  			t.Fatalf("descs[%d] should exist", i)
  2647  		}
  2648  	}
  2649  
  2650  	// tag manifest blob 3
  2651  	s.Tag(ctx, descs[3], "latest")
  2652  
  2653  	// perform double GC
  2654  	if err = s.GC(ctx); err != nil {
  2655  		t.Fatal(err)
  2656  	}
  2657  	if err = s.GC(ctx); err != nil {
  2658  		t.Fatal(err)
  2659  	}
  2660  
  2661  	// verify existence
  2662  	wantExistence := []bool{true, true, false, true, true, false, false, false,
  2663  		false, false, false, false, false, false, false, false, false, false, false}
  2664  	for i, wantValue := range wantExistence {
  2665  		exists, err := s.Exists(ctx, descs[i])
  2666  		if err != nil {
  2667  			t.Fatal(err)
  2668  		}
  2669  		if exists != wantValue {
  2670  			t.Fatalf("want existence %d to be %v, got %v", i, wantValue, exists)
  2671  		}
  2672  	}
  2673  }
  2674  
  2675  func TestStore_GCAndDeleteOnIndex(t *testing.T) {
  2676  	tempDir := t.TempDir()
  2677  	s, err := New(tempDir)
  2678  	if err != nil {
  2679  		t.Fatal("New() error =", err)
  2680  	}
  2681  	ctx := context.Background()
  2682  
  2683  	// generate test content
  2684  	var blobs [][]byte
  2685  	var descs []ocispec.Descriptor
  2686  	appendBlob := func(mediaType string, blob []byte) {
  2687  		blobs = append(blobs, blob)
  2688  		descs = append(descs, ocispec.Descriptor{
  2689  			MediaType: mediaType,
  2690  			Digest:    digest.FromBytes(blob),
  2691  			Size:      int64(len(blob)),
  2692  		})
  2693  	}
  2694  	generateManifest := func(config ocispec.Descriptor, subject *ocispec.Descriptor, layers ...ocispec.Descriptor) {
  2695  		manifest := ocispec.Manifest{
  2696  			Config:  config,
  2697  			Subject: subject,
  2698  			Layers:  layers,
  2699  		}
  2700  		manifestJSON, err := json.Marshal(manifest)
  2701  		if err != nil {
  2702  			t.Fatal(err)
  2703  		}
  2704  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  2705  	}
  2706  	generateImageIndex := func(manifests ...ocispec.Descriptor) {
  2707  		index := ocispec.Index{
  2708  			Manifests: manifests,
  2709  		}
  2710  		indexJSON, err := json.Marshal(index)
  2711  		if err != nil {
  2712  			t.Fatal(err)
  2713  		}
  2714  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  2715  	}
  2716  
  2717  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  2718  	appendBlob(ocispec.MediaTypeImageLayer, []byte("blob1"))   // Blob 1
  2719  	generateManifest(descs[0], nil, descs[1])                  // Blob 2, manifest
  2720  	appendBlob(ocispec.MediaTypeImageLayer, []byte("blob2"))   // Blob 3
  2721  	generateManifest(descs[0], nil, descs[3])                  // Blob 4, manifest
  2722  	appendBlob(ocispec.MediaTypeImageLayer, []byte("blob3"))   // Blob 5
  2723  	generateManifest(descs[0], nil, descs[5])                  // Blob 6, manifest
  2724  	appendBlob(ocispec.MediaTypeImageLayer, []byte("blob4"))   // Blob 7
  2725  	generateManifest(descs[0], nil, descs[7])                  // Blob 8, manifest
  2726  	generateImageIndex(descs[2], descs[4], descs[6], descs[8]) // blob 9, image index
  2727  
  2728  	// push all blobs into the store
  2729  	for i := 0; i < len(blobs); i++ {
  2730  		err := s.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  2731  		if err != nil {
  2732  			t.Errorf("failed to push test content to src: %d: %v", i, err)
  2733  		}
  2734  	}
  2735  
  2736  	// confirm that all the blobs are in the storage
  2737  	for i := 0; i < len(blobs); i++ {
  2738  		exists, err := s.Exists(ctx, descs[i])
  2739  		if err != nil {
  2740  			t.Fatal(err)
  2741  		}
  2742  		if !exists {
  2743  			t.Fatalf("descs[%d] should exist", i)
  2744  		}
  2745  	}
  2746  
  2747  	// tag manifest blob 8
  2748  	s.Tag(ctx, descs[8], "latest")
  2749  
  2750  	// delete the image index
  2751  	if err := s.Delete(ctx, descs[9]); err != nil {
  2752  		t.Fatal(err)
  2753  	}
  2754  
  2755  	// verify existence
  2756  	wantExistence := []bool{true, false, false, false, false, false, false, true, true, false}
  2757  	for i, wantValue := range wantExistence {
  2758  		exists, err := s.Exists(ctx, descs[i])
  2759  		if err != nil {
  2760  			t.Fatal(err)
  2761  		}
  2762  		if exists != wantValue {
  2763  			t.Fatalf("want existence %d to be %v, got %v", i, wantValue, exists)
  2764  		}
  2765  	}
  2766  }
  2767  
  2768  func TestStore_GCErrorPath(t *testing.T) {
  2769  	tempDir := t.TempDir()
  2770  	s, err := New(tempDir)
  2771  	if err != nil {
  2772  		t.Fatal("New() error =", err)
  2773  	}
  2774  	ctx := context.Background()
  2775  
  2776  	// generate test content
  2777  	var blobs [][]byte
  2778  	var descs []ocispec.Descriptor
  2779  	appendBlob := func(mediaType string, blob []byte) {
  2780  		blobs = append(blobs, blob)
  2781  		descs = append(descs, ocispec.Descriptor{
  2782  			MediaType: mediaType,
  2783  			Digest:    digest.FromBytes(blob),
  2784  			Size:      int64(len(blob)),
  2785  		})
  2786  	}
  2787  	appendBlob(ocispec.MediaTypeImageLayer, []byte("valid blob")) // Blob 0
  2788  
  2789  	// push the valid blob
  2790  	err = s.Push(ctx, descs[0], bytes.NewReader(blobs[0]))
  2791  	if err != nil {
  2792  		t.Error("failed to push test content to src")
  2793  	}
  2794  
  2795  	// write random contents
  2796  	algPath := path.Join(tempDir, "blobs")
  2797  	dgstPath := path.Join(algPath, "sha256")
  2798  	if err := os.WriteFile(path.Join(algPath, "other"), []byte("random"), 0444); err != nil {
  2799  		t.Fatal("error calling WriteFile(), error =", err)
  2800  	}
  2801  	if err := os.WriteFile(path.Join(dgstPath, "other2"), []byte("random2"), 0444); err != nil {
  2802  		t.Fatal("error calling WriteFile(), error =", err)
  2803  	}
  2804  
  2805  	// perform GC
  2806  	if err = s.GC(ctx); err != nil {
  2807  		t.Fatal(err)
  2808  	}
  2809  
  2810  	appendBlob(ocispec.MediaTypeImageLayer, []byte("valid blob 2")) // Blob 1
  2811  
  2812  	// push the valid blob
  2813  	err = s.Push(ctx, descs[1], bytes.NewReader(blobs[1]))
  2814  	if err != nil {
  2815  		t.Error("failed to push test content to src")
  2816  	}
  2817  
  2818  	// unknown algorithm
  2819  	if err := os.Mkdir(path.Join(algPath, "sha666"), 0777); err != nil {
  2820  		t.Fatal(err)
  2821  	}
  2822  	if err = s.GC(ctx); err != nil {
  2823  		t.Fatal("this error should be silently ignored")
  2824  	}
  2825  
  2826  	// os.Remove() error
  2827  	badDigest := digest.FromBytes([]byte("bad digest")).Encoded()
  2828  	badPath := path.Join(algPath, "sha256", badDigest)
  2829  	if err := os.Mkdir(badPath, 0777); err != nil {
  2830  		t.Fatal(err)
  2831  	}
  2832  	if err := os.WriteFile(path.Join(badPath, "whatever"), []byte("extra content"), 0444); err != nil {
  2833  		t.Fatal("error calling WriteFile(), error =", err)
  2834  	}
  2835  	if err = s.GC(ctx); err == nil {
  2836  		t.Fatal("expect an error when os.Remove()")
  2837  	}
  2838  }
  2839  
  2840  func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool {
  2841  	if len(actual) != len(expected) {
  2842  		return false
  2843  	}
  2844  	contains := func(node ocispec.Descriptor) bool {
  2845  		for _, candidate := range actual {
  2846  			if reflect.DeepEqual(candidate, node) {
  2847  				return true
  2848  			}
  2849  		}
  2850  		return false
  2851  	}
  2852  	for _, node := range expected {
  2853  		if !contains(node) {
  2854  			return false
  2855  		}
  2856  	}
  2857  	return true
  2858  }
  2859  
  2860  func Test_isContextDone(t *testing.T) {
  2861  	ctx := context.Background()
  2862  	ctx, cancel := context.WithCancel(ctx)
  2863  	if err := isContextDone(ctx); err != nil {
  2864  		t.Errorf("expect error = %v, got %v", nil, err)
  2865  	}
  2866  	cancel()
  2867  	if err := isContextDone(ctx); err != context.Canceled {
  2868  		t.Errorf("expect error = %v, got %v", context.Canceled, err)
  2869  	}
  2870  }