zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/pkg/extensions/sync/sync_internal_test.go (about)

     1  //go:build sync
     2  // +build sync
     3  
     4  package sync
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"encoding/json"
    10  	"fmt"
    11  	"os"
    12  	"path"
    13  	"testing"
    14  
    15  	dockerManifest "github.com/containers/image/v5/manifest"
    16  	"github.com/containers/image/v5/oci/layout"
    17  	"github.com/containers/image/v5/types"
    18  	godigest "github.com/opencontainers/go-digest"
    19  	ispec "github.com/opencontainers/image-spec/specs-go/v1"
    20  	"github.com/rs/zerolog"
    21  	. "github.com/smartystreets/goconvey/convey"
    22  
    23  	zerr "zotregistry.dev/zot/errors"
    24  	"zotregistry.dev/zot/pkg/extensions/config"
    25  	syncconf "zotregistry.dev/zot/pkg/extensions/config/sync"
    26  	"zotregistry.dev/zot/pkg/extensions/lint"
    27  	"zotregistry.dev/zot/pkg/extensions/monitoring"
    28  	client "zotregistry.dev/zot/pkg/extensions/sync/httpclient"
    29  	"zotregistry.dev/zot/pkg/log"
    30  	mTypes "zotregistry.dev/zot/pkg/meta/types"
    31  	"zotregistry.dev/zot/pkg/storage"
    32  	"zotregistry.dev/zot/pkg/storage/cache"
    33  	storageConstants "zotregistry.dev/zot/pkg/storage/constants"
    34  	"zotregistry.dev/zot/pkg/storage/local"
    35  	. "zotregistry.dev/zot/pkg/test/image-utils"
    36  	"zotregistry.dev/zot/pkg/test/inject"
    37  	"zotregistry.dev/zot/pkg/test/mocks"
    38  	ociutils "zotregistry.dev/zot/pkg/test/oci-utils"
    39  )
    40  
    41  const (
    42  	testImage    = "zot-test"
    43  	testImageTag = "0.0.1"
    44  
    45  	host = "127.0.0.1:45117"
    46  )
    47  
    48  var ErrTestError = fmt.Errorf("testError")
    49  
    50  func TestInjectSyncUtils(t *testing.T) {
    51  	Convey("Inject errors in utils functions", t, func() {
    52  		repositoryReference := fmt.Sprintf("%s/%s", host, testImage)
    53  		ref, err := parseRepositoryReference(repositoryReference)
    54  		So(err, ShouldBeNil)
    55  		So(ref.Name(), ShouldEqual, repositoryReference)
    56  
    57  		injected := inject.InjectFailure(0)
    58  		if injected {
    59  			_, err = getRepoTags(context.Background(), &types.SystemContext{}, host, testImage)
    60  			So(err, ShouldNotBeNil)
    61  		}
    62  
    63  		injected = inject.InjectFailure(0)
    64  		_, err = getPolicyContext(log.NewLogger("debug", ""))
    65  		if injected {
    66  			So(err, ShouldNotBeNil)
    67  		} else {
    68  			So(err, ShouldBeNil)
    69  		}
    70  
    71  		log := log.Logger{Logger: zerolog.New(os.Stdout)}
    72  		metrics := monitoring.NewMetricsServer(false, log)
    73  		imageStore := local.NewImageStore(t.TempDir(), false, false, log, metrics, nil, nil)
    74  		injected = inject.InjectFailure(0)
    75  
    76  		ols := NewOciLayoutStorage(storage.StoreController{DefaultStore: imageStore})
    77  		_, err = ols.GetImageReference(testImage, testImageTag)
    78  		if injected {
    79  			So(err, ShouldNotBeNil)
    80  		} else {
    81  			So(err, ShouldBeNil)
    82  		}
    83  	})
    84  }
    85  
    86  func TestSyncInternal(t *testing.T) {
    87  	Convey("Verify parseRepositoryReference func", t, func() {
    88  		repositoryReference := fmt.Sprintf("%s/%s", host, testImage)
    89  		ref, err := parseRepositoryReference(repositoryReference)
    90  		So(err, ShouldBeNil)
    91  		So(ref.Name(), ShouldEqual, repositoryReference)
    92  
    93  		repositoryReference = fmt.Sprintf("%s/%s:tagged", host, testImage)
    94  		_, err = parseRepositoryReference(repositoryReference)
    95  		So(err, ShouldEqual, zerr.ErrInvalidRepositoryName)
    96  
    97  		repositoryReference = fmt.Sprintf("http://%s/%s", host, testImage)
    98  		_, err = parseRepositoryReference(repositoryReference)
    99  		So(err, ShouldNotBeNil)
   100  
   101  		repositoryReference = fmt.Sprintf("docker://%s/%s", host, testImage)
   102  		_, err = parseRepositoryReference(repositoryReference)
   103  		So(err, ShouldNotBeNil)
   104  
   105  		_, err = getFileCredentials("/path/to/inexistent/file")
   106  		So(err, ShouldNotBeNil)
   107  
   108  		tempFile, err := os.CreateTemp("", "sync-credentials-")
   109  		if err != nil {
   110  			panic(err)
   111  		}
   112  
   113  		content := []byte(`{`)
   114  		if err := os.WriteFile(tempFile.Name(), content, 0o600); err != nil {
   115  			panic(err)
   116  		}
   117  
   118  		_, err = getFileCredentials(tempFile.Name())
   119  		So(err, ShouldNotBeNil)
   120  
   121  		srcCtx := &types.SystemContext{}
   122  		_, err = getRepoTags(context.Background(), srcCtx, host, testImage)
   123  		So(err, ShouldNotBeNil)
   124  
   125  		_, err = getRepoTags(context.Background(), srcCtx, host, testImage)
   126  		So(err, ShouldNotBeNil)
   127  
   128  		_, err = getFileCredentials("/invalid/path/to/file")
   129  		So(err, ShouldNotBeNil)
   130  
   131  		ok := isSupportedMediaType("unknown")
   132  		So(ok, ShouldBeFalse)
   133  	})
   134  }
   135  
   136  func TestRemoteRegistry(t *testing.T) {
   137  	Convey("test remote registry", t, func() {
   138  		logger := log.NewLogger("debug", "")
   139  		cfg := client.Config{
   140  			URL:       "url",
   141  			TLSVerify: false,
   142  		}
   143  
   144  		client, err := client.New(cfg, logger)
   145  		So(err, ShouldBeNil)
   146  
   147  		remote := NewRemoteRegistry(client, logger)
   148  		imageRef, err := layout.NewReference("dir", "image")
   149  		So(err, ShouldBeNil)
   150  		_, _, _, err = remote.GetManifestContent(imageRef)
   151  		So(err, ShouldNotBeNil)
   152  
   153  		tags, err := remote.GetRepoTags("repo")
   154  		So(tags, ShouldBeEmpty)
   155  		So(err, ShouldNotBeNil)
   156  	})
   157  }
   158  
   159  func TestService(t *testing.T) {
   160  	Convey("trigger fetch tags error", t, func() {
   161  		conf := syncconf.RegistryConfig{
   162  			URLs: []string{"http://localhost"},
   163  		}
   164  
   165  		service, err := New(conf, "", os.TempDir(), storage.StoreController{}, mocks.MetaDBMock{}, log.Logger{})
   166  		So(err, ShouldBeNil)
   167  
   168  		err = service.SyncRepo(context.Background(), "repo")
   169  		So(err, ShouldNotBeNil)
   170  	})
   171  }
   172  
   173  func TestSyncRepo(t *testing.T) {
   174  	Convey("trigger context error", t, func() {
   175  		conf := syncconf.RegistryConfig{
   176  			URLs: []string{"http://localhost"},
   177  		}
   178  
   179  		service, err := New(conf, "", os.TempDir(), storage.StoreController{}, mocks.MetaDBMock{}, log.Logger{})
   180  		So(err, ShouldBeNil)
   181  
   182  		service.remote = mocks.SyncRemote{
   183  			GetRepoTagsFn: func(repo string) ([]string, error) {
   184  				return []string{"repo1", "repo2"}, nil
   185  			},
   186  		}
   187  
   188  		ctx, cancel := context.WithCancel(context.Background())
   189  		cancel()
   190  
   191  		err = service.SyncRepo(ctx, "repo")
   192  		So(err, ShouldEqual, ctx.Err())
   193  	})
   194  }
   195  
   196  func TestDestinationRegistry(t *testing.T) {
   197  	Convey("make StoreController", t, func() {
   198  		dir := t.TempDir()
   199  
   200  		log := log.NewLogger("debug", "")
   201  		metrics := monitoring.NewMetricsServer(false, log)
   202  		cacheDriver, _ := storage.Create("boltdb", cache.BoltDBDriverParameters{
   203  			RootDir:     dir,
   204  			Name:        "cache",
   205  			UseRelPaths: true,
   206  		}, log)
   207  
   208  		syncImgStore := local.NewImageStore(dir, true, true, log, metrics, nil, cacheDriver)
   209  		repoName := "repo"
   210  
   211  		storeController := storage.StoreController{DefaultStore: syncImgStore}
   212  		registry := NewDestinationRegistry(storeController, storeController, nil, log)
   213  		imageReference, err := registry.GetImageReference(repoName, "1.0")
   214  		So(err, ShouldBeNil)
   215  		So(imageReference, ShouldNotBeNil)
   216  
   217  		imgStore := getImageStoreFromImageReference(imageReference, repoName, "1.0")
   218  
   219  		// create a blob/layer
   220  		upload, err := imgStore.NewBlobUpload(repoName)
   221  		So(err, ShouldBeNil)
   222  		So(upload, ShouldNotBeEmpty)
   223  
   224  		content := []byte("this is a blob1")
   225  		buf := bytes.NewBuffer(content)
   226  		buflen := buf.Len()
   227  		digest := godigest.FromBytes(content)
   228  		So(digest, ShouldNotBeNil)
   229  		blob, err := imgStore.PutBlobChunkStreamed(repoName, upload, buf)
   230  		So(err, ShouldBeNil)
   231  		So(blob, ShouldEqual, buflen)
   232  		bdgst1 := digest
   233  		bsize1 := len(content)
   234  
   235  		err = imgStore.FinishBlobUpload(repoName, upload, buf, digest)
   236  		So(err, ShouldBeNil)
   237  		So(blob, ShouldEqual, buflen)
   238  
   239  		// push index image
   240  		var index ispec.Index
   241  		index.SchemaVersion = 2
   242  		index.MediaType = ispec.MediaTypeImageIndex
   243  
   244  		for i := 0; i < 4; i++ {
   245  			// upload image config blob
   246  			upload, err := imgStore.NewBlobUpload(repoName)
   247  			So(err, ShouldBeNil)
   248  			So(upload, ShouldNotBeEmpty)
   249  
   250  			cblob, cdigest := GetRandomImageConfig()
   251  			buf := bytes.NewBuffer(cblob)
   252  			buflen := buf.Len()
   253  			blob, err := imgStore.PutBlobChunkStreamed(repoName, upload, buf)
   254  			So(err, ShouldBeNil)
   255  			So(blob, ShouldEqual, buflen)
   256  
   257  			err = imgStore.FinishBlobUpload(repoName, upload, buf, cdigest)
   258  			So(err, ShouldBeNil)
   259  			So(blob, ShouldEqual, buflen)
   260  
   261  			// create a manifest
   262  			manifest := ispec.Manifest{
   263  				Config: ispec.Descriptor{
   264  					MediaType: ispec.MediaTypeImageConfig,
   265  					Digest:    cdigest,
   266  					Size:      int64(len(cblob)),
   267  				},
   268  				Layers: []ispec.Descriptor{
   269  					{
   270  						MediaType: ispec.MediaTypeImageLayer,
   271  						Digest:    bdgst1,
   272  						Size:      int64(bsize1),
   273  					},
   274  				},
   275  			}
   276  			manifest.SchemaVersion = 2
   277  			content, err = json.Marshal(manifest)
   278  			So(err, ShouldBeNil)
   279  			digest = godigest.FromBytes(content)
   280  			So(digest, ShouldNotBeNil)
   281  			_, _, err = imgStore.PutImageManifest(repoName, digest.String(), ispec.MediaTypeImageManifest, content)
   282  			So(err, ShouldBeNil)
   283  
   284  			index.Manifests = append(index.Manifests, ispec.Descriptor{
   285  				Digest:    digest,
   286  				MediaType: ispec.MediaTypeImageManifest,
   287  				Size:      int64(len(content)),
   288  			})
   289  		}
   290  
   291  		// upload index image
   292  		indexContent, err := json.Marshal(index)
   293  		So(err, ShouldBeNil)
   294  		indexDigest := godigest.FromBytes(indexContent)
   295  		So(indexDigest, ShouldNotBeNil)
   296  
   297  		_, _, err = imgStore.PutImageManifest(repoName, "1.0", ispec.MediaTypeImageIndex, indexContent)
   298  		So(err, ShouldBeNil)
   299  
   300  		Convey("sync index image", func() {
   301  			ok, err := registry.CanSkipImage(repoName, "1.0", indexDigest)
   302  			So(ok, ShouldBeFalse)
   303  			So(err, ShouldBeNil)
   304  
   305  			err = registry.CommitImage(imageReference, repoName, "1.0")
   306  			So(err, ShouldBeNil)
   307  		})
   308  
   309  		Convey("trigger GetImageManifest error in CommitImage()", func() {
   310  			err = os.Chmod(imgStore.BlobPath(repoName, indexDigest), 0o000)
   311  			So(err, ShouldBeNil)
   312  
   313  			err = registry.CommitImage(imageReference, repoName, "1.0")
   314  			So(err, ShouldNotBeNil)
   315  		})
   316  
   317  		Convey("trigger linter error in CommitImage()", func() {
   318  			defaultVal := true
   319  			linter := lint.NewLinter(&config.LintConfig{
   320  				BaseConfig: config.BaseConfig{
   321  					Enable: &defaultVal,
   322  				},
   323  				MandatoryAnnotations: []string{"annot1"},
   324  			}, log)
   325  
   326  			syncImgStore := local.NewImageStore(dir, true, true, log, metrics, linter, cacheDriver)
   327  			repoName := "repo"
   328  
   329  			storeController := storage.StoreController{DefaultStore: syncImgStore}
   330  			registry := NewDestinationRegistry(storeController, storeController, nil, log)
   331  
   332  			err = registry.CommitImage(imageReference, repoName, "1.0")
   333  			So(err, ShouldBeNil)
   334  		})
   335  
   336  		Convey("trigger GetBlobContent on manifest error in CommitImage()", func() {
   337  			err = os.Chmod(imgStore.BlobPath(repoName, digest), 0o000)
   338  			So(err, ShouldBeNil)
   339  
   340  			err = registry.CommitImage(imageReference, repoName, "1.0")
   341  			So(err, ShouldNotBeNil)
   342  		})
   343  
   344  		Convey("trigger copyBlob() error in CommitImage()", func() {
   345  			err = os.Chmod(imgStore.BlobPath(repoName, bdgst1), 0o000)
   346  			So(err, ShouldBeNil)
   347  
   348  			err = registry.CommitImage(imageReference, repoName, "1.0")
   349  			So(err, ShouldNotBeNil)
   350  		})
   351  
   352  		Convey("trigger PutImageManifest error on index manifest in CommitImage()", func() {
   353  			err = os.MkdirAll(syncImgStore.BlobPath(repoName, indexDigest), storageConstants.DefaultDirPerms)
   354  			So(err, ShouldBeNil)
   355  
   356  			err = os.Chmod(syncImgStore.BlobPath(repoName, indexDigest), 0o000)
   357  			So(err, ShouldBeNil)
   358  
   359  			err = registry.CommitImage(imageReference, repoName, "1.0")
   360  			So(err, ShouldNotBeNil)
   361  		})
   362  
   363  		Convey("trigger metaDB error on index manifest in CommitImage()", func() {
   364  			storeController := storage.StoreController{DefaultStore: syncImgStore}
   365  			registry := NewDestinationRegistry(storeController, storeController, mocks.MetaDBMock{
   366  				SetRepoReferenceFn: func(ctx context.Context, repo string, reference string, imageMeta mTypes.ImageMeta) error {
   367  					if reference == "1.0" {
   368  						return zerr.ErrRepoMetaNotFound
   369  					}
   370  
   371  					return nil
   372  				},
   373  			}, log)
   374  
   375  			err = registry.CommitImage(imageReference, repoName, "1.0")
   376  			So(err, ShouldNotBeNil)
   377  		})
   378  
   379  		Convey("trigger metaDB error on image manifest in CommitImage()", func() {
   380  			storeController := storage.StoreController{DefaultStore: syncImgStore}
   381  			registry := NewDestinationRegistry(storeController, storeController, mocks.MetaDBMock{
   382  				SetRepoReferenceFn: func(ctx context.Context, repo, reference string, imageMeta mTypes.ImageMeta) error {
   383  					return zerr.ErrRepoMetaNotFound
   384  				},
   385  			}, log)
   386  
   387  			err = registry.CommitImage(imageReference, repoName, "1.0")
   388  			So(err, ShouldNotBeNil)
   389  		})
   390  
   391  		Convey("push image", func() {
   392  			imageReference, err := registry.GetImageReference(repoName, "2.0")
   393  			So(err, ShouldBeNil)
   394  			So(imageReference, ShouldNotBeNil)
   395  
   396  			imgStore := getImageStoreFromImageReference(imageReference, repoName, "2.0")
   397  
   398  			// upload image
   399  
   400  			// create a blob/layer
   401  			upload, err := imgStore.NewBlobUpload(repoName)
   402  			So(err, ShouldBeNil)
   403  			So(upload, ShouldNotBeEmpty)
   404  
   405  			content := []byte("this is a blob1")
   406  			buf := bytes.NewBuffer(content)
   407  			buflen := buf.Len()
   408  			digest := godigest.FromBytes(content)
   409  			So(digest, ShouldNotBeNil)
   410  			blob, err := imgStore.PutBlobChunkStreamed(repoName, upload, buf)
   411  			So(err, ShouldBeNil)
   412  			So(blob, ShouldEqual, buflen)
   413  			bdgst1 := digest
   414  			bsize1 := len(content)
   415  
   416  			err = imgStore.FinishBlobUpload(repoName, upload, buf, digest)
   417  			So(err, ShouldBeNil)
   418  			So(blob, ShouldEqual, buflen)
   419  
   420  			// upload image config blob
   421  			upload, err = imgStore.NewBlobUpload(repoName)
   422  			So(err, ShouldBeNil)
   423  			So(upload, ShouldNotBeEmpty)
   424  
   425  			cblob, cdigest := GetRandomImageConfig()
   426  			buf = bytes.NewBuffer(cblob)
   427  			buflen = buf.Len()
   428  			blob, err = imgStore.PutBlobChunkStreamed(repoName, upload, buf)
   429  			So(err, ShouldBeNil)
   430  			So(blob, ShouldEqual, buflen)
   431  
   432  			err = imgStore.FinishBlobUpload(repoName, upload, buf, cdigest)
   433  			So(err, ShouldBeNil)
   434  			So(blob, ShouldEqual, buflen)
   435  
   436  			// create a manifest
   437  			manifest := ispec.Manifest{
   438  				Config: ispec.Descriptor{
   439  					MediaType: ispec.MediaTypeImageConfig,
   440  					Digest:    cdigest,
   441  					Size:      int64(len(cblob)),
   442  				},
   443  				Layers: []ispec.Descriptor{
   444  					{
   445  						MediaType: ispec.MediaTypeImageLayer,
   446  						Digest:    bdgst1,
   447  						Size:      int64(bsize1),
   448  					},
   449  				},
   450  			}
   451  			manifest.SchemaVersion = 2
   452  			content, err = json.Marshal(manifest)
   453  			So(err, ShouldBeNil)
   454  			digest = godigest.FromBytes(content)
   455  			So(digest, ShouldNotBeNil)
   456  
   457  			_, _, err = imgStore.PutImageManifest(repoName, "2.0", ispec.MediaTypeImageManifest, content)
   458  			So(err, ShouldBeNil)
   459  
   460  			Convey("sync image", func() {
   461  				ok, err := registry.CanSkipImage(repoName, "2.0", digest)
   462  				So(ok, ShouldBeFalse)
   463  				So(err, ShouldBeNil)
   464  
   465  				err = registry.CommitImage(imageReference, repoName, "2.0")
   466  				So(err, ShouldBeNil)
   467  			})
   468  		})
   469  	})
   470  }
   471  
   472  func TestConvertDockerToOCI(t *testing.T) {
   473  	Convey("test converting docker to oci functions", t, func() {
   474  		dir := t.TempDir()
   475  
   476  		srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log.NewLogger("debug", ""))
   477  
   478  		err := WriteImageToFileSystem(CreateDefaultImage(), "zot-test", "0.0.1", srcStorageCtlr)
   479  		So(err, ShouldBeNil)
   480  
   481  		imageRef, err := layout.NewReference(path.Join(dir, "zot-test"), "0.0.1")
   482  		So(err, ShouldBeNil)
   483  
   484  		imageSource, err := imageRef.NewImageSource(context.Background(), &types.SystemContext{})
   485  		So(err, ShouldBeNil)
   486  
   487  		defer imageSource.Close()
   488  
   489  		Convey("trigger Unmarshal manifest error", func() {
   490  			_, err = convertDockerManifestToOCI(imageSource, []byte{})
   491  			So(err, ShouldNotBeNil)
   492  		})
   493  
   494  		Convey("trigger getImageConfigContent() error", func() {
   495  			manifestBuf, _, err := imageSource.GetManifest(context.Background(), nil)
   496  			So(err, ShouldBeNil)
   497  
   498  			var manifest ispec.Manifest
   499  
   500  			err = json.Unmarshal(manifestBuf, &manifest)
   501  			So(err, ShouldBeNil)
   502  
   503  			err = os.Chmod(path.Join(dir, "zot-test", "blobs/sha256", manifest.Config.Digest.Encoded()), 0o000)
   504  			So(err, ShouldBeNil)
   505  
   506  			_, err = convertDockerManifestToOCI(imageSource, manifestBuf)
   507  			So(err, ShouldNotBeNil)
   508  		})
   509  
   510  		Convey("trigger Unmarshal config error", func() {
   511  			manifestBuf, _, err := imageSource.GetManifest(context.Background(), nil)
   512  			So(err, ShouldBeNil)
   513  
   514  			var manifest ispec.Manifest
   515  
   516  			err = json.Unmarshal(manifestBuf, &manifest)
   517  			So(err, ShouldBeNil)
   518  
   519  			err = os.WriteFile(path.Join(dir, "zot-test", "blobs/sha256", manifest.Config.Digest.Encoded()),
   520  				[]byte{}, storageConstants.DefaultFilePerms)
   521  			So(err, ShouldBeNil)
   522  
   523  			_, err = convertDockerManifestToOCI(imageSource, manifestBuf)
   524  			So(err, ShouldNotBeNil)
   525  		})
   526  
   527  		Convey("trigger convertDockerLayersToOCI error", func() {
   528  			manifestBuf, _, err := imageSource.GetManifest(context.Background(), nil)
   529  			So(err, ShouldBeNil)
   530  
   531  			var manifest ispec.Manifest
   532  
   533  			err = json.Unmarshal(manifestBuf, &manifest)
   534  			So(err, ShouldBeNil)
   535  
   536  			manifestDigest := godigest.FromBytes(manifestBuf)
   537  
   538  			manifest.Layers[0].MediaType = "unknown"
   539  
   540  			newManifest, err := json.Marshal(manifest)
   541  			So(err, ShouldBeNil)
   542  
   543  			err = os.WriteFile(path.Join(dir, "zot-test", "blobs/sha256", manifestDigest.Encoded()),
   544  				newManifest, storageConstants.DefaultFilePerms)
   545  			So(err, ShouldBeNil)
   546  
   547  			_, err = convertDockerManifestToOCI(imageSource, manifestBuf)
   548  			So(err, ShouldNotBeNil)
   549  		})
   550  
   551  		Convey("trigger convertDockerIndexToOCI error", func() {
   552  			manifestBuf, _, err := imageSource.GetManifest(context.Background(), nil)
   553  			So(err, ShouldBeNil)
   554  
   555  			_, err = convertDockerIndexToOCI(imageSource, manifestBuf)
   556  			So(err, ShouldNotBeNil)
   557  
   558  			// make zot-test image an index image
   559  
   560  			var manifest ispec.Manifest
   561  
   562  			err = json.Unmarshal(manifestBuf, &manifest)
   563  			So(err, ShouldBeNil)
   564  
   565  			dockerNewManifest := ispec.Manifest{
   566  				MediaType: dockerManifest.DockerV2Schema2MediaType,
   567  				Config:    manifest.Config,
   568  				Layers:    manifest.Layers,
   569  			}
   570  
   571  			dockerNewManifestBuf, err := json.Marshal(dockerNewManifest)
   572  			So(err, ShouldBeNil)
   573  
   574  			dockerManifestDigest := godigest.FromBytes(manifestBuf)
   575  
   576  			err = os.WriteFile(path.Join(dir, "zot-test", "blobs/sha256", dockerManifestDigest.Encoded()),
   577  				dockerNewManifestBuf, storageConstants.DefaultFilePerms)
   578  			So(err, ShouldBeNil)
   579  
   580  			var index ispec.Index
   581  
   582  			index.Manifests = append(index.Manifests, ispec.Descriptor{
   583  				Digest:    dockerManifestDigest,
   584  				Size:      int64(len(dockerNewManifestBuf)),
   585  				MediaType: dockerManifest.DockerV2Schema2MediaType,
   586  			})
   587  
   588  			index.MediaType = dockerManifest.DockerV2ListMediaType
   589  
   590  			dockerIndexBuf, err := json.Marshal(index)
   591  			So(err, ShouldBeNil)
   592  
   593  			dockerIndexDigest := godigest.FromBytes(dockerIndexBuf)
   594  
   595  			err = os.WriteFile(path.Join(dir, "zot-test", "blobs/sha256", dockerIndexDigest.Encoded()),
   596  				dockerIndexBuf, storageConstants.DefaultFilePerms)
   597  			So(err, ShouldBeNil)
   598  
   599  			// write index.json
   600  
   601  			var indexJSON ispec.Index
   602  
   603  			indexJSONBuf, err := os.ReadFile(path.Join(dir, "zot-test", "index.json"))
   604  			So(err, ShouldBeNil)
   605  
   606  			err = json.Unmarshal(indexJSONBuf, &indexJSON)
   607  			So(err, ShouldBeNil)
   608  
   609  			indexJSON.Manifests = append(indexJSON.Manifests, ispec.Descriptor{
   610  				Digest:    dockerIndexDigest,
   611  				Size:      int64(len(dockerIndexBuf)),
   612  				MediaType: ispec.MediaTypeImageIndex,
   613  				Annotations: map[string]string{
   614  					ispec.AnnotationRefName: "0.0.2",
   615  				},
   616  			})
   617  
   618  			indexJSONBuf, err = json.Marshal(indexJSON)
   619  			So(err, ShouldBeNil)
   620  
   621  			err = os.WriteFile(path.Join(dir, "zot-test", "index.json"), indexJSONBuf, storageConstants.DefaultFilePerms)
   622  			So(err, ShouldBeNil)
   623  
   624  			imageRef, err := layout.NewReference(path.Join(dir, "zot-test"), "0.0.2")
   625  			So(err, ShouldBeNil)
   626  
   627  			imageSource, err := imageRef.NewImageSource(context.Background(), &types.SystemContext{})
   628  			So(err, ShouldBeNil)
   629  
   630  			_, err = convertDockerIndexToOCI(imageSource, dockerIndexBuf)
   631  			So(err, ShouldNotBeNil)
   632  
   633  			err = os.Chmod(path.Join(dir, "zot-test", "blobs/sha256", dockerManifestDigest.Encoded()), 0o000)
   634  			So(err, ShouldBeNil)
   635  
   636  			_, err = convertDockerIndexToOCI(imageSource, dockerIndexBuf)
   637  			So(err, ShouldNotBeNil)
   638  		})
   639  	})
   640  }
   641  
   642  func TestConvertDockerLayersToOCI(t *testing.T) {
   643  	Convey("test converting docker to oci functions", t, func() {
   644  		dockerLayers := []ispec.Descriptor{
   645  			{
   646  				MediaType: dockerManifest.DockerV2Schema2ForeignLayerMediaType,
   647  			},
   648  			{
   649  				MediaType: dockerManifest.DockerV2Schema2ForeignLayerMediaTypeGzip,
   650  			},
   651  			{
   652  				MediaType: dockerManifest.DockerV2SchemaLayerMediaTypeUncompressed,
   653  			},
   654  			{
   655  				MediaType: dockerManifest.DockerV2Schema2LayerMediaType,
   656  			},
   657  		}
   658  
   659  		err := convertDockerLayersToOCI(dockerLayers)
   660  		So(err, ShouldBeNil)
   661  
   662  		So(dockerLayers[0].MediaType, ShouldEqual, ispec.MediaTypeImageLayerNonDistributable)     //nolint: staticcheck
   663  		So(dockerLayers[1].MediaType, ShouldEqual, ispec.MediaTypeImageLayerNonDistributableGzip) //nolint: staticcheck
   664  		So(dockerLayers[2].MediaType, ShouldEqual, ispec.MediaTypeImageLayer)
   665  		So(dockerLayers[3].MediaType, ShouldEqual, ispec.MediaTypeImageLayerGzip)
   666  	})
   667  }