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