Files
zot/pkg/storage/cache/redis_test.go
Luca Muscariello 2402296e9a fix: migrate to Go module v2 for proper semantic versioning (#3462)
* fix: migrate to Go module v2 for proper semantic versioning

This change updates the module path from 'zotregistry.dev/zot' to
'zotregistry.dev/zot/v2' to comply with Go's semantic versioning rules.

According to Go's module versioning requirements, major version v2+
must include the major version in the module path. The current
module path 'zotregistry.dev/zot' only supports v0.x.x and v1.x.x
versions, making existing v2.x.x tags (like v2.1.8) unusable.

Changes:
- Updated go.mod module path to zotregistry.dev/zot/v2
- Updated all internal import paths across 280+ Go source files
- Updated configuration files (golangcilint.yaml, gqlgen.yml)
- Updated README.md Go reference badge

This fix enables proper use of existing v2.x.x Git tags and allows
external packages to import zot v2+ versions without compatibility
errors.

Resolves: Go module import compatibility for v2+ versions
Fixes: #3071
Signed-off-by: Luca Muscariello <muscariello@ieee.org>

* fix: regenerate GraphQL files with updated v2 import paths

The gqlgen tool needs to regenerate the GraphQL schema files after
the module path change to use the new v2 imports.

Signed-off-by: Luca Muscariello <muscariello@ieee.org>

---------

Signed-off-by: Luca Muscariello <muscariello@ieee.org>
2025-10-16 22:43:47 -07:00

713 lines
24 KiB
Go

package cache_test
import (
"errors"
"fmt"
"path"
"testing"
"time"
"github.com/alicebob/miniredis/v2"
"github.com/go-redis/redismock/v9"
"github.com/redis/go-redis/v9"
. "github.com/smartystreets/goconvey/convey"
zerr "zotregistry.dev/zot/v2/errors"
"zotregistry.dev/zot/v2/pkg/log"
"zotregistry.dev/zot/v2/pkg/storage"
"zotregistry.dev/zot/v2/pkg/storage/cache"
"zotregistry.dev/zot/v2/pkg/storage/constants"
test "zotregistry.dev/zot/v2/pkg/test/common"
)
var ErrTestError = errors.New("TestError")
func TestRedisCache(t *testing.T) {
miniRedis := miniredis.RunT(t)
Convey("Make a new cache", t, func() {
dir := t.TempDir()
log := log.NewTestLogger()
So(log, ShouldNotBeNil)
cacheDriver, err := storage.Create("redis", "failTypeAssertion", log)
So(cacheDriver, ShouldBeNil)
So(err, ShouldNotBeNil)
connOpts, _ := redis.ParseURL("redis://" + miniRedis.Addr())
client := redis.NewClient(connOpts)
cacheDriver, err = storage.Create("redis",
cache.RedisDriverParameters{client, dir, true, "zot"}, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
name := cacheDriver.Name()
So(name, ShouldEqual, "redis")
val, err := cacheDriver.GetBlob("key")
So(err, ShouldEqual, zerr.ErrCacheMiss)
So(val, ShouldBeEmpty)
exists := cacheDriver.HasBlob("key", path.Join(dir, "value"))
So(exists, ShouldBeFalse)
exists = cacheDriver.HasBlob("key", "value")
So(exists, ShouldBeFalse)
err = cacheDriver.PutBlob("key", path.Join(dir, "value"))
So(err, ShouldBeNil)
err = cacheDriver.PutBlob("key", "value")
So(err, ShouldNotBeNil)
exists = cacheDriver.HasBlob("key", path.Join(dir, "value"))
So(exists, ShouldBeTrue)
val, err = cacheDriver.GetBlob("key")
So(err, ShouldBeNil)
So(val, ShouldNotBeEmpty)
err = cacheDriver.DeleteBlob("bogusKey", "bogusValue")
So(err, ShouldEqual, zerr.ErrCacheMiss)
err = cacheDriver.DeleteBlob("key", "bogusValue")
So(err, ShouldBeNil)
// try to insert empty path
err = cacheDriver.PutBlob("key", "")
So(err, ShouldNotBeNil)
So(err, ShouldEqual, zerr.ErrEmptyValue)
connOpts, _ = redis.ParseURL("redis://" + miniRedis.Addr() + "/5")
client = redis.NewClient(connOpts)
cacheDriver, err = storage.Create("redis",
cache.RedisDriverParameters{client, t.TempDir(), false, "zot"}, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
err = cacheDriver.PutBlob("key1", "originalBlobPath")
So(err, ShouldBeNil)
err = cacheDriver.PutBlob("key1", "duplicateBlobPath")
So(err, ShouldBeNil)
val, err = cacheDriver.GetBlob("key1")
So(val, ShouldEqual, "originalBlobPath")
So(err, ShouldBeNil)
err = cacheDriver.DeleteBlob("key1", "duplicateBlobPath")
So(err, ShouldBeNil)
val, err = cacheDriver.GetBlob("key1")
So(val, ShouldEqual, "originalBlobPath")
So(err, ShouldBeNil)
err = cacheDriver.PutBlob("key1", "duplicateBlobPath")
So(err, ShouldBeNil)
err = cacheDriver.DeleteBlob("key1", "originalBlobPath")
So(err, ShouldBeNil)
val, err = cacheDriver.GetBlob("key1")
So(val, ShouldEqual, "duplicateBlobPath")
So(err, ShouldBeNil)
err = cacheDriver.DeleteBlob("key1", "duplicateBlobPath")
So(err, ShouldBeNil)
// should be empty
val, err = cacheDriver.GetBlob("key1")
So(err, ShouldNotBeNil)
So(val, ShouldBeEmpty)
// try to add three same values
err = cacheDriver.PutBlob("key2", "duplicate")
So(err, ShouldBeNil)
err = cacheDriver.PutBlob("key2", "duplicate")
So(err, ShouldBeNil)
err = cacheDriver.PutBlob("key2", "duplicate")
So(err, ShouldBeNil)
val, err = cacheDriver.GetBlob("key2")
So(val, ShouldEqual, "duplicate")
So(err, ShouldBeNil)
err = cacheDriver.DeleteBlob("key2", "duplicate")
So(err, ShouldBeNil)
// should be empty
val, err = cacheDriver.GetBlob("key2")
So(err, ShouldNotBeNil)
So(val, ShouldBeEmpty)
})
Convey("Test cache.GetAllBlos()", t, func() {
dir := t.TempDir()
log := log.NewTestLogger()
So(log, ShouldNotBeNil)
connOpts, _ := redis.ParseURL("redis://" + miniRedis.Addr())
client := redis.NewClient(connOpts)
cacheDriver, err := storage.Create("redis",
cache.RedisDriverParameters{client, dir, true, "zot"}, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
name := cacheDriver.Name()
So(name, ShouldEqual, "redis")
blobs, err := cacheDriver.GetAllBlobs("digest")
So(err, ShouldEqual, zerr.ErrCacheMiss)
So(blobs, ShouldBeNil)
err = cacheDriver.PutBlob("digest", path.Join(dir, "first"))
So(err, ShouldBeNil)
err = cacheDriver.PutBlob("digest", path.Join(dir, "second"))
So(err, ShouldBeNil)
err = cacheDriver.PutBlob("digest", path.Join(dir, "third"))
So(err, ShouldBeNil)
blobs, err = cacheDriver.GetAllBlobs("digest")
So(err, ShouldBeNil)
So(blobs, ShouldResemble, []string{"first", "second", "third"})
err = cacheDriver.DeleteBlob("digest", path.Join(dir, "first"))
So(err, ShouldBeNil)
blobs, err = cacheDriver.GetAllBlobs("digest")
So(err, ShouldBeNil)
So(len(blobs), ShouldEqual, 2)
So(blobs, ShouldContain, "second")
So(blobs, ShouldContain, "third")
err = cacheDriver.DeleteBlob("digest", path.Join(dir, "third"))
So(err, ShouldBeNil)
blobs, err = cacheDriver.GetAllBlobs("digest")
So(err, ShouldBeNil)
So(blobs, ShouldResemble, []string{"second"})
})
}
func TestRedisCacheError(t *testing.T) {
Convey("Make a new cache", t, func() {
dir := t.TempDir()
redisURL := "redis://127.0.0.1:" + test.GetFreePort()
connOpts, _ := redis.ParseURL(redisURL)
brokenClient := redis.NewClient(connOpts)
log := log.NewTestLogger()
So(log, ShouldNotBeNil)
// redis server is not running
cacheDriver, err := storage.Create("redis",
cache.RedisDriverParameters{brokenClient, dir, true, "zot"}, log)
So(err, ShouldNotBeNil)
So(cacheDriver, ShouldBeNil)
})
Convey("Redis unreachable", t, func() {
miniRedis := miniredis.RunT(t)
dir := t.TempDir()
log := log.NewTestLogger()
So(log, ShouldNotBeNil)
connOpts, _ := redis.ParseURL("redis://" + miniRedis.Addr())
workingClient := redis.NewClient(connOpts)
redisURL := "redis://127.0.0.1:" + test.GetFreePort() // must not match miniRedis.Addr()
connOpts, _ = redis.ParseURL(redisURL)
brokenClient := redis.NewClient(connOpts)
cacheDriver, err := cache.NewRedisCache(
cache.RedisDriverParameters{workingClient, dir, false, "zot"}, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
// replace the working driver with the broken one
cacheDriver.SetClient(brokenClient)
err = cacheDriver.PutBlob("key", "val")
So(err, ShouldNotBeNil)
found := cacheDriver.HasBlob("key", "val")
So(found, ShouldEqual, false)
_, err = cacheDriver.GetBlob("key")
So(err, ShouldNotBeNil)
_, err = cacheDriver.GetAllBlobs("key")
So(err, ShouldNotBeNil)
err = cacheDriver.DeleteBlob("key", "val")
So(err, ShouldNotBeNil)
})
}
func TestRedisMocked(t *testing.T) {
Convey("Redis tests using mocks", t, func() {
dir := t.TempDir()
log := log.NewTestLogger()
So(log, ShouldNotBeNil)
tests := []cache.RedisDriverParameters{
{
RootDir: dir,
UseRelPaths: true,
}, {
RootDir: dir,
UseRelPaths: false,
}, {
RootDir: dir,
UseRelPaths: true,
KeyPrefix: "someprefix",
}, {
RootDir: dir,
UseRelPaths: true,
KeyPrefix: "zot",
},
}
for i, redisDriverParams := range tests {
testID := fmt.Sprintf(" %d", i)
keyPrefix := redisDriverParams.KeyPrefix
if len(keyPrefix) == 0 {
// check default
keyPrefix = "zot"
}
keyPrefix += ":"
// depending on UseRelPaths value we check the relative or absolute value
// in results using path.Join(pathPrefix, path) in both cases
pathPrefix := ""
if !redisDriverParams.UseRelPaths {
pathPrefix = redisDriverParams.RootDir
}
Convey("PutBlob HExists error"+testID, func() {
// initialize mock client
cacheDB, mock := redismock.NewClientMock()
redisDriverParams.Client = cacheDB
mock.ExpectPing().SetVal("OK")
cacheDriver, err := cache.NewRedisCache(redisDriverParams, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetErr(ErrTestError)
err = cacheDriver.PutBlob("key", path.Join(dir, "val"))
So(err, ShouldEqual, ErrTestError)
err = mock.ExpectationsWereMet()
So(err, ShouldBeNil)
})
Convey("PutBlob HSet error"+testID, func() {
// initialize mock client
cacheDB, mock := redismock.NewClientMock()
redisDriverParams.Client = cacheDB
mock.ExpectPing().SetVal("OK")
cacheDriver, err := cache.NewRedisCache(redisDriverParams, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(false)
mock.ExpectTxPipeline()
mock.ExpectHSet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key",
path.Join(pathPrefix, "val")).SetErr(ErrTestError)
err = cacheDriver.PutBlob("key", path.Join(dir, "val"))
So(err, ShouldEqual, ErrTestError)
err = mock.ExpectationsWereMet()
So(err, ShouldBeNil)
})
Convey("PutBlob SAdd error"+testID, func() {
// initialize mock client
cacheDB, mock := redismock.NewClientMock()
redisDriverParams.Client = cacheDB
mock.ExpectPing().SetVal("OK")
cacheDriver, err := cache.NewRedisCache(redisDriverParams, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(false)
mock.ExpectTxPipeline()
mock.ExpectHSet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key",
path.Join(pathPrefix, "val")).SetVal(1)
mock.ExpectSAdd(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val")).SetErr(ErrTestError)
err = cacheDriver.PutBlob("key", path.Join(dir, "val"))
So(err, ShouldEqual, ErrTestError)
err = mock.ExpectationsWereMet()
So(err, ShouldBeNil)
})
Convey("PutBlob succeeds original bucket is created"+testID, func() {
// initialize mock client
cacheDB, mock := redismock.NewClientMock()
redisDriverParams.Client = cacheDB
mock.ExpectPing().SetVal("OK")
cacheDriver, err := cache.NewRedisCache(redisDriverParams, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(false)
mock.ExpectTxPipeline()
mock.ExpectHSet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key",
path.Join(pathPrefix, "val")).SetVal(1)
mock.ExpectSAdd(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val")).SetVal(1)
mock.ExpectTxPipelineExec()
err = cacheDriver.PutBlob("key", path.Join(dir, "val"))
So(err, ShouldBeNil)
err = mock.ExpectationsWereMet()
So(err, ShouldBeNil)
})
Convey("PutBlob succeeds original bucket is reused"+testID, func() {
// initialize mock client
cacheDB, mock := redismock.NewClientMock()
redisDriverParams.Client = cacheDB
mock.ExpectPing().SetVal("OK")
cacheDriver, err := cache.NewRedisCache(redisDriverParams, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(true)
mock.ExpectTxPipeline()
mock.ExpectSAdd(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val")).SetVal(1)
mock.ExpectTxPipelineExec()
err = cacheDriver.PutBlob("key", path.Join(dir, "val"))
So(err, ShouldBeNil)
err = mock.ExpectationsWereMet()
So(err, ShouldBeNil)
})
Convey("SMembers error in GetAllBlobs"+testID, func() {
// initialize mock client
cacheDB, mock := redismock.NewClientMock()
redisDriverParams.Client = cacheDB
mock.ExpectPing().SetVal("OK")
cacheDriver, err := cache.NewRedisCache(redisDriverParams, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
mock.ExpectHGet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(path.Join(pathPrefix, "val"))
mock.ExpectSMembers(keyPrefix + constants.BlobsCache + ":" + constants.DuplicatesBucket + ":key").
SetErr(ErrTestError)
_, err = cacheDriver.GetAllBlobs("key")
So(err, ShouldEqual, ErrTestError)
err = mock.ExpectationsWereMet()
So(err, ShouldBeNil)
})
Convey("GetAllBlobs succeeds"+testID, func() {
// initialize mock client
cacheDB, mock := redismock.NewClientMock()
redisDriverParams.Client = cacheDB
mock.ExpectPing().SetVal("OK")
cacheDriver, err := cache.NewRedisCache(redisDriverParams, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(false)
mock.ExpectTxPipeline()
mock.ExpectHSet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key",
path.Join(pathPrefix, "val1")).SetVal(1)
mock.ExpectSAdd(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val1")).SetVal(1)
mock.ExpectTxPipelineExec()
err = cacheDriver.PutBlob("key", path.Join(dir, "val1"))
So(err, ShouldBeNil)
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(false)
mock.ExpectTxPipeline()
mock.ExpectHSet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key",
path.Join(pathPrefix, "val2")).SetVal(1)
mock.ExpectSAdd(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val2")).SetVal(1)
mock.ExpectTxPipelineExec()
err = cacheDriver.PutBlob("key", path.Join(dir, "val2"))
So(err, ShouldBeNil)
mock.ExpectHGet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(path.Join(pathPrefix, "val1"))
mock.ExpectSMembers(keyPrefix + constants.BlobsCache + ":" + constants.DuplicatesBucket + ":key").
SetVal([]string{path.Join(pathPrefix, "val1"), path.Join(pathPrefix, "val2")})
allBlobs, err := cacheDriver.GetAllBlobs("key")
So(err, ShouldBeNil)
So(allBlobs, ShouldResemble, []string{path.Join(pathPrefix, "val1"), path.Join(pathPrefix, "val2")})
err = mock.ExpectationsWereMet()
So(err, ShouldBeNil)
})
Convey("HasBlob HExists returns error"+testID, func() {
// initialize mock client
cacheDB, mock := redismock.NewClientMock()
redisDriverParams.Client = cacheDB
mock.ExpectPing().SetVal("OK")
cacheDriver, err := cache.NewRedisCache(redisDriverParams, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
mock.ExpectSIsMember(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val")).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetErr(ErrTestError)
ok := cacheDriver.HasBlob("key", path.Join(dir, "val"))
So(ok, ShouldBeFalse)
err = mock.ExpectationsWereMet()
So(err, ShouldBeNil)
})
Convey("HasBlob SIsMember returns error"+testID, func() {
// initialize mock client
cacheDB, mock := redismock.NewClientMock()
redisDriverParams.Client = cacheDB
mock.ExpectPing().SetVal("OK")
cacheDriver, err := cache.NewRedisCache(redisDriverParams, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
mock.ExpectSIsMember(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val")).SetErr(ErrTestError)
ok := cacheDriver.HasBlob("key", path.Join(dir, "val"))
So(ok, ShouldBeFalse)
err = mock.ExpectationsWereMet()
So(err, ShouldBeNil)
})
Convey("HasBlob HExists returns false"+testID, func() {
// initialize mock client
cacheDB, mock := redismock.NewClientMock()
redisDriverParams.Client = cacheDB
mock.ExpectPing().SetVal("OK")
cacheDriver, err := cache.NewRedisCache(redisDriverParams, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
mock.ExpectSIsMember(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val")).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(false)
ok := cacheDriver.HasBlob("key", path.Join(dir, "val"))
So(ok, ShouldBeFalse)
err = mock.ExpectationsWereMet()
So(err, ShouldBeNil)
})
Convey("DeleteBlob tests"+testID, func() {
// initialize mock client
cacheDB, mock := redismock.NewClientMock()
redisDriverParams.Client = cacheDB
mock.ExpectPing().SetVal("OK")
cacheDriver, err := cache.NewRedisCache(redisDriverParams, log)
So(cacheDriver, ShouldNotBeNil)
So(err, ShouldBeNil)
// Create entry for 1st path
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(false)
mock.ExpectTxPipeline()
mock.ExpectHSet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key",
path.Join(pathPrefix, "val1")).SetVal(1)
mock.ExpectSAdd(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val1")).SetVal(1)
mock.ExpectTxPipelineExec()
err = cacheDriver.PutBlob("key", path.Join(dir, "val1"))
So(err, ShouldBeNil)
Convey("DeleteBlob error in HDel"+testID, func() {
// If the 2nd path does not exist, HDel is callled
// Error switching to new path
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectSRem(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val1")).SetVal(1)
mock.ExpectHGet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(path.Join(pathPrefix, "val1"))
// failed to get new path
mock.ExpectSRandMember(keyPrefix + constants.BlobsCache + ":" + constants.DuplicatesBucket + ":key").
RedisNil()
mock.ExpectHDel(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetErr(ErrTestError)
err = cacheDriver.DeleteBlob("key", path.Join(dir, "val1"))
So(err, ShouldEqual, ErrTestError)
})
Convey("DeleteBlob succeeds in deleting all data for original blob"+testID, func() {
// If the 2nd path does not exist, HDel is callled
// Error switching to new path
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectSRem(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val1")).SetVal(1)
mock.ExpectHGet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(path.Join(pathPrefix, "val1"))
// failed to get new path
mock.ExpectSRandMember(keyPrefix + constants.BlobsCache + ":" + constants.DuplicatesBucket + ":key").
RedisNil()
mock.ExpectHDel(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(1)
err = cacheDriver.DeleteBlob("key", path.Join(dir, "val1"))
So(err, ShouldBeNil)
})
Convey("DeleteBlob error in SRandMember"+testID, func() {
// Create entry for 2nd path
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(false)
mock.ExpectTxPipeline()
mock.ExpectHSet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key",
path.Join(pathPrefix, "val2")).SetVal(1)
mock.ExpectSAdd(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val2")).SetVal(1)
mock.ExpectTxPipelineExec()
err = cacheDriver.PutBlob("key", path.Join(dir, "val2"))
So(err, ShouldBeNil)
// Error switching to new path
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectSRem(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val1")).SetVal(1)
mock.ExpectHGet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(path.Join(pathPrefix, "val1"))
// failed to get new path
mock.ExpectSRandMember(keyPrefix + constants.BlobsCache + ":" + constants.DuplicatesBucket + ":key").
SetErr(ErrTestError)
err = cacheDriver.DeleteBlob("key", path.Join(dir, "val1"))
So(err, ShouldEqual, ErrTestError)
})
Convey("DeleteBlob error in HSet"+testID, func() {
// Create entry for 2nd path
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(false)
mock.ExpectTxPipeline()
mock.ExpectHSet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key",
path.Join(pathPrefix, "val2")).SetVal(1)
mock.ExpectSAdd(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val2")).SetVal(1)
mock.ExpectTxPipelineExec()
err = cacheDriver.PutBlob("key", path.Join(dir, "val2"))
So(err, ShouldBeNil)
// Error switching to new path
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectSRem(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val1")).SetVal(1)
mock.ExpectHGet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(path.Join(pathPrefix, "val1"))
mock.ExpectSRandMember(keyPrefix + constants.BlobsCache + ":" + constants.DuplicatesBucket + ":key").
SetVal(path.Join(pathPrefix, "val2"))
mock.ExpectHSet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key",
path.Join(pathPrefix, "val2")).SetErr(ErrTestError)
err = cacheDriver.DeleteBlob("key", path.Join(dir, "val1"))
So(err, ShouldEqual, ErrTestError)
})
Convey("DeleteBlob succeeds in switching original blob path"+testID, func() {
// Create entry for 2nd path
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectHExists(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(false)
mock.ExpectTxPipeline()
mock.ExpectHSet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key",
path.Join(pathPrefix, "val2")).SetVal(1)
mock.ExpectSAdd(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val2")).SetVal(1)
mock.ExpectTxPipelineExec()
err = cacheDriver.PutBlob("key", path.Join(dir, "val2"))
So(err, ShouldBeNil)
mock.Regexp().ExpectSetNX(keyPrefix+"locks:key", `.*`, 8*time.Second).SetVal(true)
mock.ExpectSRem(keyPrefix+constants.BlobsCache+":"+constants.DuplicatesBucket+":key",
path.Join(pathPrefix, "val1")).SetVal(1)
mock.ExpectHGet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key").
SetVal(path.Join(pathPrefix, "val1"))
mock.ExpectSRandMember(keyPrefix + constants.BlobsCache + ":" + constants.DuplicatesBucket + ":key").
SetVal(path.Join(pathPrefix, "val2"))
mock.ExpectHSet(keyPrefix+constants.BlobsCache+":"+constants.OriginalBucket, "key",
path.Join(pathPrefix, "val2")).SetVal(1)
err = cacheDriver.DeleteBlob("key", path.Join(dir, "val1"))
So(err, ShouldBeNil)
})
err = mock.ExpectationsWereMet()
So(err, ShouldBeNil)
})
}
})
}