GCS storage support (#3798)

feat(storage): add a GCS driver

test(storage): add unit tests for GCS driver

test(storage): add missing unit tests for GCS driver & resolve lint issues

fix: configuration validation for GCS Storage

test(storage): resolve panic by test due to setupGCS ignoring returned error

test(storage): add dummy gcs credentials

test: add darwin support for macos to run tests

ci: update workflows to pin gcs emulator version

lint: resolve long line lengths & formatting issues

test: move error for gcs mock earlier with an error

test: stop test using local google credentials and use mock instead

test: add missing dummy creds

test(storage): use storage-testbench for GCS, isolate GCS tests, fix driver Delete

- Switch GCS emulator from fake-gcs-server to storage-testbench in CI.
  Run the GCS emulator only in the privileged-test job; remove it from
  minimal and extended test jobs.

- Consolidate GCS tests under pkg/storage/gcs (needprivileges,linux).
  Add TestMain with HTTPS proxy and /etc/hosts so tests talk to
  storage-testbench; move GCS-specific cases from storage_test.go and
  scrub_test.go into gcs_test.go. Run GCS tests via a second privileged-test
  invocation and collect coverage in coverage-needprivileges-gcs.txt.

- Make GCS driver Delete idempotent and normalize errors. Treat
  PathNotFoundError from Delete as success so that deleting an already-gone
  path (e.g. after GC under eventual consistency) does not fail. Add
  formatErr to map 404/not found to PathNotFoundError and use it for all
  driver methods so callers get consistent storage driver errors.

- Drop GCS branches and helpers from storage_test.go and scrub_test.go so
  non-privileged tests only use local/S3; GCS is tested only in
  pkg/storage/gcs with storage-testbench.

- Set GCSMOCK_ENDPOINT without /storage/v1/, as the rest of the URL is set in tests.

- Show errors in case of failure to create bucket.

- Consolidate StorageDriverMock structs inside the pkg/test/mocks package.

Signed-off-by: Andrei Aaron <andreifdaaron@gmail.com>
Co-authored-by: Steven Marks <steve.marks@qomodo.io>
This commit is contained in:
Andrei Aaron
2026-02-19 09:41:21 +02:00
committed by GitHub
parent 5b2312d538
commit 5e57656bff
19 changed files with 4634 additions and 401 deletions
+1
View File
@@ -24,5 +24,6 @@ const (
DefaultGCDelay = 1 * time.Hour
DefaultGCInterval = 1 * time.Hour
S3StorageDriverName = "s3"
GCSStorageDriverName = "gcs"
LocalStorageDriverName = "local"
)
+209
View File
@@ -0,0 +1,209 @@
package gcs
import (
"context"
"errors"
"io"
"strings"
// Add gcs support.
storagedriver "github.com/distribution/distribution/v3/registry/storage/driver"
_ "github.com/distribution/distribution/v3/registry/storage/driver/gcs"
storageConstants "zotregistry.dev/zot/v2/pkg/storage/constants"
)
type Driver struct {
store storagedriver.StorageDriver
}
func New(storeDriver storagedriver.StorageDriver) *Driver {
return &Driver{store: storeDriver}
}
func (driver *Driver) Name() string {
return storageConstants.GCSStorageDriverName
}
func (driver *Driver) EnsureDir(path string) error {
return nil
}
func (driver *Driver) DirExists(path string) bool {
if fi, err := driver.Stat(path); err == nil && fi.IsDir() {
return true
}
return false
}
func (driver *Driver) Reader(path string, offset int64) (io.ReadCloser, error) {
reader, err := driver.store.Reader(context.Background(), path, offset)
if err != nil {
return nil, driver.formatErr(err, path)
}
return reader, nil
}
func (driver *Driver) ReadFile(path string) ([]byte, error) {
content, err := driver.store.GetContent(context.Background(), path)
if err != nil {
return nil, driver.formatErr(err, path)
}
return content, nil
}
func (driver *Driver) Delete(path string) error {
err := driver.store.Delete(context.Background(), path)
if err == nil {
return nil
}
// Format the error first to convert GCS-specific 404 errors to PathNotFoundError
formattedErr := driver.formatErr(err, path)
// Check if the formatted error is PathNotFoundError
var pathNotFoundErr storagedriver.PathNotFoundError
if errors.As(formattedErr, &pathNotFoundErr) {
// For directory deletion, if the path doesn't exist, treat it as success (idempotent delete)
// In GCS, directories are just prefixes, so if all objects are deleted,
// the directory may already be gone (especially with eventual consistency in storage-testbench)
// This makes Delete idempotent: deleting a non-existent path is a no-op
return nil
}
return formattedErr
}
func (driver *Driver) Stat(path string) (storagedriver.FileInfo, error) {
fileInfo, err := driver.store.Stat(context.Background(), path)
if err != nil {
return nil, driver.formatErr(err, path)
}
return fileInfo, nil
}
func (driver *Driver) Writer(filepath string, append bool) (storagedriver.FileWriter, error) { //nolint:predeclared
writer, err := driver.store.Writer(context.Background(), filepath, append)
if err != nil {
return nil, driver.formatErr(err, filepath)
}
return writer, nil
}
func (driver *Driver) WriteFile(filepath string, content []byte) (int, error) {
var n int
stwr, err := driver.store.Writer(context.Background(), filepath, false)
if err != nil {
return -1, driver.formatErr(err, filepath)
}
defer stwr.Close()
if n, err = stwr.Write(content); err != nil {
return -1, driver.formatErr(err, filepath)
}
if err := stwr.Commit(context.Background()); err != nil {
return -1, driver.formatErr(err, filepath)
}
return n, nil
}
func (driver *Driver) Walk(path string, f storagedriver.WalkFn) error {
return driver.formatErr(driver.store.Walk(context.Background(), path, f), path)
}
func (driver *Driver) List(fullpath string) ([]string, error) {
list, err := driver.store.List(context.Background(), fullpath)
if err != nil {
return nil, driver.formatErr(err, fullpath)
}
return list, nil
}
func (driver *Driver) Move(sourcePath string, destPath string) error {
return driver.formatErr(driver.store.Move(context.Background(), sourcePath, destPath), sourcePath)
}
func (driver *Driver) SameFile(path1, path2 string) bool {
fi1, _ := driver.store.Stat(context.Background(), path1)
fi2, _ := driver.store.Stat(context.Background(), path2)
if fi1 != nil && fi2 != nil {
if fi1.IsDir() == fi2.IsDir() &&
fi1.ModTime() == fi2.ModTime() &&
fi1.Path() == fi2.Path() &&
fi1.Size() == fi2.Size() {
return true
}
}
return false
}
// Link puts an empty file that will act like a link between the original file and deduped one.
// Because gcs doesn't support symlinks, wherever the storage will encounter an empty file, it will get the original one
// from cache.
func (driver *Driver) Link(src, dest string) error {
return driver.formatErr(driver.store.PutContent(context.Background(), dest, []byte{}), dest)
}
// formatErr converts GCS-specific 404/not found errors to PathNotFoundError.
func (driver *Driver) formatErr(err error, path string) error {
switch actual := err.(type) { //nolint: errorlint
case nil:
return nil
case storagedriver.PathNotFoundError:
actual.DriverName = driver.Name()
if actual.Path == "" && path != "" {
actual.Path = path
}
return actual
case storagedriver.InvalidPathError:
actual.DriverName = driver.Name()
return actual
case storagedriver.InvalidOffsetError:
actual.DriverName = driver.Name()
return actual
default:
// Check for GCS-specific 404/not found errors by unwrapping the error chain
errToCheck := err
for errToCheck != nil {
errStr := errToCheck.Error()
isNotFound := strings.Contains(errStr, "object doesn't exist") ||
strings.Contains(errStr, "Error 404") ||
strings.Contains(errStr, "does not exist")
if isNotFound {
return storagedriver.PathNotFoundError{
DriverName: driver.Name(),
Path: path,
}
}
if unwrappable, ok := errToCheck.(interface{ Unwrap() error }); ok {
errToCheck = unwrappable.Unwrap()
} else {
break
}
}
storageError := storagedriver.Error{
DriverName: driver.Name(),
Detail: err,
}
return storageError
}
}
+364
View File
@@ -0,0 +1,364 @@
package gcs_test
import (
"context"
"errors"
"fmt"
"io"
"strings"
"testing"
"time"
"github.com/distribution/distribution/v3/registry/storage/driver"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.dev/zot/v2/pkg/extensions/monitoring"
zlog "zotregistry.dev/zot/v2/pkg/log"
"zotregistry.dev/zot/v2/pkg/storage/gcs"
"zotregistry.dev/zot/v2/pkg/test/mocks"
)
var errTest = errors.New("error")
type fileInfoMock struct {
isDir bool
size int64
modTime time.Time
path string
}
func (f *fileInfoMock) Path() string { return f.path }
func (f *fileInfoMock) Size() int64 { return f.size }
func (f *fileInfoMock) ModTime() time.Time { return f.modTime }
func (f *fileInfoMock) IsDir() bool { return f.isDir }
func TestDriver(t *testing.T) {
Convey("GCS Driver", t, func() {
storeMock := &mocks.StorageDriverMock{}
gcsDriver := gcs.New(storeMock)
Convey("Name", func() {
So(gcsDriver.Name(), ShouldEqual, "gcs")
})
Convey("EnsureDir", func() {
err := gcsDriver.EnsureDir("/test")
So(err, ShouldBeNil)
})
Convey("DirExists", func() {
Convey("True", func() {
storeMock.StatFn = func(ctx context.Context, path string) (driver.FileInfo, error) {
return &mocks.FileInfoMock{
IsDirFn: func() bool { return true },
}, nil
}
So(gcsDriver.DirExists("/test"), ShouldBeTrue)
})
Convey("False - Not a dir", func() {
storeMock.StatFn = func(ctx context.Context, path string) (driver.FileInfo, error) {
return &mocks.FileInfoMock{
IsDirFn: func() bool { return false },
}, nil
}
So(gcsDriver.DirExists("/test"), ShouldBeFalse)
})
Convey("False - Error", func() {
storeMock.StatFn = func(ctx context.Context, path string) (driver.FileInfo, error) {
return nil, errTest
}
So(gcsDriver.DirExists("/test"), ShouldBeFalse)
})
})
Convey("Reader", func() {
Convey("Success", func() {
storeMock.ReaderFn = func(ctx context.Context, path string, offset int64) (io.ReadCloser, error) {
return io.NopCloser(strings.NewReader("")), nil
}
r, err := gcsDriver.Reader("/test", 0)
So(err, ShouldBeNil)
So(r, ShouldNotBeNil)
})
Convey("InvalidOffsetError", func() {
storeMock.ReaderFn = func(ctx context.Context, path string, offset int64) (io.ReadCloser, error) {
return nil, driver.InvalidOffsetError{Path: path, Offset: offset}
}
_, err := gcsDriver.Reader("/test", 100)
So(err, ShouldNotBeNil)
var invalidOffset driver.InvalidOffsetError
So(errors.As(err, &invalidOffset), ShouldBeTrue)
So(invalidOffset.DriverName, ShouldEqual, "gcs")
})
})
Convey("ReadFile", func() {
Convey("Success", func() {
storeMock.GetContentFn = func(ctx context.Context, path string) ([]byte, error) {
return []byte("content"), nil
}
content, err := gcsDriver.ReadFile("/test")
So(err, ShouldBeNil)
So(string(content), ShouldEqual, "content")
})
Convey("PathNotFoundError with empty Path gets path set", func() {
storeMock.GetContentFn = func(ctx context.Context, path string) ([]byte, error) {
return nil, driver.PathNotFoundError{Path: ""} // Path empty so driver sets it
}
_, err := gcsDriver.ReadFile("/requested/path")
So(err, ShouldNotBeNil)
var pathErr driver.PathNotFoundError
So(errors.As(err, &pathErr), ShouldBeTrue)
So(pathErr.DriverName, ShouldEqual, "gcs")
So(pathErr.Path, ShouldEqual, "/requested/path")
})
Convey("GCS not-found string becomes PathNotFoundError", func() {
for _, msg := range []string{"object doesn't exist", "Error 404", "does not exist"} {
errMsg := msg
storeMock.GetContentFn = func(ctx context.Context, path string) ([]byte, error) {
//nolint:err113 // test needs variable not-found message
return nil, fmt.Errorf("%s", errMsg)
}
_, err := gcsDriver.ReadFile("/key")
So(err, ShouldNotBeNil)
var pathErr driver.PathNotFoundError
So(errors.As(err, &pathErr), ShouldBeTrue)
So(pathErr.Path, ShouldEqual, "/key")
}
})
Convey("Generic error becomes storagedriver.Error", func() {
storeMock.GetContentFn = func(ctx context.Context, path string) ([]byte, error) {
return nil, errTest
}
_, err := gcsDriver.ReadFile("/test")
So(err, ShouldNotBeNil)
var storageErr driver.Error
So(errors.As(err, &storageErr), ShouldBeTrue)
So(storageErr.DriverName, ShouldEqual, "gcs")
So(storageErr.Detail, ShouldEqual, errTest)
})
})
Convey("Delete", func() {
Convey("Success", func() {
storeMock.DeleteFn = func(ctx context.Context, path string) error {
return nil
}
err := gcsDriver.Delete("/test")
So(err, ShouldBeNil)
})
Convey("PathNotFoundError is idempotent (return nil)", func() {
storeMock.DeleteFn = func(ctx context.Context, path string) error {
return driver.PathNotFoundError{Path: path}
}
err := gcsDriver.Delete("/nonexistent")
So(err, ShouldBeNil)
})
Convey("Other error is returned", func() {
storeMock.DeleteFn = func(ctx context.Context, path string) error {
return errTest
}
err := gcsDriver.Delete("/test")
So(err, ShouldNotBeNil)
So(errors.Is(err, errTest), ShouldBeFalse) // wrapped in storagedriver.Error
})
})
Convey("Stat", func() {
Convey("Success", func() {
storeMock.StatFn = func(ctx context.Context, path string) (driver.FileInfo, error) {
return &mocks.FileInfoMock{}, nil
}
fi, err := gcsDriver.Stat("/test")
So(err, ShouldBeNil)
So(fi, ShouldNotBeNil)
})
Convey("InvalidPathError", func() {
storeMock.StatFn = func(ctx context.Context, path string) (driver.FileInfo, error) {
return nil, driver.InvalidPathError{Path: path}
}
_, err := gcsDriver.Stat("/bad")
So(err, ShouldNotBeNil)
var invalidPath driver.InvalidPathError
So(errors.As(err, &invalidPath), ShouldBeTrue)
So(invalidPath.DriverName, ShouldEqual, "gcs")
})
})
Convey("Writer", func() {
Convey("Success", func() {
storeMock.WriterFn = func(ctx context.Context, path string, isAppend bool) (driver.FileWriter, error) {
return &mocks.FileWriterMock{}, nil
}
w, err := gcsDriver.Writer("/test", false)
So(err, ShouldBeNil)
So(w, ShouldNotBeNil)
})
Convey("Error", func() {
storeMock.WriterFn = func(ctx context.Context, path string, isAppend bool) (driver.FileWriter, error) {
return nil, errTest
}
_, err := gcsDriver.Writer("/test", false)
So(err, ShouldNotBeNil)
})
})
Convey("WriteFile", func() {
Convey("Success", func() {
storeMock.WriterFn = func(ctx context.Context, path string, isAppend bool) (driver.FileWriter, error) {
return &mocks.FileWriterMock{
WriteFn: func(p []byte) (int, error) {
return len(p), nil
},
CommitFn: func() error {
return nil
},
CloseFn: func() error {
return nil
},
}, nil
}
n, err := gcsDriver.WriteFile("/test", []byte("content"))
So(err, ShouldBeNil)
So(n, ShouldEqual, 7)
})
Convey("Writer Error", func() {
storeMock.WriterFn = func(ctx context.Context, path string, isAppend bool) (driver.FileWriter, error) {
return nil, errTest
}
_, err := gcsDriver.WriteFile("/test", []byte("content"))
So(err, ShouldNotBeNil)
})
Convey("Write Error", func() {
storeMock.WriterFn = func(ctx context.Context, path string, isAppend bool) (driver.FileWriter, error) {
return &mocks.FileWriterMock{
WriteFn: func(p []byte) (int, error) {
return 0, errTest
},
CloseFn: func() error { return nil },
}, nil
}
_, err := gcsDriver.WriteFile("/test", []byte("content"))
So(err, ShouldNotBeNil)
})
Convey("Commit Error", func() {
storeMock.WriterFn = func(ctx context.Context, path string, isAppend bool) (driver.FileWriter, error) {
return &mocks.FileWriterMock{
WriteFn: func(p []byte) (int, error) {
return len(p), nil
},
CommitFn: func() error {
return errTest
},
CloseFn: func() error { return nil },
}, nil
}
_, err := gcsDriver.WriteFile("/test", []byte("content"))
So(err, ShouldNotBeNil)
})
})
Convey("Walk", func() {
storeMock.WalkFn = func(ctx context.Context, path string, f driver.WalkFn, _ ...func(*driver.WalkOptions)) error {
return nil
}
err := gcsDriver.Walk("/test", nil)
So(err, ShouldBeNil)
})
Convey("List", func() {
Convey("Success", func() {
storeMock.ListFn = func(ctx context.Context, path string) ([]string, error) {
return []string{"a"}, nil
}
l, err := gcsDriver.List("/test")
So(err, ShouldBeNil)
So(l, ShouldResemble, []string{"a"})
})
Convey("Error", func() {
storeMock.ListFn = func(ctx context.Context, path string) ([]string, error) {
return nil, errTest
}
_, err := gcsDriver.List("/test")
So(err, ShouldNotBeNil)
})
})
Convey("Move", func() {
storeMock.MoveFn = func(ctx context.Context, sourcePath, destPath string) error {
return nil
}
err := gcsDriver.Move("/src", "/dst")
So(err, ShouldBeNil)
})
Convey("SameFile", func() {
Convey("True", func() {
now := time.Now()
storeMock.StatFn = func(ctx context.Context, path string) (driver.FileInfo, error) {
return &fileInfoMock{
isDir: false,
size: 10,
modTime: now,
path: "/canonical/path",
}, nil
}
So(gcsDriver.SameFile("/path1", "/path2"), ShouldBeTrue)
})
Convey("False - Different ModTime", func() {
storeMock.StatFn = func(ctx context.Context, path string) (driver.FileInfo, error) {
modTime := time.Now()
if path == "/path2" {
modTime = modTime.Add(1 * time.Hour)
}
return &fileInfoMock{
isDir: false,
size: 10,
modTime: modTime,
path: path,
}, nil
}
So(gcsDriver.SameFile("/path1", "/path2"), ShouldBeFalse)
})
})
Convey("Link", func() {
storeMock.PutContentFn = func(ctx context.Context, path string, content []byte) error {
return nil
}
err := gcsDriver.Link("/src", "/dst")
So(err, ShouldBeNil)
})
})
}
func TestNewImageStore(t *testing.T) {
Convey("NewImageStore", t, func() {
storeMock := &mocks.StorageDriverMock{}
log := zlog.NewTestLogger()
metrics := monitoring.NewMetricsServer(false, log)
imgStore := gcs.NewImageStore("/tmp", "/tmp", true, true, log, metrics, nil, storeMock, nil, nil, nil)
So(imgStore, ShouldNotBeNil)
})
}
+38
View File
@@ -0,0 +1,38 @@
package gcs
import (
// Add gcs support.
"github.com/distribution/distribution/v3/registry/storage/driver"
// Load gcs driver.
_ "github.com/distribution/distribution/v3/registry/storage/driver/gcs"
"zotregistry.dev/zot/v2/pkg/compat"
"zotregistry.dev/zot/v2/pkg/extensions/events"
"zotregistry.dev/zot/v2/pkg/extensions/monitoring"
zlog "zotregistry.dev/zot/v2/pkg/log"
common "zotregistry.dev/zot/v2/pkg/storage/common"
"zotregistry.dev/zot/v2/pkg/storage/imagestore"
storageTypes "zotregistry.dev/zot/v2/pkg/storage/types"
)
// NewImageStore returns a new image store backed by cloud storages.
// see https://github.com/docker/docker.github.io/tree/master/registry/storage-drivers
// Use the last argument to properly set a cache database, or it will default to boltDB local storage.
func NewImageStore(rootDir string, cacheDir string, dedupe, commit bool, log zlog.Logger,
metrics monitoring.MetricServer, linter common.Lint, store driver.StorageDriver,
cacheDriver storageTypes.Cache, compat []compat.MediaCompatibility, recorder events.Recorder,
) storageTypes.ImageStore {
return imagestore.NewImageStore(
rootDir,
cacheDir,
dedupe,
commit,
log,
metrics,
linter,
New(store),
cacheDriver,
compat,
recorder,
)
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
//go:build needprivileges
//go:build needprivileges && linux
package local_test
+116 -304
View File
File diff suppressed because it is too large Load Diff
+21 -7
View File
@@ -18,6 +18,7 @@ import (
"zotregistry.dev/zot/v2/pkg/log"
common "zotregistry.dev/zot/v2/pkg/storage/common"
"zotregistry.dev/zot/v2/pkg/storage/constants"
"zotregistry.dev/zot/v2/pkg/storage/gcs"
"zotregistry.dev/zot/v2/pkg/storage/local"
"zotregistry.dev/zot/v2/pkg/storage/s3"
storageTypes "zotregistry.dev/zot/v2/pkg/storage/types"
@@ -63,7 +64,7 @@ func New(config *config.Config, linter common.Lint, metrics monitoring.MetricSer
)
} else {
storeName := fmt.Sprintf("%v", config.Storage.StorageDriver["name"])
if storeName != constants.S3StorageDriverName {
if storeName != constants.S3StorageDriverName && storeName != constants.GCSStorageDriverName {
log.Error().Err(zerr.ErrBadConfig).Str("storageDriver", storeName).
Msg("unsupported storage driver")
@@ -92,8 +93,15 @@ func New(config *config.Config, linter common.Lint, metrics monitoring.MetricSer
// false positive lint - linter does not implement Lint method
//nolint: typecheck,contextcheck
defaultStore = s3.NewImageStore(rootDir, config.Storage.RootDirectory,
config.Storage.Dedupe, config.Storage.Commit, log, metrics, linter, store, cacheDriver, config.HTTP.Compat, recorder)
if storeName == constants.S3StorageDriverName {
defaultStore = s3.NewImageStore(rootDir, config.Storage.RootDirectory,
config.Storage.Dedupe, config.Storage.Commit, log, metrics, linter, store, cacheDriver,
config.HTTP.Compat, recorder)
} else {
defaultStore = gcs.NewImageStore(rootDir, config.Storage.RootDirectory,
config.Storage.Dedupe, config.Storage.Commit, log, metrics, linter, store, cacheDriver,
config.HTTP.Compat, recorder)
}
}
storeController.DefaultStore = defaultStore
@@ -178,7 +186,7 @@ func getSubStore(cfg *config.Config, subPaths map[string]config.StorageConfig,
}
} else {
storeName := fmt.Sprintf("%v", storageConfig.StorageDriver["name"])
if storeName != constants.S3StorageDriverName {
if storeName != constants.S3StorageDriverName && storeName != constants.GCSStorageDriverName {
log.Error().Err(zerr.ErrBadConfig).Str("storageDriver", storeName).
Msg("unsupported storage driver")
@@ -210,9 +218,15 @@ func getSubStore(cfg *config.Config, subPaths map[string]config.StorageConfig,
// false positive lint - linter does not implement Lint method
//nolint: typecheck
subImageStore[route] = s3.NewImageStore(rootDir, storageConfig.RootDirectory,
storageConfig.Dedupe, storageConfig.Commit, log, metrics, linter, store, cacheDriver, cfg.HTTP.Compat, recorder,
)
if storeName == constants.S3StorageDriverName {
subImageStore[route] = s3.NewImageStore(rootDir, storageConfig.RootDirectory,
storageConfig.Dedupe, storageConfig.Commit, log, metrics, linter, store, cacheDriver, cfg.HTTP.Compat, recorder,
)
} else {
subImageStore[route] = gcs.NewImageStore(rootDir, storageConfig.RootDirectory,
storageConfig.Dedupe, storageConfig.Commit, log, metrics, linter, store, cacheDriver, cfg.HTTP.Compat, recorder,
)
}
}
}
+53 -27
View File
@@ -59,7 +59,9 @@ var DeleteReferrers = config.ImageRetention{ //nolint: gochecknoglobals
}
func cleanupStorage(store storageTypes.Driver, name string) {
_ = store.Delete(name)
if store != nil {
_ = store.Delete(name)
}
}
type createObjectStoreOpts struct {
@@ -207,7 +209,8 @@ func TestGetAllDedupeReposCandidates(t *testing.T) {
defer DumpKeys(t, opts.miniRedisAddr)
}
if testcase.storageType == storageConstants.S3StorageDriverName {
switch testcase.storageType {
case storageConstants.S3StorageDriverName:
tskip.SkipS3(t)
uuid, err := guuid.NewV4()
@@ -219,9 +222,10 @@ func TestGetAllDedupeReposCandidates(t *testing.T) {
opts.rootDir = testDir
var store storageTypes.Driver
store, imgStore, _, _ = createObjectsStore(opts)
defer cleanupStorage(store, testDir)
} else {
default:
_, imgStore, _, _ = createObjectsStore(opts)
}
@@ -279,7 +283,8 @@ func TestStorageAPIs(t *testing.T) {
defer DumpKeys(t, opts.miniRedisAddr)
}
if testcase.storageType == storageConstants.S3StorageDriverName {
switch testcase.storageType {
case storageConstants.S3StorageDriverName:
tskip.SkipS3(t)
uuid, err := guuid.NewV4()
@@ -291,9 +296,10 @@ func TestStorageAPIs(t *testing.T) {
opts.rootDir = testDir
var store storageTypes.Driver
store, imgStore, _, _ = createObjectsStore(opts)
defer cleanupStorage(store, testDir)
} else {
default:
_, imgStore, _, _ = createObjectsStore(opts)
}
@@ -1028,7 +1034,8 @@ func TestMandatoryAnnotations(t *testing.T) {
defer DumpKeys(t, opts.miniRedisAddr)
}
if testcase.storageType == storageConstants.S3StorageDriverName {
switch testcase.storageType {
case storageConstants.S3StorageDriverName:
tskip.SkipS3(t)
uuid, err := guuid.NewV4()
@@ -1040,6 +1047,7 @@ func TestMandatoryAnnotations(t *testing.T) {
opts.rootDir = testDir
var cacheDriver storageTypes.Cache
store, _, cacheDriver, _ = createObjectsStore(opts)
imgStore = imagestore.NewImageStore(testDir, cacheDir, false, false, log, metrics,
@@ -1050,8 +1058,9 @@ func TestMandatoryAnnotations(t *testing.T) {
}, store, cacheDriver, nil, nil)
defer cleanupStorage(store, testDir)
} else {
default:
var cacheDriver storageTypes.Cache
store, _, cacheDriver, _ = createObjectsStore(opts)
imgStore = imagestore.NewImageStore(cacheDir, cacheDir, true, true, log, metrics,
@@ -1115,8 +1124,10 @@ func TestMandatoryAnnotations(t *testing.T) {
}, store, nil, nil, nil)
} else {
var cacheDriver storageTypes.Cache
store, _, cacheDriver, _ = createObjectsStore(opts)
store, _, cacheDriver, err := createObjectsStore(opts)
if err != nil {
t.Fatal(err)
}
imgStore = imagestore.NewImageStore(cacheDir, cacheDir, true, true, log, metrics,
&mocks.MockedLint{
LintFn: func(repo string, manifestDigest godigest.Digest, imageStore storageTypes.ImageStore) (bool, error) {
@@ -1223,7 +1234,8 @@ func TestDeleteBlobsInUse(t *testing.T) {
defer DumpKeys(t, opts.miniRedisAddr)
}
if testcase.storageType == storageConstants.S3StorageDriverName {
switch testcase.storageType {
case storageConstants.S3StorageDriverName:
tskip.SkipS3(t)
uuid, err := guuid.NewV4()
@@ -1238,7 +1250,7 @@ func TestDeleteBlobsInUse(t *testing.T) {
store, imgStore, _, _ = createObjectsStore(opts)
defer cleanupStorage(store, testDir)
} else {
default:
_, imgStore, _, _ = createObjectsStore(opts)
}
@@ -1532,7 +1544,8 @@ func TestReuploadCorruptedBlob(t *testing.T) {
defer DumpKeys(t, opts.miniRedisAddr)
}
if testcase.storageType == storageConstants.S3StorageDriverName {
switch testcase.storageType {
case storageConstants.S3StorageDriverName:
tskip.SkipS3(t)
uuid, err := guuid.NewV4()
@@ -1545,7 +1558,7 @@ func TestReuploadCorruptedBlob(t *testing.T) {
driver, imgStore, _, _ = createObjectsStore(opts)
defer cleanupStorage(driver, testDir)
} else {
default:
driver, imgStore, _, _ = createObjectsStore(opts)
}
@@ -1666,7 +1679,8 @@ func TestStorageHandler(t *testing.T) {
defer DumpKeys(t, opts.miniRedisAddr)
}
if testcase.storageType == storageConstants.S3StorageDriverName {
switch testcase.storageType {
case storageConstants.S3StorageDriverName:
tskip.SkipS3(t)
var (
@@ -1695,7 +1709,7 @@ func TestStorageHandler(t *testing.T) {
thirdStorageDriver, thirdStore, _, _ = createObjectsStore(opts)
defer cleanupStorage(thirdStorageDriver, thirdRootDir)
} else {
default:
firstRootDir = t.TempDir()
opts.rootDir = firstRootDir
opts.cacheDir = firstRootDir
@@ -1784,7 +1798,8 @@ func TestGarbageCollectImageManifest(t *testing.T) {
Convey("Garbage collect with default/long delay", func() {
var imgStore storageTypes.ImageStore
if testcase.storageType == storageConstants.S3StorageDriverName {
switch testcase.storageType {
case storageConstants.S3StorageDriverName:
tskip.SkipS3(t)
uuid, err := guuid.NewV4()
@@ -1796,9 +1811,10 @@ func TestGarbageCollectImageManifest(t *testing.T) {
opts.rootDir = testDir
var store storageTypes.Driver
store, imgStore, _, _ = createObjectsStore(opts)
defer cleanupStorage(store, testDir)
} else {
default:
_, imgStore, _, _ = createObjectsStore(opts)
}
@@ -1945,7 +1961,8 @@ func TestGarbageCollectImageManifest(t *testing.T) {
gcDelay := 1 * time.Second
if testcase.storageType == storageConstants.S3StorageDriverName {
switch testcase.storageType {
case storageConstants.S3StorageDriverName:
tskip.SkipS3(t)
uuid, err := guuid.NewV4()
@@ -1957,9 +1974,10 @@ func TestGarbageCollectImageManifest(t *testing.T) {
opts.rootDir = testDir
var store storageTypes.Driver
store, imgStore, _, _ = createObjectsStore(opts)
defer cleanupStorage(store, testDir)
} else {
default:
_, imgStore, _, _ = createObjectsStore(opts)
}
@@ -2220,7 +2238,8 @@ func TestGarbageCollectImageManifest(t *testing.T) {
gcDelay := 3 * time.Second
if testcase.storageType == storageConstants.S3StorageDriverName {
switch testcase.storageType {
case storageConstants.S3StorageDriverName:
tskip.SkipS3(t)
uuid, err := guuid.NewV4()
@@ -2232,9 +2251,10 @@ func TestGarbageCollectImageManifest(t *testing.T) {
opts.rootDir = testDir
var store storageTypes.Driver
store, imgStore, _, _ = createObjectsStore(opts)
defer cleanupStorage(store, testDir)
} else {
default:
_, imgStore, _, _ = createObjectsStore(opts)
}
@@ -2467,7 +2487,8 @@ func TestGarbageCollectImageIndex(t *testing.T) {
Convey("Garbage collect with default/long delay", func() {
var imgStore storageTypes.ImageStore
if testcase.storageType == storageConstants.S3StorageDriverName {
switch testcase.storageType {
case storageConstants.S3StorageDriverName:
tskip.SkipS3(t)
uuid, err := guuid.NewV4()
@@ -2479,9 +2500,10 @@ func TestGarbageCollectImageIndex(t *testing.T) {
opts.rootDir = testDir
var store storageTypes.Driver
store, imgStore, _, _ = createObjectsStore(opts)
defer cleanupStorage(store, testDir)
} else {
default:
_, imgStore, _, _ = createObjectsStore(opts)
}
@@ -2586,7 +2608,8 @@ func TestGarbageCollectImageIndex(t *testing.T) {
gcDelay := 2 * time.Second
imageRetentionDelay := 2 * time.Second
if testcase.storageType == storageConstants.S3StorageDriverName {
switch testcase.storageType {
case storageConstants.S3StorageDriverName:
tskip.SkipS3(t)
uuid, err := guuid.NewV4()
@@ -2598,9 +2621,10 @@ func TestGarbageCollectImageIndex(t *testing.T) {
opts.rootDir = testDir
var store storageTypes.Driver
store, imgStore, _, _ = createObjectsStore(opts)
defer cleanupStorage(store, testDir)
} else {
default:
_, imgStore, _, _ = createObjectsStore(opts)
}
@@ -2876,7 +2900,8 @@ func TestGarbageCollectChainedImageIndexes(t *testing.T) {
defer DumpKeys(t, opts.miniRedisAddr)
}
if testcase.storageType == storageConstants.S3StorageDriverName {
switch testcase.storageType {
case storageConstants.S3StorageDriverName:
tskip.SkipS3(t)
uuid, err := guuid.NewV4()
@@ -2888,9 +2913,10 @@ func TestGarbageCollectChainedImageIndexes(t *testing.T) {
opts.rootDir = testDir
var store storageTypes.Driver
store, imgStore, _, _ = createObjectsStore(opts)
defer cleanupStorage(store, testDir)
} else {
default:
_, imgStore, _, _ = createObjectsStore(opts)
}