github.com/opcr-io/oras-go/v2@v2.0.0-20231122155130-eb4260d8a0ae/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/filepath"
    28  	"reflect"
    29  	"strconv"
    30  	"strings"
    31  	"sync/atomic"
    32  	"testing"
    33  
    34  	"github.com/opcr-io/oras-go/v2"
    35  	"github.com/opcr-io/oras-go/v2/content"
    36  	"github.com/opcr-io/oras-go/v2/content/memory"
    37  	"github.com/opcr-io/oras-go/v2/errdef"
    38  	"github.com/opcr-io/oras-go/v2/internal/cas"
    39  	"github.com/opcr-io/oras-go/v2/internal/descriptor"
    40  	"github.com/opcr-io/oras-go/v2/registry"
    41  	"github.com/opencontainers/go-digest"
    42  	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
    43  	"golang.org/x/sync/errgroup"
    44  )
    45  
    46  // storageTracker tracks storage API counts.
    47  type storageTracker struct {
    48  	content.Storage
    49  	fetch  int64
    50  	push   int64
    51  	exists int64
    52  }
    53  
    54  func (t *storageTracker) Fetch(ctx context.Context, target ocispec.Descriptor) (io.ReadCloser, error) {
    55  	atomic.AddInt64(&t.fetch, 1)
    56  	return t.Storage.Fetch(ctx, target)
    57  }
    58  
    59  func (t *storageTracker) Push(ctx context.Context, expected ocispec.Descriptor, content io.Reader) error {
    60  	atomic.AddInt64(&t.push, 1)
    61  	return t.Storage.Push(ctx, expected, content)
    62  }
    63  
    64  func (t *storageTracker) Exists(ctx context.Context, target ocispec.Descriptor) (bool, error) {
    65  	atomic.AddInt64(&t.exists, 1)
    66  	return t.Storage.Exists(ctx, target)
    67  }
    68  
    69  func TestStoreInterface(t *testing.T) {
    70  	var store interface{} = &Store{}
    71  	if _, ok := store.(oras.GraphTarget); !ok {
    72  		t.Error("&Store{} does not conform oras.Target")
    73  	}
    74  	if _, ok := store.(registry.TagLister); !ok {
    75  		t.Error("&Store{} does not conform registry.TagLister")
    76  	}
    77  }
    78  
    79  func TestStore_Success(t *testing.T) {
    80  	blob := []byte("test")
    81  	blobDesc := content.NewDescriptorFromBytes("test", blob)
    82  	manifest := []byte(`{"layers":[]}`)
    83  	manifestDesc := content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest)
    84  	ref := "foobar"
    85  
    86  	tempDir := t.TempDir()
    87  	s, err := New(tempDir)
    88  	if err != nil {
    89  		t.Fatal("New() error =", err)
    90  	}
    91  	ctx := context.Background()
    92  
    93  	// validate layout
    94  	layoutFilePath := filepath.Join(tempDir, ocispec.ImageLayoutFile)
    95  	layoutFile, err := os.Open(layoutFilePath)
    96  	if err != nil {
    97  		t.Errorf("error opening layout file, error = %v", err)
    98  	}
    99  	defer layoutFile.Close()
   100  
   101  	var layout *ocispec.ImageLayout
   102  	err = json.NewDecoder(layoutFile).Decode(&layout)
   103  	if err != nil {
   104  		t.Fatal("error decoding layout, error =", err)
   105  	}
   106  	if want := ocispec.ImageLayoutVersion; layout.Version != want {
   107  		t.Errorf("layout.Version = %s, want %s", layout.Version, want)
   108  	}
   109  
   110  	// validate index.json
   111  	indexFilePath := filepath.Join(tempDir, ociImageIndexFile)
   112  	indexFile, err := os.Open(indexFilePath)
   113  	if err != nil {
   114  		t.Errorf("error opening layout file, error = %v", err)
   115  	}
   116  	defer indexFile.Close()
   117  
   118  	var index *ocispec.Index
   119  	err = json.NewDecoder(indexFile).Decode(&index)
   120  	if err != nil {
   121  		t.Fatal("error decoding index.json, error =", err)
   122  	}
   123  	if want := 2; index.SchemaVersion != want {
   124  		t.Errorf("index.SchemaVersion = %v, want %v", index.SchemaVersion, want)
   125  	}
   126  
   127  	// test push blob
   128  	err = s.Push(ctx, blobDesc, bytes.NewReader(blob))
   129  	if err != nil {
   130  		t.Fatal("Store.Push() error =", err)
   131  	}
   132  	internalResolver := s.tagResolver
   133  	if got, want := len(internalResolver.Map()), 0; got != want {
   134  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   135  	}
   136  
   137  	// test push manifest
   138  	err = s.Push(ctx, manifestDesc, bytes.NewReader(manifest))
   139  	if err != nil {
   140  		t.Fatal("Store.Push() error =", err)
   141  	}
   142  	if got, want := len(internalResolver.Map()), 1; got != want {
   143  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   144  	}
   145  
   146  	// test resolving blob by digest
   147  	gotDesc, err := s.Resolve(ctx, blobDesc.Digest.String())
   148  	if err != nil {
   149  		t.Fatal("Store.Resolve() error =", err)
   150  	}
   151  	if want := blobDesc; gotDesc.Size != want.Size || gotDesc.Digest != want.Digest {
   152  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, blobDesc)
   153  	}
   154  
   155  	// test resolving manifest by digest
   156  	gotDesc, err = s.Resolve(ctx, manifestDesc.Digest.String())
   157  	if err != nil {
   158  		t.Fatal("Store.Resolve() error =", err)
   159  	}
   160  	if !reflect.DeepEqual(gotDesc, manifestDesc) {
   161  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, manifestDesc)
   162  	}
   163  
   164  	// test tag
   165  	err = s.Tag(ctx, manifestDesc, ref)
   166  	if err != nil {
   167  		t.Fatal("Store.Tag() error =", err)
   168  	}
   169  	if got, want := len(internalResolver.Map()), 2; got != want {
   170  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   171  	}
   172  
   173  	// test resolving manifest by tag
   174  	gotDesc, err = s.Resolve(ctx, ref)
   175  	if err != nil {
   176  		t.Fatal("Store.Resolve() error =", err)
   177  	}
   178  	if !reflect.DeepEqual(gotDesc, manifestDesc) {
   179  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, manifestDesc)
   180  	}
   181  
   182  	// test fetch
   183  	exists, err := s.Exists(ctx, manifestDesc)
   184  	if err != nil {
   185  		t.Fatal("Store.Exists() error =", err)
   186  	}
   187  	if !exists {
   188  		t.Errorf("Store.Exists() = %v, want %v", exists, true)
   189  	}
   190  
   191  	rc, err := s.Fetch(ctx, manifestDesc)
   192  	if err != nil {
   193  		t.Fatal("Store.Fetch() error =", err)
   194  	}
   195  	got, err := io.ReadAll(rc)
   196  	if err != nil {
   197  		t.Fatal("Store.Fetch().Read() error =", err)
   198  	}
   199  	err = rc.Close()
   200  	if err != nil {
   201  		t.Error("Store.Fetch().Close() error =", err)
   202  	}
   203  	if !bytes.Equal(got, manifest) {
   204  		t.Errorf("Store.Fetch() = %v, want %v", got, manifest)
   205  	}
   206  }
   207  
   208  func TestStore_RelativeRoot_Success(t *testing.T) {
   209  	blob := []byte("test")
   210  	blobDesc := content.NewDescriptorFromBytes("test", blob)
   211  	manifest := []byte(`{"layers":[]}`)
   212  	manifestDesc := content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest)
   213  	ref := "foobar"
   214  
   215  	tempDir, err := filepath.EvalSymlinks(t.TempDir())
   216  	if err != nil {
   217  		t.Fatal("error calling filepath.EvalSymlinks(), error =", err)
   218  	}
   219  	currDir, err := os.Getwd()
   220  	if err != nil {
   221  		t.Fatal("error calling Getwd(), error=", err)
   222  	}
   223  	if err := os.Chdir(tempDir); err != nil {
   224  		t.Fatal("error calling Chdir(), error=", err)
   225  	}
   226  	s, err := New(".")
   227  	if err != nil {
   228  		t.Fatal("New() error =", err)
   229  	}
   230  	if want := tempDir; s.root != want {
   231  		t.Errorf("Store.root = %s, want %s", s.root, want)
   232  	}
   233  	// cd back to allow the temp directory to be removed
   234  	if err := os.Chdir(currDir); err != nil {
   235  		t.Fatal("error calling Chdir(), error=", err)
   236  	}
   237  	ctx := context.Background()
   238  
   239  	// validate layout
   240  	layoutFilePath := filepath.Join(tempDir, ocispec.ImageLayoutFile)
   241  	layoutFile, err := os.Open(layoutFilePath)
   242  	if err != nil {
   243  		t.Errorf("error opening layout file, error = %v", err)
   244  	}
   245  	defer layoutFile.Close()
   246  
   247  	var layout *ocispec.ImageLayout
   248  	err = json.NewDecoder(layoutFile).Decode(&layout)
   249  	if err != nil {
   250  		t.Fatal("error decoding layout, error =", err)
   251  	}
   252  	if want := ocispec.ImageLayoutVersion; layout.Version != want {
   253  		t.Errorf("layout.Version = %s, want %s", layout.Version, want)
   254  	}
   255  
   256  	// test push blob
   257  	err = s.Push(ctx, blobDesc, bytes.NewReader(blob))
   258  	if err != nil {
   259  		t.Fatal("Store.Push() error =", err)
   260  	}
   261  	internalResolver := s.tagResolver
   262  	if got, want := len(internalResolver.Map()), 0; got != want {
   263  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   264  	}
   265  
   266  	// test push manifest
   267  	err = s.Push(ctx, manifestDesc, bytes.NewReader(manifest))
   268  	if err != nil {
   269  		t.Fatal("Store.Push() error =", err)
   270  	}
   271  	if got, want := len(internalResolver.Map()), 1; got != want {
   272  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   273  	}
   274  
   275  	// test resolving blob by digest
   276  	gotDesc, err := s.Resolve(ctx, blobDesc.Digest.String())
   277  	if err != nil {
   278  		t.Fatal("Store.Resolve() error =", err)
   279  	}
   280  	if want := blobDesc; gotDesc.Size != want.Size || gotDesc.Digest != want.Digest {
   281  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, blobDesc)
   282  	}
   283  
   284  	// test resolving manifest by digest
   285  	gotDesc, err = s.Resolve(ctx, manifestDesc.Digest.String())
   286  	if err != nil {
   287  		t.Fatal("Store.Resolve() error =", err)
   288  	}
   289  	if !reflect.DeepEqual(gotDesc, manifestDesc) {
   290  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, manifestDesc)
   291  	}
   292  
   293  	// test tag
   294  	err = s.Tag(ctx, manifestDesc, ref)
   295  	if err != nil {
   296  		t.Fatal("Store.Tag() error =", err)
   297  	}
   298  	if got, want := len(internalResolver.Map()), 2; got != want {
   299  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   300  	}
   301  
   302  	// test resolving manifest by tag
   303  	gotDesc, err = s.Resolve(ctx, ref)
   304  	if err != nil {
   305  		t.Fatal("Store.Resolve() error =", err)
   306  	}
   307  	if !reflect.DeepEqual(gotDesc, manifestDesc) {
   308  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, manifestDesc)
   309  	}
   310  
   311  	// test fetch
   312  	exists, err := s.Exists(ctx, manifestDesc)
   313  	if err != nil {
   314  		t.Fatal("Store.Exists() error =", err)
   315  	}
   316  	if !exists {
   317  		t.Errorf("Store.Exists() = %v, want %v", exists, true)
   318  	}
   319  
   320  	rc, err := s.Fetch(ctx, manifestDesc)
   321  	if err != nil {
   322  		t.Fatal("Store.Fetch() error =", err)
   323  	}
   324  	got, err := io.ReadAll(rc)
   325  	if err != nil {
   326  		t.Fatal("Store.Fetch().Read() error =", err)
   327  	}
   328  	err = rc.Close()
   329  	if err != nil {
   330  		t.Error("Store.Fetch().Close() error =", err)
   331  	}
   332  	if !bytes.Equal(got, manifest) {
   333  		t.Errorf("Store.Fetch() = %v, want %v", got, manifest)
   334  	}
   335  }
   336  
   337  func TestStore_NotExistingRoot(t *testing.T) {
   338  	tempDir := t.TempDir()
   339  	root := filepath.Join(tempDir, "rootDir")
   340  	_, err := New(root)
   341  	if err != nil {
   342  		t.Fatal("New() error =", err)
   343  	}
   344  
   345  	// validate layout
   346  	layoutFilePath := filepath.Join(root, ocispec.ImageLayoutFile)
   347  	layoutFile, err := os.Open(layoutFilePath)
   348  	if err != nil {
   349  		t.Errorf("error opening layout file, error = %v", err)
   350  	}
   351  	defer layoutFile.Close()
   352  
   353  	var layout *ocispec.ImageLayout
   354  	err = json.NewDecoder(layoutFile).Decode(&layout)
   355  	if err != nil {
   356  		t.Fatal("error decoding layout, error =", err)
   357  	}
   358  	if want := ocispec.ImageLayoutVersion; layout.Version != want {
   359  		t.Errorf("layout.Version = %s, want %s", layout.Version, want)
   360  	}
   361  
   362  	// validate index.json
   363  	indexFilePath := filepath.Join(root, ociImageIndexFile)
   364  	indexFile, err := os.Open(indexFilePath)
   365  	if err != nil {
   366  		t.Errorf("error opening layout file, error = %v", err)
   367  	}
   368  	defer indexFile.Close()
   369  
   370  	var index *ocispec.Index
   371  	err = json.NewDecoder(indexFile).Decode(&index)
   372  	if err != nil {
   373  		t.Fatal("error decoding index.json, error =", err)
   374  	}
   375  	if want := 2; index.SchemaVersion != want {
   376  		t.Errorf("index.SchemaVersion = %v, want %v", index.SchemaVersion, want)
   377  	}
   378  }
   379  
   380  func TestStore_ContentNotFound(t *testing.T) {
   381  	content := []byte("hello world")
   382  	desc := ocispec.Descriptor{
   383  		MediaType: "test",
   384  		Digest:    digest.FromBytes(content),
   385  		Size:      int64(len(content)),
   386  	}
   387  
   388  	tempDir := t.TempDir()
   389  	s, err := New(tempDir)
   390  	if err != nil {
   391  		t.Fatal("New() error =", err)
   392  	}
   393  	ctx := context.Background()
   394  
   395  	exists, err := s.Exists(ctx, desc)
   396  	if err != nil {
   397  		t.Error("Store.Exists() error =", err)
   398  	}
   399  	if exists {
   400  		t.Errorf("Store.Exists() = %v, want %v", exists, false)
   401  	}
   402  
   403  	_, err = s.Fetch(ctx, desc)
   404  	if !errors.Is(err, errdef.ErrNotFound) {
   405  		t.Errorf("Store.Fetch() error = %v, want %v", err, errdef.ErrNotFound)
   406  	}
   407  }
   408  
   409  func TestStore_ContentAlreadyExists(t *testing.T) {
   410  	content := []byte("hello world")
   411  	desc := ocispec.Descriptor{
   412  		MediaType: "test",
   413  		Digest:    digest.FromBytes(content),
   414  		Size:      int64(len(content)),
   415  	}
   416  
   417  	tempDir := t.TempDir()
   418  	s, err := New(tempDir)
   419  	if err != nil {
   420  		t.Fatal("New() error =", err)
   421  	}
   422  	ctx := context.Background()
   423  
   424  	err = s.Push(ctx, desc, bytes.NewReader(content))
   425  	if err != nil {
   426  		t.Fatal("Store.Push() error =", err)
   427  	}
   428  
   429  	err = s.Push(ctx, desc, bytes.NewReader(content))
   430  	if !errors.Is(err, errdef.ErrAlreadyExists) {
   431  		t.Errorf("Store.Push() error = %v, want %v", err, errdef.ErrAlreadyExists)
   432  	}
   433  }
   434  
   435  func TestStore_ContentBadPush(t *testing.T) {
   436  	content := []byte("hello world")
   437  	desc := ocispec.Descriptor{
   438  		MediaType: "test",
   439  		Digest:    digest.FromBytes(content),
   440  		Size:      int64(len(content)),
   441  	}
   442  
   443  	tempDir := t.TempDir()
   444  	s, err := New(tempDir)
   445  	if err != nil {
   446  		t.Fatal("New() error =", err)
   447  	}
   448  	ctx := context.Background()
   449  
   450  	err = s.Push(ctx, desc, strings.NewReader("foobar"))
   451  	if err == nil {
   452  		t.Errorf("Store.Push() error = %v, wantErr %v", err, true)
   453  	}
   454  }
   455  
   456  func TestStore_ResolveByTagReturnsFullDescriptor(t *testing.T) {
   457  	content := []byte("hello world")
   458  	ref := "hello-world:0.0.1"
   459  	annotations := map[string]string{"name": "Hello"}
   460  	desc := ocispec.Descriptor{
   461  		MediaType:   "test",
   462  		Digest:      digest.FromBytes(content),
   463  		Size:        int64(len(content)),
   464  		Annotations: annotations,
   465  	}
   466  
   467  	tempDir := t.TempDir()
   468  	s, err := New(tempDir)
   469  	if err != nil {
   470  		t.Fatal("New() error =", err)
   471  	}
   472  	ctx := context.Background()
   473  
   474  	err = s.Push(ctx, desc, bytes.NewReader(content))
   475  	if err != nil {
   476  		t.Errorf("Store.Push() error = %v, wantErr %v", err, false)
   477  	}
   478  
   479  	err = s.Tag(ctx, desc, ref)
   480  	if err != nil {
   481  		t.Errorf("error tagging descriptor error = %v, wantErr %v", err, false)
   482  	}
   483  
   484  	resolvedDescr, err := s.Resolve(ctx, ref)
   485  	if err != nil {
   486  		t.Errorf("error resolving descriptor error = %v, wantErr %v", err, false)
   487  	}
   488  
   489  	if !reflect.DeepEqual(resolvedDescr, desc) {
   490  		t.Errorf("Store.Resolve() = %v, want %v", resolvedDescr, desc)
   491  	}
   492  }
   493  
   494  func TestStore_ResolveByDigestReturnsPlainDescriptor(t *testing.T) {
   495  	content := []byte("hello world")
   496  	ref := "hello-world:0.0.1"
   497  	desc := ocispec.Descriptor{
   498  		MediaType:   "test",
   499  		Digest:      digest.FromBytes(content),
   500  		Size:        int64(len(content)),
   501  		Annotations: map[string]string{"name": "Hello"},
   502  	}
   503  	plainDescriptor := descriptor.Plain(desc)
   504  
   505  	tempDir := t.TempDir()
   506  	s, err := New(tempDir)
   507  	if err != nil {
   508  		t.Fatal("New() error =", err)
   509  	}
   510  	ctx := context.Background()
   511  
   512  	err = s.Push(ctx, desc, bytes.NewReader(content))
   513  	if err != nil {
   514  		t.Errorf("Store.Push() error = %v, wantErr %v", err, false)
   515  	}
   516  
   517  	err = s.Tag(ctx, desc, ref)
   518  	if err != nil {
   519  		t.Errorf("error tagging descriptor error = %v, wantErr %v", err, false)
   520  	}
   521  
   522  	resolvedDescr, err := s.Resolve(ctx, string(desc.Digest))
   523  	if err != nil {
   524  		t.Errorf("error resolving descriptor error = %v, wantErr %v", err, false)
   525  	}
   526  
   527  	if !reflect.DeepEqual(resolvedDescr, plainDescriptor) {
   528  		t.Errorf("Store.Resolve() = %v, want %v", resolvedDescr, plainDescriptor)
   529  	}
   530  }
   531  
   532  func TestStore_TagNotFound(t *testing.T) {
   533  	ref := "foobar"
   534  
   535  	tempDir := t.TempDir()
   536  	s, err := New(tempDir)
   537  	if err != nil {
   538  		t.Fatal("New() error =", err)
   539  	}
   540  	ctx := context.Background()
   541  
   542  	_, err = s.Resolve(ctx, ref)
   543  	if !errors.Is(err, errdef.ErrNotFound) {
   544  		t.Errorf("Store.Resolve() error = %v, want %v", err, errdef.ErrNotFound)
   545  	}
   546  }
   547  
   548  func TestStore_TagUnknownContent(t *testing.T) {
   549  	content := []byte("hello world")
   550  	desc := ocispec.Descriptor{
   551  		MediaType: "test",
   552  		Digest:    digest.FromBytes(content),
   553  		Size:      int64(len(content)),
   554  	}
   555  	ref := "foobar"
   556  
   557  	tempDir := t.TempDir()
   558  	s, err := New(tempDir)
   559  	if err != nil {
   560  		t.Fatal("New() error =", err)
   561  	}
   562  	ctx := context.Background()
   563  
   564  	err = s.Tag(ctx, desc, ref)
   565  	if !errors.Is(err, errdef.ErrNotFound) {
   566  		t.Errorf("Store.Resolve() error = %v, want %v", err, errdef.ErrNotFound)
   567  	}
   568  }
   569  
   570  func TestStore_DisableAutoSaveIndex(t *testing.T) {
   571  	content := []byte(`{"layers":[]}`)
   572  	desc := ocispec.Descriptor{
   573  		MediaType: ocispec.MediaTypeImageManifest,
   574  		Digest:    digest.FromBytes(content),
   575  		Size:      int64(len(content)),
   576  	}
   577  	ref := "foobar"
   578  
   579  	tempDir := t.TempDir()
   580  	s, err := New(tempDir)
   581  	if err != nil {
   582  		t.Fatal("New() error =", err)
   583  	}
   584  	// disable auto save
   585  	s.AutoSaveIndex = false
   586  	ctx := context.Background()
   587  
   588  	// validate layout
   589  	layoutFilePath := filepath.Join(tempDir, ocispec.ImageLayoutFile)
   590  	layoutFile, err := os.Open(layoutFilePath)
   591  	if err != nil {
   592  		t.Errorf("error opening layout file, error = %v", err)
   593  	}
   594  	defer layoutFile.Close()
   595  
   596  	var layout *ocispec.ImageLayout
   597  	err = json.NewDecoder(layoutFile).Decode(&layout)
   598  	if err != nil {
   599  		t.Fatal("error decoding layout, error =", err)
   600  	}
   601  	if want := ocispec.ImageLayoutVersion; layout.Version != want {
   602  		t.Errorf("layout.Version = %s, want %s", layout.Version, want)
   603  	}
   604  
   605  	// test push
   606  	err = s.Push(ctx, desc, bytes.NewReader(content))
   607  	if err != nil {
   608  		t.Fatal("Store.Push() error =", err)
   609  	}
   610  	internalResolver := s.tagResolver
   611  	if got, want := len(internalResolver.Map()), 1; got != want {
   612  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   613  	}
   614  
   615  	// test resolving by digest
   616  	gotDesc, err := s.Resolve(ctx, desc.Digest.String())
   617  	if err != nil {
   618  		t.Fatal("Store.Resolve() error =", err)
   619  	}
   620  	if !reflect.DeepEqual(gotDesc, desc) {
   621  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   622  	}
   623  
   624  	// test tag
   625  	err = s.Tag(ctx, desc, ref)
   626  	if err != nil {
   627  		t.Fatal("Store.Tag() error =", err)
   628  	}
   629  	if got, want := len(internalResolver.Map()), 2; got != want {
   630  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   631  	}
   632  
   633  	// test resolving by digest
   634  	gotDesc, err = s.Resolve(ctx, ref)
   635  	if err != nil {
   636  		t.Fatal("Store.Resolve() error =", err)
   637  	}
   638  	if !reflect.DeepEqual(gotDesc, desc) {
   639  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   640  	}
   641  
   642  	// test index file
   643  	if got, want := len(s.index.Manifests), 0; got != want {
   644  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   645  	}
   646  	if err := s.SaveIndex(); err != nil {
   647  		t.Fatal("Store.SaveIndex() error =", err)
   648  	}
   649  	// test index file again
   650  	if got, want := len(s.index.Manifests), 1; got != want {
   651  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   652  	}
   653  	if _, err := os.Stat(s.indexPath); err != nil {
   654  		t.Errorf("error: %s does not exist", s.indexPath)
   655  	}
   656  }
   657  
   658  func TestStore_RepeatTag(t *testing.T) {
   659  	tempDir := t.TempDir()
   660  	s, err := New(tempDir)
   661  	if err != nil {
   662  		t.Fatal("New() error =", err)
   663  	}
   664  	ctx := context.Background()
   665  	ref := "foobar"
   666  
   667  	// get internal resolver
   668  	internalResolver := s.tagResolver
   669  
   670  	// first tag a manifest
   671  	manifest := []byte(`{"layers":[]}`)
   672  	desc := content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest)
   673  	err = s.Push(ctx, desc, bytes.NewReader(manifest))
   674  	if err != nil {
   675  		t.Fatal("Store.Push() error =", err)
   676  	}
   677  	if got, want := len(internalResolver.Map()), 1; got != want {
   678  		t.Errorf("len(resolver.Map()) = %v, want %v", got, want)
   679  	}
   680  	if got, want := len(s.index.Manifests), 1; got != want {
   681  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   682  	}
   683  
   684  	err = s.Tag(ctx, desc, ref)
   685  	if err != nil {
   686  		t.Fatal("Store.Tag() error =", err)
   687  	}
   688  	if got, want := len(internalResolver.Map()), 2; got != want {
   689  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   690  	}
   691  	if got, want := len(s.index.Manifests), 1; got != want {
   692  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   693  	}
   694  
   695  	gotDesc, err := s.Resolve(ctx, desc.Digest.String())
   696  	if err != nil {
   697  		t.Fatal("Store.Resolve() error =", err)
   698  	}
   699  	if !reflect.DeepEqual(gotDesc, desc) {
   700  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   701  	}
   702  
   703  	gotDesc, err = s.Resolve(ctx, ref)
   704  	if err != nil {
   705  		t.Fatal("Store.Resolve() error =", err)
   706  	}
   707  	if !reflect.DeepEqual(gotDesc, desc) {
   708  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   709  	}
   710  
   711  	// tag another manifest
   712  	manifest = []byte(`{"layers":[], "annotations":{}}`)
   713  	desc = content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest)
   714  	err = s.Push(ctx, desc, bytes.NewReader(manifest))
   715  	if err != nil {
   716  		t.Fatal("Store.Push() error =", err)
   717  	}
   718  	if got, want := len(internalResolver.Map()), 3; got != want {
   719  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   720  	}
   721  	if got, want := len(s.index.Manifests), 2; got != want {
   722  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   723  	}
   724  
   725  	err = s.Tag(ctx, desc, ref)
   726  	if err != nil {
   727  		t.Fatal("Store.Tag() error =", err)
   728  	}
   729  	if got, want := len(internalResolver.Map()), 3; got != want {
   730  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   731  	}
   732  	if got, want := len(s.index.Manifests), 2; got != want {
   733  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   734  	}
   735  
   736  	gotDesc, err = s.Resolve(ctx, desc.Digest.String())
   737  	if err != nil {
   738  		t.Fatal("Store.Resolve() error =", err)
   739  	}
   740  	if !reflect.DeepEqual(gotDesc, desc) {
   741  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   742  	}
   743  
   744  	gotDesc, err = s.Resolve(ctx, ref)
   745  	if err != nil {
   746  		t.Fatal("Store.Resolve() error =", err)
   747  	}
   748  	if !reflect.DeepEqual(gotDesc, desc) {
   749  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   750  	}
   751  
   752  	// tag a blob
   753  	blob := []byte("foobar")
   754  	desc = content.NewDescriptorFromBytes("test", blob)
   755  	err = s.Push(ctx, desc, bytes.NewReader(blob))
   756  	if err != nil {
   757  		t.Fatal("Store.Push() error =", err)
   758  	}
   759  	if got, want := len(internalResolver.Map()), 3; got != want {
   760  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   761  	}
   762  	if got, want := len(s.index.Manifests), 2; got != want {
   763  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   764  	}
   765  
   766  	err = s.Tag(ctx, desc, ref)
   767  	if err != nil {
   768  		t.Fatal("Store.Tag() error =", err)
   769  	}
   770  	if got, want := len(internalResolver.Map()), 4; got != want {
   771  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   772  	}
   773  	if got, want := len(s.index.Manifests), 3; got != want {
   774  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   775  	}
   776  
   777  	gotDesc, err = s.Resolve(ctx, desc.Digest.String())
   778  	if err != nil {
   779  		t.Fatal("Store.Resolve() error =", err)
   780  	}
   781  	if !reflect.DeepEqual(gotDesc, desc) {
   782  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   783  	}
   784  
   785  	gotDesc, err = s.Resolve(ctx, ref)
   786  	if err != nil {
   787  		t.Fatal("Store.Resolve() error =", err)
   788  	}
   789  	if !reflect.DeepEqual(gotDesc, desc) {
   790  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   791  	}
   792  
   793  	// tag another blob
   794  	blob = []byte("barfoo")
   795  	desc = content.NewDescriptorFromBytes("test", blob)
   796  	err = s.Push(ctx, desc, bytes.NewReader(blob))
   797  	if err != nil {
   798  		t.Fatal("Store.Push() error =", err)
   799  	}
   800  	if got, want := len(internalResolver.Map()), 4; got != want {
   801  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   802  	}
   803  	if got, want := len(s.index.Manifests), 3; got != want {
   804  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   805  	}
   806  
   807  	err = s.Tag(ctx, desc, ref)
   808  	if err != nil {
   809  		t.Fatal("Store.Tag() error =", err)
   810  	}
   811  	if got, want := len(internalResolver.Map()), 5; got != want {
   812  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   813  	}
   814  	if got, want := len(s.index.Manifests), 4; got != want {
   815  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   816  	}
   817  
   818  	gotDesc, err = s.Resolve(ctx, desc.Digest.String())
   819  	if err != nil {
   820  		t.Fatal("Store.Resolve() error =", err)
   821  	}
   822  	if !reflect.DeepEqual(gotDesc, desc) {
   823  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   824  	}
   825  
   826  	gotDesc, err = s.Resolve(ctx, ref)
   827  	if err != nil {
   828  		t.Fatal("Store.Resolve() error =", err)
   829  	}
   830  	if !reflect.DeepEqual(gotDesc, desc) {
   831  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, desc)
   832  	}
   833  }
   834  
   835  // Related bug: https://github.com/oras-project/oras-go/issues/461
   836  func TestStore_TagByDigest(t *testing.T) {
   837  	tempDir := t.TempDir()
   838  	s, err := New(tempDir)
   839  	if err != nil {
   840  		t.Fatal("New() error =", err)
   841  	}
   842  	ctx := context.Background()
   843  
   844  	// get internal resolver
   845  	internalResolver := s.tagResolver
   846  
   847  	manifest := []byte(`{"layers":[]}`)
   848  	manifestDesc := content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest)
   849  
   850  	// push a manifest
   851  	err = s.Push(ctx, manifestDesc, bytes.NewReader(manifest))
   852  	if err != nil {
   853  		t.Fatal("Store.Push() error =", err)
   854  	}
   855  	if got, want := len(internalResolver.Map()), 1; got != want {
   856  		t.Errorf("len(resolver.Map()) = %v, want %v", got, want)
   857  	}
   858  	if got, want := len(s.index.Manifests), 1; got != want {
   859  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   860  	}
   861  	gotDesc, err := s.Resolve(ctx, manifestDesc.Digest.String())
   862  	if err != nil {
   863  		t.Fatal("Store.Resolve() error =", err)
   864  	}
   865  	if !reflect.DeepEqual(gotDesc, manifestDesc) {
   866  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, manifestDesc)
   867  	}
   868  
   869  	// tag manifest by digest
   870  	err = s.Tag(ctx, manifestDesc, manifestDesc.Digest.String())
   871  	if err != nil {
   872  		t.Fatal("Store.Tag() error =", err)
   873  	}
   874  	if got, want := len(internalResolver.Map()), 1; got != want {
   875  		t.Errorf("len(resolver.Map()) = %v, want %v", got, want)
   876  	}
   877  	if got, want := len(s.index.Manifests), 1; got != want {
   878  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   879  	}
   880  	gotDesc, err = s.Resolve(ctx, manifestDesc.Digest.String())
   881  	if err != nil {
   882  		t.Fatal("Store.Resolve() error =", err)
   883  	}
   884  	if !reflect.DeepEqual(gotDesc, manifestDesc) {
   885  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, manifestDesc)
   886  	}
   887  
   888  	// push a blob
   889  	blob := []byte("foobar")
   890  	blobDesc := content.NewDescriptorFromBytes("test", blob)
   891  	err = s.Push(ctx, blobDesc, bytes.NewReader(blob))
   892  	if err != nil {
   893  		t.Fatal("Store.Push() error =", err)
   894  	}
   895  	if got, want := len(internalResolver.Map()), 1; got != want {
   896  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   897  	}
   898  	if got, want := len(s.index.Manifests), 1; got != want {
   899  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   900  	}
   901  	gotDesc, err = s.Resolve(ctx, blobDesc.Digest.String())
   902  	if err != nil {
   903  		t.Fatal("Store.Resolve() error =", err)
   904  	}
   905  	if gotDesc.Digest != blobDesc.Digest || gotDesc.Size != blobDesc.Size {
   906  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, blobDesc)
   907  	}
   908  
   909  	// tag blob by digest
   910  	err = s.Tag(ctx, blobDesc, blobDesc.Digest.String())
   911  	if err != nil {
   912  		t.Fatal("Store.Tag() error =", err)
   913  	}
   914  	if got, want := len(internalResolver.Map()), 2; got != want {
   915  		t.Errorf("resolver.Map() = %v, want %v", got, want)
   916  	}
   917  	if got, want := len(s.index.Manifests), 2; got != want {
   918  		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
   919  	}
   920  	gotDesc, err = s.Resolve(ctx, blobDesc.Digest.String())
   921  	if err != nil {
   922  		t.Fatal("Store.Resolve() error =", err)
   923  	}
   924  	if !reflect.DeepEqual(gotDesc, blobDesc) {
   925  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, blobDesc)
   926  	}
   927  }
   928  
   929  func TestStore_Untag(t *testing.T) {
   930  	content := []byte("hello world")
   931  	ref := "hello-world:0.0.1"
   932  	desc := ocispec.Descriptor{
   933  		MediaType: "test",
   934  		Digest:    digest.FromBytes(content),
   935  		Size:      int64(len(content)),
   936  	}
   937  
   938  	tempDir := t.TempDir()
   939  	s, err := New(tempDir)
   940  	if err != nil {
   941  		t.Fatal("New() error =", err)
   942  	}
   943  	ctx := context.Background()
   944  
   945  	err = s.Push(ctx, desc, bytes.NewReader(content))
   946  	if err != nil {
   947  		t.Errorf("Store.Push() error = %v, wantErr %v", err, false)
   948  	}
   949  
   950  	err = s.Tag(ctx, desc, ref)
   951  	if err != nil {
   952  		t.Errorf("error tagging descriptor error = %v, wantErr %v", err, false)
   953  	}
   954  
   955  	if len(s.tagResolver.Map()) == 0 {
   956  		t.Error("tagresolver map should not be empty")
   957  	}
   958  
   959  	resolvedDescr, err := s.Resolve(ctx, string(desc.Digest))
   960  	if err != nil {
   961  		t.Errorf("error resolving descriptor error = %v, wantErr %v", err, false)
   962  	}
   963  
   964  	if !reflect.DeepEqual(resolvedDescr, desc) {
   965  		t.Errorf("Store.Resolve() = %v, want %v", resolvedDescr, desc)
   966  	}
   967  
   968  	err = s.Untag(ctx, resolvedDescr, ref)
   969  	if err != nil {
   970  		t.Errorf("error untagging descriptor error = %v, wantErr %v", err, false)
   971  	}
   972  
   973  	if len(s.tagResolver.Map()) > 0 {
   974  		t.Error("tagresolver map should be empty")
   975  	}
   976  }
   977  
   978  func TestStore_BadIndex(t *testing.T) {
   979  	tempDir := t.TempDir()
   980  	content := []byte("whatever")
   981  	path := filepath.Join(tempDir, ociImageIndexFile)
   982  	os.WriteFile(path, content, 0666)
   983  
   984  	_, err := New(tempDir)
   985  	if err == nil {
   986  		t.Errorf("New() error = nil, want: error")
   987  	}
   988  }
   989  
   990  func TestStore_BadLayout(t *testing.T) {
   991  	tempDir := t.TempDir()
   992  	content := []byte("whatever")
   993  	path := filepath.Join(tempDir, ocispec.ImageLayoutFile)
   994  	os.WriteFile(path, content, 0666)
   995  
   996  	_, err := New(tempDir)
   997  	if err == nil {
   998  		t.Errorf("New() error = nil, want: error")
   999  	}
  1000  }
  1001  
  1002  func TestStore_Predecessors(t *testing.T) {
  1003  	tempDir := t.TempDir()
  1004  	s, err := New(tempDir)
  1005  	if err != nil {
  1006  		t.Fatal("New() error =", err)
  1007  	}
  1008  	ctx := context.Background()
  1009  
  1010  	// generate test content
  1011  	var blobs [][]byte
  1012  	var descs []ocispec.Descriptor
  1013  	appendBlob := func(mediaType string, blob []byte) {
  1014  		blobs = append(blobs, blob)
  1015  		descs = append(descs, ocispec.Descriptor{
  1016  			MediaType: mediaType,
  1017  			Digest:    digest.FromBytes(blob),
  1018  			Size:      int64(len(blob)),
  1019  		})
  1020  	}
  1021  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1022  		manifest := ocispec.Manifest{
  1023  			Config: config,
  1024  			Layers: layers,
  1025  		}
  1026  		manifestJSON, err := json.Marshal(manifest)
  1027  		if err != nil {
  1028  			t.Fatal(err)
  1029  		}
  1030  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1031  	}
  1032  	generateIndex := func(manifests ...ocispec.Descriptor) {
  1033  		index := ocispec.Index{
  1034  			Manifests: manifests,
  1035  		}
  1036  		indexJSON, err := json.Marshal(index)
  1037  		if err != nil {
  1038  			t.Fatal(err)
  1039  		}
  1040  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  1041  	}
  1042  	generateArtifactManifest := func(subject ocispec.Descriptor, blobs ...ocispec.Descriptor) {
  1043  		var manifest ocispec.Artifact
  1044  		manifest.Subject = &subject
  1045  		manifest.Blobs = append(manifest.Blobs, blobs...)
  1046  		manifestJSON, err := json.Marshal(manifest)
  1047  		if err != nil {
  1048  			t.Fatal(err)
  1049  		}
  1050  		appendBlob(ocispec.MediaTypeArtifactManifest, manifestJSON)
  1051  	}
  1052  
  1053  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1054  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1055  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1056  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 3
  1057  	generateManifest(descs[0], descs[1:3]...)                  // Blob 4
  1058  	generateManifest(descs[0], descs[3])                       // Blob 5
  1059  	generateManifest(descs[0], descs[1:4]...)                  // Blob 6
  1060  	generateIndex(descs[4:6]...)                               // Blob 7
  1061  	generateIndex(descs[6])                                    // Blob 8
  1062  	generateIndex()                                            // Blob 9
  1063  	generateIndex(descs[7:10]...)                              // Blob 10
  1064  	appendBlob(ocispec.MediaTypeImageLayer, []byte("sig_1"))   // Blob 11
  1065  	generateArtifactManifest(descs[6], descs[11])              // Blob 12
  1066  	appendBlob(ocispec.MediaTypeImageLayer, []byte("sig_2"))   // Blob 13
  1067  	generateArtifactManifest(descs[10], descs[13])             // Blob 14
  1068  
  1069  	eg, egCtx := errgroup.WithContext(ctx)
  1070  	for i := range blobs {
  1071  		eg.Go(func(i int) func() error {
  1072  			return func() error {
  1073  				err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i]))
  1074  				if err != nil {
  1075  					return fmt.Errorf("failed to push test content to src: %d: %v", i, err)
  1076  				}
  1077  				return nil
  1078  			}
  1079  		}(i))
  1080  	}
  1081  	if err := eg.Wait(); err != nil {
  1082  		t.Fatal(err)
  1083  	}
  1084  
  1085  	// verify predecessors
  1086  	wants := [][]ocispec.Descriptor{
  1087  		descs[4:7],            // Blob 0
  1088  		{descs[4], descs[6]},  // Blob 1
  1089  		{descs[4], descs[6]},  // Blob 2
  1090  		{descs[5], descs[6]},  // Blob 3
  1091  		{descs[7]},            // Blob 4
  1092  		{descs[7]},            // Blob 5
  1093  		{descs[8], descs[12]}, // Blob 6
  1094  		{descs[10]},           // Blob 7
  1095  		{descs[10]},           // Blob 8
  1096  		{descs[10]},           // Blob 9
  1097  		{descs[14]},           // Blob 10
  1098  		{descs[12]},           // Blob 11
  1099  		nil,                   // Blob 12
  1100  		{descs[14]},           // Blob 13
  1101  		nil,                   // Blob 14
  1102  	}
  1103  	for i, want := range wants {
  1104  		predecessors, err := s.Predecessors(ctx, descs[i])
  1105  		if err != nil {
  1106  			t.Errorf("Store.Predecessors(%d) error = %v", i, err)
  1107  		}
  1108  		if !equalDescriptorSet(predecessors, want) {
  1109  			t.Errorf("Store.Predecessors(%d) = %v, want %v", i, predecessors, want)
  1110  		}
  1111  	}
  1112  }
  1113  
  1114  func TestStore_ExistingStore(t *testing.T) {
  1115  	tempDir := t.TempDir()
  1116  	s, err := New(tempDir)
  1117  	if err != nil {
  1118  		t.Fatal("New() error =", err)
  1119  	}
  1120  
  1121  	// generate test content
  1122  	var blobs [][]byte
  1123  	var descs []ocispec.Descriptor
  1124  	appendBlob := func(mediaType string, blob []byte) {
  1125  		blobs = append(blobs, blob)
  1126  		descs = append(descs, ocispec.Descriptor{
  1127  			MediaType: mediaType,
  1128  			Digest:    digest.FromBytes(blob),
  1129  			Size:      int64(len(blob)),
  1130  		})
  1131  	}
  1132  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1133  		manifest := ocispec.Manifest{
  1134  			Config: config,
  1135  			Layers: layers,
  1136  		}
  1137  		manifestJSON, err := json.Marshal(manifest)
  1138  		if err != nil {
  1139  			t.Fatal(err)
  1140  		}
  1141  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1142  	}
  1143  	generateIndex := func(manifests ...ocispec.Descriptor) {
  1144  		index := ocispec.Index{
  1145  			Manifests: manifests,
  1146  		}
  1147  		indexJSON, err := json.Marshal(index)
  1148  		if err != nil {
  1149  			t.Fatal(err)
  1150  		}
  1151  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  1152  	}
  1153  
  1154  	generateArtifactManifest := func(subject ocispec.Descriptor, blobs ...ocispec.Descriptor) {
  1155  		var manifest ocispec.Artifact
  1156  		manifest.Subject = &subject
  1157  		manifest.Blobs = append(manifest.Blobs, blobs...)
  1158  		manifestJSON, err := json.Marshal(manifest)
  1159  		if err != nil {
  1160  			t.Fatal(err)
  1161  		}
  1162  		appendBlob(ocispec.MediaTypeArtifactManifest, manifestJSON)
  1163  	}
  1164  
  1165  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1166  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1167  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1168  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 3
  1169  	generateManifest(descs[0], descs[1:3]...)                  // Blob 4
  1170  	generateManifest(descs[0], descs[3])                       // Blob 5
  1171  	generateManifest(descs[0], descs[1:4]...)                  // Blob 6
  1172  	generateIndex(descs[4:6]...)                               // Blob 7
  1173  	generateIndex(descs[6])                                    // Blob 8
  1174  	generateIndex()                                            // Blob 9
  1175  	generateIndex(descs[7:10]...)                              // Blob 10
  1176  	appendBlob(ocispec.MediaTypeImageLayer, []byte("sig_1"))   // Blob 11
  1177  	generateArtifactManifest(descs[6], descs[11])              // Blob 12
  1178  	appendBlob(ocispec.MediaTypeImageLayer, []byte("sig_2"))   // Blob 13
  1179  	generateArtifactManifest(descs[10], descs[13])             // Blob 14
  1180  
  1181  	ctx := context.Background()
  1182  	eg, egCtx := errgroup.WithContext(ctx)
  1183  	for i := range blobs {
  1184  		eg.Go(func(i int) func() error {
  1185  			return func() error {
  1186  				err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i]))
  1187  				if err != nil {
  1188  					return fmt.Errorf("failed to push test content to src: %d: %v", i, err)
  1189  				}
  1190  				return nil
  1191  			}
  1192  		}(i))
  1193  	}
  1194  	if err := eg.Wait(); err != nil {
  1195  		t.Fatal(err)
  1196  	}
  1197  
  1198  	// tag index root
  1199  	indexRoot := descs[10]
  1200  	tag := "latest"
  1201  	if err := s.Tag(ctx, indexRoot, tag); err != nil {
  1202  		t.Fatal("Tag() error =", err)
  1203  	}
  1204  	// tag index root by digest
  1205  	// related bug: https://github.com/oras-project/oras-go/issues/461
  1206  	if err := s.Tag(ctx, indexRoot, indexRoot.Digest.String()); err != nil {
  1207  		t.Fatal("Tag() error =", err)
  1208  	}
  1209  
  1210  	// test with another OCI store instance to mock loading from an existing store
  1211  	anotherS, err := New(tempDir)
  1212  	if err != nil {
  1213  		t.Fatal("New() error =", err)
  1214  	}
  1215  
  1216  	// test resolving index root by tag
  1217  	gotDesc, err := anotherS.Resolve(ctx, tag)
  1218  	if err != nil {
  1219  		t.Fatal("Store: Resolve() error =", err)
  1220  	}
  1221  	if !content.Equal(gotDesc, indexRoot) {
  1222  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, indexRoot)
  1223  	}
  1224  
  1225  	// test resolving index root by digest
  1226  	gotDesc, err = anotherS.Resolve(ctx, indexRoot.Digest.String())
  1227  	if err != nil {
  1228  		t.Fatal("Store: Resolve() error =", err)
  1229  	}
  1230  	if !reflect.DeepEqual(gotDesc, indexRoot) {
  1231  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, indexRoot)
  1232  	}
  1233  
  1234  	// test resolving artifact manifest by digest
  1235  	artifactRootDesc := descs[12]
  1236  	gotDesc, err = anotherS.Resolve(ctx, artifactRootDesc.Digest.String())
  1237  	if err != nil {
  1238  		t.Fatal("Store: Resolve() error =", err)
  1239  	}
  1240  	if !reflect.DeepEqual(gotDesc, artifactRootDesc) {
  1241  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, artifactRootDesc)
  1242  	}
  1243  
  1244  	// test resolving blob by digest
  1245  	gotDesc, err = anotherS.Resolve(ctx, descs[0].Digest.String())
  1246  	if err != nil {
  1247  		t.Fatal("Store.Resolve() error =", err)
  1248  	}
  1249  	if want := descs[0]; gotDesc.Size != want.Size || gotDesc.Digest != want.Digest {
  1250  		t.Errorf("Store.Resolve() = %v, want %v", gotDesc, want)
  1251  	}
  1252  
  1253  	// test fetching OCI root index
  1254  	exists, err := anotherS.Exists(ctx, indexRoot)
  1255  	if err != nil {
  1256  		t.Fatal("Store.Exists() error =", err)
  1257  	}
  1258  	if !exists {
  1259  		t.Errorf("Store.Exists() = %v, want %v", exists, true)
  1260  	}
  1261  
  1262  	// test fetching blobs
  1263  	for i := range blobs {
  1264  		eg.Go(func(i int) func() error {
  1265  			return func() error {
  1266  				rc, err := s.Fetch(egCtx, descs[i])
  1267  				if err != nil {
  1268  					return fmt.Errorf("Store.Fetch(%d) error = %v", i, err)
  1269  				}
  1270  				got, err := io.ReadAll(rc)
  1271  				if err != nil {
  1272  					return fmt.Errorf("Store.Fetch(%d).Read() error = %v", i, err)
  1273  				}
  1274  				err = rc.Close()
  1275  				if err != nil {
  1276  					return fmt.Errorf("Store.Fetch(%d).Close() error = %v", i, err)
  1277  				}
  1278  				if !bytes.Equal(got, blobs[i]) {
  1279  					return fmt.Errorf("Store.Fetch(%d) = %v, want %v", i, got, blobs[i])
  1280  				}
  1281  				return nil
  1282  			}
  1283  		}(i))
  1284  	}
  1285  	if err := eg.Wait(); err != nil {
  1286  		t.Fatal(err)
  1287  	}
  1288  
  1289  	// verify predecessors
  1290  	wants := [][]ocispec.Descriptor{
  1291  		descs[4:7],            // Blob 0
  1292  		{descs[4], descs[6]},  // Blob 1
  1293  		{descs[4], descs[6]},  // Blob 2
  1294  		{descs[5], descs[6]},  // Blob 3
  1295  		{descs[7]},            // Blob 4
  1296  		{descs[7]},            // Blob 5
  1297  		{descs[8], descs[12]}, // Blob 6
  1298  		{descs[10]},           // Blob 7
  1299  		{descs[10]},           // Blob 8
  1300  		{descs[10]},           // Blob 9
  1301  		{descs[14]},           // Blob 10
  1302  		{descs[12]},           // Blob 11
  1303  		nil,                   // Blob 12, no predecessors
  1304  		{descs[14]},           // Blob 13
  1305  		nil,                   // Blob 14, no predecessors
  1306  	}
  1307  	for i, want := range wants {
  1308  		predecessors, err := anotherS.Predecessors(ctx, descs[i])
  1309  		if err != nil {
  1310  			t.Errorf("Store.Predecessors(%d) error = %v", i, err)
  1311  		}
  1312  		if !equalDescriptorSet(predecessors, want) {
  1313  			t.Errorf("Store.Predecessors(%d) = %v, want %v", i, predecessors, want)
  1314  		}
  1315  	}
  1316  }
  1317  
  1318  func Test_ExistingStore_Retag(t *testing.T) {
  1319  	tempDir := t.TempDir()
  1320  	s, err := New(tempDir)
  1321  	if err != nil {
  1322  		t.Fatal("New() error =", err)
  1323  	}
  1324  	ctx := context.Background()
  1325  
  1326  	manifest_1 := []byte(`{"layers":[]}`)
  1327  	manifestDesc_1 := content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest_1)
  1328  	manifestDesc_1.Annotations = map[string]string{"key1": "val1"}
  1329  
  1330  	// push a manifest
  1331  	err = s.Push(ctx, manifestDesc_1, bytes.NewReader(manifest_1))
  1332  	if err != nil {
  1333  		t.Fatal("Store.Push() error =", err)
  1334  	}
  1335  	// tag manifest by digest
  1336  	err = s.Tag(ctx, manifestDesc_1, manifestDesc_1.Digest.String())
  1337  	if err != nil {
  1338  		t.Fatal("Store.Tag() error =", err)
  1339  	}
  1340  	// tag manifest by tag
  1341  	ref := "foobar"
  1342  	err = s.Tag(ctx, manifestDesc_1, ref)
  1343  	if err != nil {
  1344  		t.Fatal("Store.Tag() error =", err)
  1345  	}
  1346  
  1347  	// verify index
  1348  	want := []ocispec.Descriptor{
  1349  		{
  1350  			MediaType: manifestDesc_1.MediaType,
  1351  			Digest:    manifestDesc_1.Digest,
  1352  			Size:      manifestDesc_1.Size,
  1353  			Annotations: map[string]string{
  1354  				"key1":                    "val1",
  1355  				ocispec.AnnotationRefName: ref,
  1356  			},
  1357  		},
  1358  	}
  1359  	if got := s.index.Manifests; !equalDescriptorSet(got, want) {
  1360  		t.Errorf("index.Manifests = %v, want %v", got, want)
  1361  	}
  1362  
  1363  	// test with another OCI store instance to mock loading from an existing store
  1364  	anotherS, err := New(tempDir)
  1365  	if err != nil {
  1366  		t.Fatal("New() error =", err)
  1367  	}
  1368  	manifest_2 := []byte(`{"layers":[], "annotations":{}}`)
  1369  	manifestDesc_2 := content.NewDescriptorFromBytes(ocispec.MediaTypeImageManifest, manifest_2)
  1370  	manifestDesc_2.Annotations = map[string]string{"key2": "val2"}
  1371  
  1372  	err = anotherS.Push(ctx, manifestDesc_2, bytes.NewReader(manifest_2))
  1373  	if err != nil {
  1374  		t.Fatal("Store.Push() error =", err)
  1375  	}
  1376  	err = anotherS.Tag(ctx, manifestDesc_2, ref)
  1377  	if err != nil {
  1378  		t.Fatal("Store.Tag() error =", err)
  1379  	}
  1380  
  1381  	// verify index
  1382  	want = []ocispec.Descriptor{
  1383  		{
  1384  			MediaType: manifestDesc_1.MediaType,
  1385  			Digest:    manifestDesc_1.Digest,
  1386  			Size:      manifestDesc_1.Size,
  1387  			Annotations: map[string]string{
  1388  				"key1": "val1",
  1389  			},
  1390  		},
  1391  		{
  1392  			MediaType: manifestDesc_2.MediaType,
  1393  			Digest:    manifestDesc_2.Digest,
  1394  			Size:      manifestDesc_2.Size,
  1395  			Annotations: map[string]string{
  1396  				"key2":                    "val2",
  1397  				ocispec.AnnotationRefName: ref,
  1398  			},
  1399  		},
  1400  	}
  1401  	if got := anotherS.index.Manifests; !equalDescriptorSet(got, want) {
  1402  		t.Errorf("index.Manifests = %v, want %v", got, want)
  1403  	}
  1404  }
  1405  
  1406  func TestCopy_MemoryToOCI_FullCopy(t *testing.T) {
  1407  	src := memory.New()
  1408  
  1409  	tempDir := t.TempDir()
  1410  	dst, err := New(tempDir)
  1411  	if err != nil {
  1412  		t.Fatal("OCI.New() error =", err)
  1413  	}
  1414  
  1415  	// generate test content
  1416  	var blobs [][]byte
  1417  	var descs []ocispec.Descriptor
  1418  	appendBlob := func(mediaType string, blob []byte) {
  1419  		blobs = append(blobs, blob)
  1420  		descs = append(descs, ocispec.Descriptor{
  1421  			MediaType: mediaType,
  1422  			Digest:    digest.FromBytes(blob),
  1423  			Size:      int64(len(blob)),
  1424  		})
  1425  	}
  1426  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1427  		manifest := ocispec.Manifest{
  1428  			Config: config,
  1429  			Layers: layers,
  1430  		}
  1431  		manifestJSON, err := json.Marshal(manifest)
  1432  		if err != nil {
  1433  			t.Fatal(err)
  1434  		}
  1435  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1436  	}
  1437  
  1438  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1439  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1440  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1441  	generateManifest(descs[0], descs[1:3]...)                  // Blob 3
  1442  
  1443  	ctx := context.Background()
  1444  	for i := range blobs {
  1445  		err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  1446  		if err != nil {
  1447  			t.Fatalf("failed to push test content to src: %d: %v", i, err)
  1448  		}
  1449  	}
  1450  
  1451  	root := descs[3]
  1452  	ref := "foobar"
  1453  	err = src.Tag(ctx, root, ref)
  1454  	if err != nil {
  1455  		t.Fatal("fail to tag root node", err)
  1456  	}
  1457  
  1458  	// test copy
  1459  	gotDesc, err := oras.Copy(ctx, src, ref, dst, "", oras.CopyOptions{})
  1460  	if err != nil {
  1461  		t.Fatalf("Copy() error = %v, wantErr %v", err, false)
  1462  	}
  1463  	if !reflect.DeepEqual(gotDesc, root) {
  1464  		t.Errorf("Copy() = %v, want %v", gotDesc, root)
  1465  	}
  1466  
  1467  	// verify contents
  1468  	for i, desc := range descs {
  1469  		exists, err := dst.Exists(ctx, desc)
  1470  		if err != nil {
  1471  			t.Fatalf("dst.Exists(%d) error = %v", i, err)
  1472  		}
  1473  		if !exists {
  1474  			t.Errorf("dst.Exists(%d) = %v, want %v", i, exists, true)
  1475  		}
  1476  	}
  1477  
  1478  	// verify tag
  1479  	gotDesc, err = dst.Resolve(ctx, ref)
  1480  	if err != nil {
  1481  		t.Fatal("dst.Resolve() error =", err)
  1482  	}
  1483  	if !reflect.DeepEqual(gotDesc, root) {
  1484  		t.Errorf("dst.Resolve() = %v, want %v", gotDesc, root)
  1485  	}
  1486  }
  1487  
  1488  func TestCopyGraph_MemoryToOCI_FullCopy(t *testing.T) {
  1489  	src := cas.NewMemory()
  1490  
  1491  	tempDir := t.TempDir()
  1492  	dst, err := New(tempDir)
  1493  	if err != nil {
  1494  		t.Fatal("OCI.New() error =", err)
  1495  	}
  1496  
  1497  	// generate test content
  1498  	var blobs [][]byte
  1499  	var descs []ocispec.Descriptor
  1500  	appendBlob := func(mediaType string, blob []byte) {
  1501  		blobs = append(blobs, blob)
  1502  		descs = append(descs, ocispec.Descriptor{
  1503  			MediaType: mediaType,
  1504  			Digest:    digest.FromBytes(blob),
  1505  			Size:      int64(len(blob)),
  1506  		})
  1507  	}
  1508  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1509  		manifest := ocispec.Manifest{
  1510  			Config: config,
  1511  			Layers: layers,
  1512  		}
  1513  		manifestJSON, err := json.Marshal(manifest)
  1514  		if err != nil {
  1515  			t.Fatal(err)
  1516  		}
  1517  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1518  	}
  1519  	generateIndex := func(manifests ...ocispec.Descriptor) {
  1520  		index := ocispec.Index{
  1521  			Manifests: manifests,
  1522  		}
  1523  		indexJSON, err := json.Marshal(index)
  1524  		if err != nil {
  1525  			t.Fatal(err)
  1526  		}
  1527  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  1528  	}
  1529  
  1530  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1531  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1532  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1533  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 3
  1534  	generateManifest(descs[0], descs[1:3]...)                  // Blob 4
  1535  	generateManifest(descs[0], descs[3])                       // Blob 5
  1536  	generateManifest(descs[0], descs[1:4]...)                  // Blob 6
  1537  	generateIndex(descs[4:6]...)                               // Blob 7
  1538  	generateIndex(descs[6])                                    // Blob 8
  1539  	generateIndex()                                            // Blob 9
  1540  	generateIndex(descs[7:10]...)                              // Blob 10
  1541  
  1542  	ctx := context.Background()
  1543  	for i := range blobs {
  1544  		err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  1545  		if err != nil {
  1546  			t.Fatalf("failed to push test content to src: %d: %v", i, err)
  1547  		}
  1548  	}
  1549  
  1550  	// test copy
  1551  	srcTracker := &storageTracker{Storage: src}
  1552  	dstTracker := &storageTracker{Storage: dst}
  1553  	root := descs[len(descs)-1]
  1554  	if err := oras.CopyGraph(ctx, srcTracker, dstTracker, root, oras.CopyGraphOptions{}); err != nil {
  1555  		t.Fatalf("CopyGraph() error = %v, wantErr %v", err, false)
  1556  	}
  1557  
  1558  	// verify contents
  1559  	for i := range blobs {
  1560  		got, err := content.FetchAll(ctx, dst, descs[i])
  1561  		if err != nil {
  1562  			t.Errorf("content[%d] error = %v, wantErr %v", i, err, false)
  1563  			continue
  1564  		}
  1565  		if want := blobs[i]; !bytes.Equal(got, want) {
  1566  			t.Errorf("content[%d] = %v, want %v", i, got, want)
  1567  		}
  1568  	}
  1569  
  1570  	// verify API counts
  1571  	if got, want := srcTracker.fetch, int64(len(blobs)); got != want {
  1572  		t.Errorf("count(src.Fetch()) = %v, want %v", got, want)
  1573  	}
  1574  	if got, want := srcTracker.push, int64(0); got != want {
  1575  		t.Errorf("count(src.Push()) = %v, want %v", got, want)
  1576  	}
  1577  	if got, want := srcTracker.exists, int64(0); got != want {
  1578  		t.Errorf("count(src.Exists()) = %v, want %v", got, want)
  1579  	}
  1580  	if got, want := dstTracker.fetch, int64(0); got != want {
  1581  		t.Errorf("count(dst.Fetch()) = %v, want %v", got, want)
  1582  	}
  1583  	if got, want := dstTracker.push, int64(len(blobs)); got != want {
  1584  		t.Errorf("count(dst.Push()) = %v, want %v", got, want)
  1585  	}
  1586  	if got, want := dstTracker.exists, int64(len(blobs)); got != want {
  1587  		t.Errorf("count(dst.Exists()) = %v, want %v", got, want)
  1588  	}
  1589  }
  1590  
  1591  func TestCopyGraph_MemoryToOCI_PartialCopy(t *testing.T) {
  1592  	src := cas.NewMemory()
  1593  
  1594  	tempDir := t.TempDir()
  1595  	dst, err := New(tempDir)
  1596  	if err != nil {
  1597  		t.Fatal("OCI.New() error =", err)
  1598  	}
  1599  
  1600  	// generate test content
  1601  	var blobs [][]byte
  1602  	var descs []ocispec.Descriptor
  1603  	appendBlob := func(mediaType string, blob []byte) {
  1604  		blobs = append(blobs, blob)
  1605  		descs = append(descs, ocispec.Descriptor{
  1606  			MediaType: mediaType,
  1607  			Digest:    digest.FromBytes(blob),
  1608  			Size:      int64(len(blob)),
  1609  		})
  1610  	}
  1611  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1612  		manifest := ocispec.Manifest{
  1613  			Config: config,
  1614  			Layers: layers,
  1615  		}
  1616  		manifestJSON, err := json.Marshal(manifest)
  1617  		if err != nil {
  1618  			t.Fatal(err)
  1619  		}
  1620  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1621  	}
  1622  	generateIndex := func(manifests ...ocispec.Descriptor) {
  1623  		index := ocispec.Index{
  1624  			Manifests: manifests,
  1625  		}
  1626  		indexJSON, err := json.Marshal(index)
  1627  		if err != nil {
  1628  			t.Fatal(err)
  1629  		}
  1630  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  1631  	}
  1632  
  1633  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1634  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1635  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1636  	generateManifest(descs[0], descs[1:3]...)                  // Blob 3
  1637  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 4
  1638  	generateManifest(descs[0], descs[4])                       // Blob 5
  1639  	generateIndex(descs[3], descs[5])                          // Blob 6
  1640  
  1641  	ctx := context.Background()
  1642  	for i := range blobs {
  1643  		err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  1644  		if err != nil {
  1645  			t.Fatalf("failed to push test content to src: %d: %v", i, err)
  1646  		}
  1647  	}
  1648  
  1649  	// initial copy
  1650  	root := descs[3]
  1651  	if err := oras.CopyGraph(ctx, src, dst, root, oras.CopyGraphOptions{}); err != nil {
  1652  		t.Fatalf("CopyGraph() error = %v, wantErr %v", err, false)
  1653  	}
  1654  	// verify contents
  1655  	for i := range blobs[:4] {
  1656  		got, err := content.FetchAll(ctx, dst, descs[i])
  1657  		if err != nil {
  1658  			t.Fatalf("content[%d] error = %v, wantErr %v", i, err, false)
  1659  		}
  1660  		if want := blobs[i]; !bytes.Equal(got, want) {
  1661  			t.Fatalf("content[%d] = %v, want %v", i, got, want)
  1662  		}
  1663  	}
  1664  
  1665  	// test copy
  1666  	srcTracker := &storageTracker{Storage: src}
  1667  	dstTracker := &storageTracker{Storage: dst}
  1668  	root = descs[len(descs)-1]
  1669  	if err := oras.CopyGraph(ctx, srcTracker, dstTracker, root, oras.CopyGraphOptions{}); err != nil {
  1670  		t.Fatalf("CopyGraph() error = %v, wantErr %v", err, false)
  1671  	}
  1672  
  1673  	// verify contents
  1674  	for i := range blobs {
  1675  		got, err := content.FetchAll(ctx, dst, descs[i])
  1676  		if err != nil {
  1677  			t.Errorf("content[%d] error = %v, wantErr %v", i, err, false)
  1678  			continue
  1679  		}
  1680  		if want := blobs[i]; !bytes.Equal(got, want) {
  1681  			t.Errorf("content[%d] = %v, want %v", i, got, want)
  1682  		}
  1683  	}
  1684  
  1685  	// verify API counts
  1686  	if got, want := srcTracker.fetch, int64(3); got != want {
  1687  		t.Errorf("count(src.Fetch()) = %v, want %v", got, want)
  1688  	}
  1689  	if got, want := srcTracker.push, int64(0); got != want {
  1690  		t.Errorf("count(src.Push()) = %v, want %v", got, want)
  1691  	}
  1692  	if got, want := srcTracker.exists, int64(0); got != want {
  1693  		t.Errorf("count(src.Exists()) = %v, want %v", got, want)
  1694  	}
  1695  	if got, want := dstTracker.fetch, int64(0); got != want {
  1696  		t.Errorf("count(dst.Fetch()) = %v, want %v", got, want)
  1697  	}
  1698  	if got, want := dstTracker.push, int64(3); got != want {
  1699  		t.Errorf("count(dst.Push()) = %v, want %v", got, want)
  1700  	}
  1701  	if got, want := dstTracker.exists, int64(5); got != want {
  1702  		t.Errorf("count(dst.Exists()) = %v, want %v", got, want)
  1703  	}
  1704  }
  1705  
  1706  func TestCopyGraph_OCIToMemory_FullCopy(t *testing.T) {
  1707  	tempDir := t.TempDir()
  1708  	src, err := New(tempDir)
  1709  	if err != nil {
  1710  		t.Fatal("OCI.New() error =", err)
  1711  	}
  1712  
  1713  	dst := cas.NewMemory()
  1714  
  1715  	// generate test content
  1716  	var blobs [][]byte
  1717  	var descs []ocispec.Descriptor
  1718  	appendBlob := func(mediaType string, blob []byte) {
  1719  		blobs = append(blobs, blob)
  1720  		descs = append(descs, ocispec.Descriptor{
  1721  			MediaType: mediaType,
  1722  			Digest:    digest.FromBytes(blob),
  1723  			Size:      int64(len(blob)),
  1724  		})
  1725  	}
  1726  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1727  		manifest := ocispec.Manifest{
  1728  			Config: config,
  1729  			Layers: layers,
  1730  		}
  1731  		manifestJSON, err := json.Marshal(manifest)
  1732  		if err != nil {
  1733  			t.Fatal(err)
  1734  		}
  1735  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1736  	}
  1737  	generateIndex := func(manifests ...ocispec.Descriptor) {
  1738  		index := ocispec.Index{
  1739  			Manifests: manifests,
  1740  		}
  1741  		indexJSON, err := json.Marshal(index)
  1742  		if err != nil {
  1743  			t.Fatal(err)
  1744  		}
  1745  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  1746  	}
  1747  
  1748  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1749  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1750  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1751  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 3
  1752  	generateManifest(descs[0], descs[1:3]...)                  // Blob 4
  1753  	generateManifest(descs[0], descs[3])                       // Blob 5
  1754  	generateManifest(descs[0], descs[1:4]...)                  // Blob 6
  1755  	generateIndex(descs[4:6]...)                               // Blob 7
  1756  	generateIndex(descs[6])                                    // Blob 8
  1757  	generateIndex()                                            // Blob 9
  1758  	generateIndex(descs[7:10]...)                              // Blob 10
  1759  
  1760  	ctx := context.Background()
  1761  	for i := range blobs {
  1762  		err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  1763  		if err != nil {
  1764  			t.Fatalf("failed to push test content to src: %d: %v", i, err)
  1765  		}
  1766  	}
  1767  
  1768  	// test copy
  1769  	srcTracker := &storageTracker{Storage: src}
  1770  	dstTracker := &storageTracker{Storage: dst}
  1771  	root := descs[len(descs)-1]
  1772  	if err := oras.CopyGraph(ctx, srcTracker, dstTracker, root, oras.CopyGraphOptions{}); err != nil {
  1773  		t.Fatalf("CopyGraph() error = %v, wantErr %v", err, false)
  1774  	}
  1775  
  1776  	// verify contents
  1777  	for i := range blobs {
  1778  		got, err := content.FetchAll(ctx, dst, descs[i])
  1779  		if err != nil {
  1780  			t.Errorf("content[%d] error = %v, wantErr %v", i, err, false)
  1781  			continue
  1782  		}
  1783  		if want := blobs[i]; !bytes.Equal(got, want) {
  1784  			t.Errorf("content[%d] = %v, want %v", i, got, want)
  1785  		}
  1786  	}
  1787  
  1788  	// verify API counts
  1789  	if got, want := srcTracker.fetch, int64(len(blobs)); got != want {
  1790  		t.Errorf("count(src.Fetch()) = %v, want %v", got, want)
  1791  	}
  1792  	if got, want := srcTracker.push, int64(0); got != want {
  1793  		t.Errorf("count(src.Push()) = %v, want %v", got, want)
  1794  	}
  1795  	if got, want := srcTracker.exists, int64(0); got != want {
  1796  		t.Errorf("count(src.Exists()) = %v, want %v", got, want)
  1797  	}
  1798  	if got, want := dstTracker.fetch, int64(0); got != want {
  1799  		t.Errorf("count(dst.Fetch()) = %v, want %v", got, want)
  1800  	}
  1801  	if got, want := dstTracker.push, int64(len(blobs)); got != want {
  1802  		t.Errorf("count(dst.Push()) = %v, want %v", got, want)
  1803  	}
  1804  	if got, want := dstTracker.exists, int64(len(blobs)); got != want {
  1805  		t.Errorf("count(dst.Exists()) = %v, want %v", got, want)
  1806  	}
  1807  }
  1808  
  1809  func TestCopyGraph_OCIToMemory_PartialCopy(t *testing.T) {
  1810  	tempDir := t.TempDir()
  1811  	src, err := New(tempDir)
  1812  	if err != nil {
  1813  		t.Fatal("OCI.New() error =", err)
  1814  	}
  1815  
  1816  	dst := cas.NewMemory()
  1817  
  1818  	// generate test content
  1819  	var blobs [][]byte
  1820  	var descs []ocispec.Descriptor
  1821  	appendBlob := func(mediaType string, blob []byte) {
  1822  		blobs = append(blobs, blob)
  1823  		descs = append(descs, ocispec.Descriptor{
  1824  			MediaType: mediaType,
  1825  			Digest:    digest.FromBytes(blob),
  1826  			Size:      int64(len(blob)),
  1827  		})
  1828  	}
  1829  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1830  		manifest := ocispec.Manifest{
  1831  			Config: config,
  1832  			Layers: layers,
  1833  		}
  1834  		manifestJSON, err := json.Marshal(manifest)
  1835  		if err != nil {
  1836  			t.Fatal(err)
  1837  		}
  1838  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1839  	}
  1840  	generateIndex := func(manifests ...ocispec.Descriptor) {
  1841  		index := ocispec.Index{
  1842  			Manifests: manifests,
  1843  		}
  1844  		indexJSON, err := json.Marshal(index)
  1845  		if err != nil {
  1846  			t.Fatal(err)
  1847  		}
  1848  		appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
  1849  	}
  1850  
  1851  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1852  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foo"))     // Blob 1
  1853  	appendBlob(ocispec.MediaTypeImageLayer, []byte("bar"))     // Blob 2
  1854  	generateManifest(descs[0], descs[1:3]...)                  // Blob 3
  1855  	appendBlob(ocispec.MediaTypeImageLayer, []byte("hello"))   // Blob 4
  1856  	generateManifest(descs[0], descs[4])                       // Blob 5
  1857  	generateIndex(descs[3], descs[5])                          // Blob 6
  1858  
  1859  	ctx := context.Background()
  1860  	for i := range blobs {
  1861  		err := src.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  1862  		if err != nil {
  1863  			t.Fatalf("failed to push test content to src: %d: %v", i, err)
  1864  		}
  1865  	}
  1866  
  1867  	// initial copy
  1868  	root := descs[3]
  1869  	if err := oras.CopyGraph(ctx, src, dst, root, oras.CopyGraphOptions{}); err != nil {
  1870  		t.Fatalf("CopyGraph() error = %v, wantErr %v", err, false)
  1871  	}
  1872  	// verify contents
  1873  	for i := range blobs[:4] {
  1874  		got, err := content.FetchAll(ctx, dst, descs[i])
  1875  		if err != nil {
  1876  			t.Fatalf("content[%d] error = %v, wantErr %v", i, err, false)
  1877  		}
  1878  		if want := blobs[i]; !bytes.Equal(got, want) {
  1879  			t.Fatalf("content[%d] = %v, want %v", i, got, want)
  1880  		}
  1881  	}
  1882  
  1883  	// test copy
  1884  	srcTracker := &storageTracker{Storage: src}
  1885  	dstTracker := &storageTracker{Storage: dst}
  1886  	root = descs[len(descs)-1]
  1887  	if err := oras.CopyGraph(ctx, srcTracker, dstTracker, root, oras.CopyGraphOptions{}); err != nil {
  1888  		t.Fatalf("CopyGraph() error = %v, wantErr %v", err, false)
  1889  	}
  1890  
  1891  	// verify contents
  1892  	for i := range blobs {
  1893  		got, err := content.FetchAll(ctx, dst, descs[i])
  1894  		if err != nil {
  1895  			t.Errorf("content[%d] error = %v, wantErr %v", i, err, false)
  1896  			continue
  1897  		}
  1898  		if want := blobs[i]; !bytes.Equal(got, want) {
  1899  			t.Errorf("content[%d] = %v, want %v", i, got, want)
  1900  		}
  1901  	}
  1902  
  1903  	// verify API counts
  1904  	if got, want := srcTracker.fetch, int64(3); got != want {
  1905  		t.Errorf("count(src.Fetch()) = %v, want %v", got, want)
  1906  	}
  1907  	if got, want := srcTracker.push, int64(0); got != want {
  1908  		t.Errorf("count(src.Push()) = %v, want %v", got, want)
  1909  	}
  1910  	if got, want := srcTracker.exists, int64(0); got != want {
  1911  		t.Errorf("count(src.Exists()) = %v, want %v", got, want)
  1912  	}
  1913  	if got, want := dstTracker.fetch, int64(0); got != want {
  1914  		t.Errorf("count(dst.Fetch()) = %v, want %v", got, want)
  1915  	}
  1916  	if got, want := dstTracker.push, int64(3); got != want {
  1917  		t.Errorf("count(dst.Push()) = %v, want %v", got, want)
  1918  	}
  1919  	if got, want := dstTracker.exists, int64(5); got != want {
  1920  		t.Errorf("count(dst.Exists()) = %v, want %v", got, want)
  1921  	}
  1922  }
  1923  
  1924  func TestStore_Tags(t *testing.T) {
  1925  	tempDir := t.TempDir()
  1926  	s, err := New(tempDir)
  1927  	if err != nil {
  1928  		t.Fatal("New() error =", err)
  1929  	}
  1930  	ctx := context.Background()
  1931  
  1932  	// generate test content
  1933  	var blobs [][]byte
  1934  	var descs []ocispec.Descriptor
  1935  	appendBlob := func(mediaType string, blob []byte) {
  1936  		blobs = append(blobs, blob)
  1937  		descs = append(descs, ocispec.Descriptor{
  1938  			MediaType: mediaType,
  1939  			Digest:    digest.FromBytes(blob),
  1940  			Size:      int64(len(blob)),
  1941  		})
  1942  	}
  1943  	generateManifest := func(config ocispec.Descriptor, layers ...ocispec.Descriptor) {
  1944  		manifest := ocispec.Manifest{
  1945  			Config: config,
  1946  			Layers: layers,
  1947  		}
  1948  		// add annotation to make each manifest unique
  1949  		manifest.Annotations = map[string]string{
  1950  			"blob_index": strconv.Itoa(len(blobs)),
  1951  		}
  1952  		manifestJSON, err := json.Marshal(manifest)
  1953  		if err != nil {
  1954  			t.Fatal(err)
  1955  		}
  1956  		appendBlob(ocispec.MediaTypeImageManifest, manifestJSON)
  1957  	}
  1958  	tagManifest := func(desc ocispec.Descriptor, ref string) {
  1959  		if err := s.Tag(ctx, desc, ref); err != nil {
  1960  			t.Fatal("Store.Tag() error =", err)
  1961  		}
  1962  	}
  1963  
  1964  	appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
  1965  	appendBlob(ocispec.MediaTypeImageLayer, []byte("foobar"))  // Blob 1
  1966  	generateManifest(descs[0], descs[1])                       // Blob 2
  1967  	generateManifest(descs[0], descs[1])                       // Blob 3
  1968  	generateManifest(descs[0], descs[1])                       // Blob 4
  1969  	generateManifest(descs[0], descs[1])                       // Blob 5
  1970  	generateManifest(descs[0], descs[1])                       // Blob 6
  1971  
  1972  	for i := range blobs {
  1973  		err := s.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
  1974  		if err != nil {
  1975  			t.Fatalf("failed to push test content: %d: %v", i, err)
  1976  		}
  1977  	}
  1978  
  1979  	tagManifest(descs[3], "v2")
  1980  	tagManifest(descs[4], "v3")
  1981  	tagManifest(descs[5], "v1")
  1982  	tagManifest(descs[6], "v4")
  1983  
  1984  	// test tags
  1985  	tests := []struct {
  1986  		name string
  1987  		last string
  1988  		want []string
  1989  	}{
  1990  		{
  1991  			name: "list all tags",
  1992  			want: []string{"v1", "v2", "v3", "v4"},
  1993  		},
  1994  		{
  1995  			name: "list from middle",
  1996  			last: "v2",
  1997  			want: []string{"v3", "v4"},
  1998  		},
  1999  		{
  2000  			name: "list from end",
  2001  			last: "v4",
  2002  			want: nil,
  2003  		},
  2004  	}
  2005  	for _, tt := range tests {
  2006  		t.Run(tt.name, func(t *testing.T) {
  2007  			if err := s.Tags(ctx, tt.last, func(got []string) error {
  2008  				if !reflect.DeepEqual(got, tt.want) {
  2009  					t.Errorf("Store.Tags() = %v, want %v", got, tt.want)
  2010  				}
  2011  				return nil
  2012  			}); err != nil {
  2013  				t.Errorf("Store.Tags() error = %v", err)
  2014  			}
  2015  		})
  2016  	}
  2017  
  2018  	wantErr := errors.New("expected error")
  2019  	if err := s.Tags(ctx, "", func(got []string) error {
  2020  		return wantErr
  2021  	}); err != wantErr {
  2022  		t.Errorf("Store.Tags() error = %v, wantErr %v", err, wantErr)
  2023  	}
  2024  }
  2025  
  2026  func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool {
  2027  	if len(actual) != len(expected) {
  2028  		return false
  2029  	}
  2030  	contains := func(node ocispec.Descriptor) bool {
  2031  		for _, candidate := range actual {
  2032  			if reflect.DeepEqual(candidate, node) {
  2033  				return true
  2034  			}
  2035  		}
  2036  		return false
  2037  	}
  2038  	for _, node := range expected {
  2039  		if !contains(node) {
  2040  			return false
  2041  		}
  2042  	}
  2043  	return true
  2044  }
  2045  
  2046  func TestStore_Delete(t *testing.T) {
  2047  	content := []byte("hello world")
  2048  	ref := "hello-world:0.0.1"
  2049  	desc := ocispec.Descriptor{
  2050  		MediaType: "test",
  2051  		Digest:    digest.FromBytes(content),
  2052  		Size:      int64(len(content)),
  2053  	}
  2054  
  2055  	tempDir := t.TempDir()
  2056  	s, err := New(tempDir)
  2057  	if err != nil {
  2058  		t.Fatal("New() error =", err)
  2059  	}
  2060  	ctx := context.Background()
  2061  
  2062  	err = s.Push(ctx, desc, bytes.NewReader(content))
  2063  	if err != nil {
  2064  		t.Errorf("Store.Push() error = %v, wantErr %v", err, false)
  2065  	}
  2066  
  2067  	err = s.Tag(ctx, desc, ref)
  2068  	if err != nil {
  2069  		t.Errorf("error tagging descriptor error = %v, wantErr %v", err, false)
  2070  	}
  2071  
  2072  	resolvedDescr, err := s.Resolve(ctx, ref)
  2073  	if err != nil {
  2074  		t.Errorf("error resolving descriptor error = %v, wantErr %v", err, false)
  2075  	}
  2076  
  2077  	if !reflect.DeepEqual(resolvedDescr, desc) {
  2078  		t.Errorf("Store.Resolve() = %v, want %v", resolvedDescr, desc)
  2079  	}
  2080  
  2081  	err = s.Delete(ctx, resolvedDescr)
  2082  	if err != nil {
  2083  		t.Errorf("Store.Delete() = %v, wantErr %v", err, true)
  2084  	}
  2085  
  2086  	_, err = s.Resolve(ctx, ref)
  2087  	if !errors.Is(err, errdef.ErrNotFound) {
  2088  		t.Errorf("descriptor should no longer exist in store = %v, wantErr %v", err, errdef.ErrNotFound)
  2089  	}
  2090  }
  2091  
  2092  func TestStore_DeleteDescriptoMultipleRefs(t *testing.T) {
  2093  	content := []byte("hello world")
  2094  	ref1 := "hello-world:0.0.1"
  2095  	ref2 := "hello-world:0.0.2"
  2096  	desc := ocispec.Descriptor{
  2097  		MediaType: "test",
  2098  		Digest:    digest.FromBytes(content),
  2099  		Size:      int64(len(content)),
  2100  	}
  2101  
  2102  	tempDir := t.TempDir()
  2103  	s, err := New(tempDir)
  2104  	s.AutoSaveIndex = true
  2105  	if err != nil {
  2106  		t.Fatal("New() error =", err)
  2107  	}
  2108  	ctx := context.Background()
  2109  
  2110  	err = s.Push(ctx, desc, bytes.NewReader(content))
  2111  	if err != nil {
  2112  		t.Errorf("Store.Push() error = %v, wantErr %v", err, false)
  2113  	}
  2114  
  2115  	if len(s.index.Manifests) != 0 {
  2116  		t.Errorf("manifest should be empty but has %d elements", len(s.index.Manifests))
  2117  	}
  2118  
  2119  	err = s.Tag(ctx, desc, ref1)
  2120  	if err != nil {
  2121  		t.Errorf("error tagging descriptor error = %v, wantErr %v", err, false)
  2122  	}
  2123  
  2124  	err = s.Tag(ctx, desc, ref2)
  2125  	if err != nil {
  2126  		t.Errorf("error tagging descriptor error = %v, wantErr %v", err, false)
  2127  	}
  2128  
  2129  	if len(s.index.Manifests) != 2 {
  2130  		t.Errorf("manifest should have %d, but has %d", len(s.index.Manifests), 0)
  2131  	}
  2132  
  2133  	resolvedDescr, err := s.Resolve(ctx, ref1)
  2134  	if err != nil {
  2135  		t.Errorf("error resolving descriptor error = %v, wantErr %v", err, false)
  2136  	}
  2137  
  2138  	if !reflect.DeepEqual(resolvedDescr, desc) {
  2139  		t.Errorf("Store.Resolve() = %v, want %v", resolvedDescr, desc)
  2140  	}
  2141  
  2142  	err = s.Delete(ctx, resolvedDescr)
  2143  	if err != nil {
  2144  		t.Errorf("Store.Delete() = %v, wantErr %v", err, true)
  2145  	}
  2146  
  2147  	if len(s.index.Manifests) != 0 {
  2148  		t.Errorf("manifest should be empty after delete but has %d", len(s.index.Manifests))
  2149  	}
  2150  
  2151  	_, err = s.Resolve(ctx, ref2)
  2152  	if !errors.Is(err, errdef.ErrNotFound) {
  2153  		t.Errorf("descriptor should no longer exist in store = %v, wantErr %v", err, errdef.ErrNotFound)
  2154  	}
  2155  }