Initial cloud-services repo - gateway service + pkg modules
This commit is contained in:
86
pkg/redis/redisutils/cache_set.go
Normal file
86
pkg/redis/redisutils/cache_set.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package redisutils
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"fiskerinc.com/modules/redis"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCacheDoesntExist = errors.New("key doesn't exist")
|
||||
ErrWrongResponseFormat = errors.New("wrong response format")
|
||||
)
|
||||
|
||||
type CachedSet struct {
|
||||
redis redis.Client
|
||||
}
|
||||
|
||||
func (s *CachedSet) SetConnection(client redis.Client) {
|
||||
s.redis = client
|
||||
}
|
||||
|
||||
func (s *CachedSet) GetCachedSet(key string) (map[string]struct{}, error) {
|
||||
batch := redis.NewRedisBatchCommands()
|
||||
batch.Add("EXISTS", key)
|
||||
batch.Add("SMEMBERS", key)
|
||||
|
||||
resultsI, err := s.redis.ExecuteBatch(batch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results, ok := resultsI.([]interface{})
|
||||
if !ok || len(results) != 2 {
|
||||
return nil, errResponseFormat("[2]interface{}", resultsI)
|
||||
}
|
||||
|
||||
keyExists, ok := results[0].(int64)
|
||||
if !ok {
|
||||
return nil, errResponseFormat("int64", results[0])
|
||||
}
|
||||
if keyExists == 0 {
|
||||
return nil, ErrCacheDoesntExist
|
||||
}
|
||||
|
||||
cacheRes, ok := results[1].([]interface{})
|
||||
if !ok {
|
||||
return nil, errResponseFormat("[]interface{}", results[1])
|
||||
}
|
||||
|
||||
cacheSet := make(map[string]struct{}, len(cacheRes))
|
||||
for _, signal := range cacheRes {
|
||||
s, ok := signal.([]byte)
|
||||
if !ok {
|
||||
return nil, errResponseFormat("[]byte", signal)
|
||||
}
|
||||
cacheSet[string(s)] = struct{}{}
|
||||
}
|
||||
|
||||
return cacheSet, nil
|
||||
}
|
||||
|
||||
func (s *CachedSet) UpdateSetCache(key string, cacheValues []interface{}) error {
|
||||
saddCommand := append([]interface{}{"SADD", key}, cacheValues...)
|
||||
_, err := s.redis.Execute(saddCommand...)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *CachedSet) CreateSetCache(key string, cacheValues []interface{}, expireTime time.Time) error {
|
||||
batch := redis.NewRedisBatchCommands()
|
||||
|
||||
saddCommand := append([]interface{}{"SADD", key}, cacheValues...)
|
||||
batch.Add(saddCommand...)
|
||||
batch.Add("EXPIREAT", key, expireTime.Unix())
|
||||
|
||||
_, err := s.redis.ExecuteBatch(batch)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func errResponseFormat(expectedType string, got interface{}) error {
|
||||
return errors.WithStack(
|
||||
errors.WithMessagef(ErrWrongResponseFormat, "expected type: %s, got: %v", expectedType, got),
|
||||
)
|
||||
}
|
||||
28
pkg/redis/redisutils/cache_set_mock.go
Normal file
28
pkg/redis/redisutils/cache_set_mock.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package redisutils
|
||||
|
||||
import (
|
||||
"fiskerinc.com/modules/redis"
|
||||
"time"
|
||||
)
|
||||
|
||||
type GetCachedSetMock func(key string) (map[string]struct{}, error)
|
||||
|
||||
type CacheSetMock struct {
|
||||
GetCachedSetMock func(key string) (map[string]struct{}, error)
|
||||
UpdateSetCacheMock func(key string, cacheValues []interface{}) error
|
||||
CreateSetCacheMock func(key string, cacheValues []interface{}, expireTime time.Time) error
|
||||
}
|
||||
|
||||
func (c CacheSetMock) SetConnection(client redis.Client) {}
|
||||
|
||||
func (c CacheSetMock) GetCachedSet(key string) (map[string]struct{}, error) {
|
||||
return c.GetCachedSetMock(key)
|
||||
}
|
||||
|
||||
func (c CacheSetMock) UpdateSetCache(key string, cacheValues []interface{}) error {
|
||||
return c.UpdateSetCacheMock(key, cacheValues)
|
||||
}
|
||||
|
||||
func (c CacheSetMock) CreateSetCache(key string, cacheValues []interface{}, expireTime time.Time) error {
|
||||
return c.CreateSetCacheMock(key, cacheValues, expireTime)
|
||||
}
|
||||
59
pkg/redis/redisutils/cache_set_mock_funcs.go
Normal file
59
pkg/redis/redisutils/cache_set_mock_funcs.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package redisutils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var ErrFailedFunc = errors.New("some error")
|
||||
|
||||
// GetCachedSetMock funcs.
|
||||
|
||||
func SuccessGetCachedSetMock(t *testing.T, expKey string, response map[string]struct{}) func(key string) (map[string]struct{}, error) {
|
||||
return func(key string) (map[string]struct{}, error) {
|
||||
assert.Equal(t, expKey, key)
|
||||
|
||||
return response, nil
|
||||
}
|
||||
}
|
||||
|
||||
func NoKeyGetCachedSetMock(key string) (map[string]struct{}, error) {
|
||||
return nil, ErrCacheDoesntExist
|
||||
}
|
||||
|
||||
func FailedGetCachedSetMock(key string) (map[string]struct{}, error) {
|
||||
return nil, ErrFailedFunc
|
||||
}
|
||||
|
||||
// UpdateSetCacheMock funcs.
|
||||
|
||||
func SuccessUpdateSetCacheMock(t *testing.T, expKey string, expCacheValues []interface{}) func(key string, cacheValues []interface{}) error {
|
||||
return func(key string, cacheValues []interface{}) error {
|
||||
assert.Equal(t, expKey, key)
|
||||
assert.Equal(t, expCacheValues, cacheValues)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func FailUpdateSetCacheMock(key string, cacheValues []interface{}) error {
|
||||
return ErrFailedFunc
|
||||
}
|
||||
|
||||
// CreateSetCacheMock funcs.
|
||||
|
||||
func SuccessCreateSetCacheMock(t *testing.T, expKey string, expCacheValues []interface{}, expExpireTime time.Time) func(key string, cacheValues []interface{}, expireTime time.Time) error {
|
||||
return func(key string, cacheValues []interface{}, expireTime time.Time) error {
|
||||
assert.Equal(t, expKey, key)
|
||||
assert.Equal(t, expCacheValues, cacheValues)
|
||||
assert.Equal(t, expExpireTime, expireTime)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func FailCreateSetCacheMock(key string, cacheValues []interface{}, expireTime time.Time) error {
|
||||
return ErrFailedFunc
|
||||
}
|
||||
211
pkg/redis/redisutils/cache_set_test.go
Normal file
211
pkg/redis/redisutils/cache_set_test.go
Normal file
@@ -0,0 +1,211 @@
|
||||
package redisutils_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"fiskerinc.com/modules/redis/redisutils"
|
||||
"fiskerinc.com/modules/redis/tester"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetCacheSet(t *testing.T) {
|
||||
key := "someKey"
|
||||
redisMock := tester.NewRedisMock()
|
||||
|
||||
tests := map[string]struct {
|
||||
getResults map[string]map[string]interface{}
|
||||
batchError error
|
||||
expRes map[string]struct{}
|
||||
expError error
|
||||
}{
|
||||
"correct": {
|
||||
getResults: map[string]map[string]interface{}{
|
||||
"EXISTS": {
|
||||
key: int64(1),
|
||||
},
|
||||
"SMEMBERS": {
|
||||
key: []interface{}{
|
||||
[]byte("609:ESP_ActvSig_DTC"),
|
||||
[]byte("832:ADAS_FltIndcr"),
|
||||
[]byte("832:ADAS_IntegtCrsFltTxt"),
|
||||
},
|
||||
},
|
||||
},
|
||||
expRes: map[string]struct{}{
|
||||
"609:ESP_ActvSig_DTC": {},
|
||||
"832:ADAS_FltIndcr": {},
|
||||
"832:ADAS_IntegtCrsFltTxt": {},
|
||||
},
|
||||
},
|
||||
"key_doesnt_exist": {
|
||||
getResults: map[string]map[string]interface{}{
|
||||
"EXISTS": {
|
||||
key: int64(0),
|
||||
},
|
||||
},
|
||||
expError: redisutils.ErrCacheDoesntExist,
|
||||
},
|
||||
"batch_error": {
|
||||
batchError: errors.New("some error"),
|
||||
expError: errors.New("some error"),
|
||||
},
|
||||
"wrong_batch_first_elem": {
|
||||
getResults: map[string]map[string]interface{}{
|
||||
"EXISTS": {
|
||||
key: 1,
|
||||
},
|
||||
"SMEMBERS": {
|
||||
key: []interface{}{},
|
||||
},
|
||||
},
|
||||
expError: errors.New("expected type: int64, got: 1: wrong response format"),
|
||||
},
|
||||
"wrong_batch_second_elem": {
|
||||
getResults: map[string]map[string]interface{}{
|
||||
"EXISTS": {
|
||||
key: int64(1),
|
||||
},
|
||||
"SMEMBERS": {
|
||||
key: 1,
|
||||
},
|
||||
},
|
||||
expError: errors.New("expected type: []interface{}, got: 1: wrong response format"),
|
||||
},
|
||||
"wrong_batch_second_sub_elem": {
|
||||
getResults: map[string]map[string]interface{}{
|
||||
"EXISTS": {
|
||||
key: int64(1),
|
||||
},
|
||||
"SMEMBERS": {
|
||||
key: []interface{}{1},
|
||||
},
|
||||
},
|
||||
expError: errors.New("expected type: []byte, got: 1: wrong response format"),
|
||||
},
|
||||
}
|
||||
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
redisMock.GetCommandResult = tt.getResults
|
||||
redisMock.Error = tt.batchError
|
||||
|
||||
cSet := redisutils.CachedSet{}
|
||||
cSet.SetConnection(redisMock)
|
||||
|
||||
res, err := cSet.GetCachedSet(key)
|
||||
if err != nil && tt.expError != nil {
|
||||
assert.Equal(t, tt.expError.Error(), err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.expError, err)
|
||||
assert.Equal(t, tt.expRes, res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateSetCache(t *testing.T) {
|
||||
redisMock := tester.NewRedisMock()
|
||||
mockTime := time.Date(2022, 8, 11, 15, 53, 0, 0, time.UTC)
|
||||
|
||||
tests := map[string]struct {
|
||||
cacheValues []interface{}
|
||||
batchError error
|
||||
expSetValues map[string]tester.ExpiringCache
|
||||
expError error
|
||||
}{
|
||||
"correct": {
|
||||
cacheValues: []interface{}{
|
||||
"609:ESP_ActvSig_DTC",
|
||||
"832:ADAS_FltIndcr",
|
||||
"832:ADAS_IntegtCrsFltTxt",
|
||||
},
|
||||
expSetValues: map[string]tester.ExpiringCache{
|
||||
"someKey": {
|
||||
Value: []interface{}{
|
||||
"609:ESP_ActvSig_DTC",
|
||||
"832:ADAS_FltIndcr",
|
||||
"832:ADAS_IntegtCrsFltTxt",
|
||||
},
|
||||
Expires: 1660233180,
|
||||
},
|
||||
},
|
||||
},
|
||||
"fail": {
|
||||
batchError: errors.New("some error"),
|
||||
expError: errors.New("some error"),
|
||||
},
|
||||
}
|
||||
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
redisMock.Reset()
|
||||
redisMock.Error = tt.batchError
|
||||
|
||||
cSet := redisutils.CachedSet{}
|
||||
cSet.SetConnection(redisMock)
|
||||
|
||||
err := cSet.CreateSetCache("someKey", tt.cacheValues, mockTime)
|
||||
if err != nil && tt.expError != nil {
|
||||
assert.Equal(t, tt.expError.Error(), err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.expError, err)
|
||||
assert.Equal(t, tt.expSetValues, redisMock.SetValues)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateSetCache(t *testing.T) {
|
||||
redisMock := tester.NewRedisMock()
|
||||
|
||||
tests := map[string]struct {
|
||||
cacheValues []interface{}
|
||||
execError error
|
||||
expSetValues map[string]tester.ExpiringCache
|
||||
expError error
|
||||
}{
|
||||
"correct": {
|
||||
cacheValues: []interface{}{
|
||||
"609:ESP_ActvSig_DTC",
|
||||
"832:ADAS_FltIndcr",
|
||||
"832:ADAS_IntegtCrsFltTxt",
|
||||
},
|
||||
expSetValues: map[string]tester.ExpiringCache{
|
||||
"someKey": {
|
||||
Value: []interface{}{
|
||||
"609:ESP_ActvSig_DTC",
|
||||
"832:ADAS_FltIndcr",
|
||||
"832:ADAS_IntegtCrsFltTxt",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"fail": {
|
||||
execError: errors.New("some error"),
|
||||
expError: errors.New("some error"),
|
||||
},
|
||||
}
|
||||
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
redisMock.Reset()
|
||||
redisMock.Error = tt.execError
|
||||
|
||||
cSet := redisutils.CachedSet{}
|
||||
cSet.SetConnection(redisMock)
|
||||
|
||||
err := cSet.UpdateSetCache("someKey", tt.cacheValues)
|
||||
if err != nil && tt.expError != nil {
|
||||
assert.Equal(t, tt.expError.Error(), err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.expError, err)
|
||||
assert.Equal(t, tt.expSetValues, redisMock.SetValues)
|
||||
})
|
||||
}
|
||||
}
|
||||
32
pkg/redis/redisutils/check_set.go
Normal file
32
pkg/redis/redisutils/check_set.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package redisutils
|
||||
|
||||
import (
|
||||
re "fiskerinc.com/modules/redis"
|
||||
"github.com/gomodule/redigo/redis"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func CheckSet(conn re.Client, id string, keys interface{}) ([]bool, error) {
|
||||
ckeys, ok := keys.([]string)
|
||||
if !ok {
|
||||
return nil, errors.New("keys is not []string")
|
||||
}
|
||||
|
||||
results := make([]bool, len(ckeys))
|
||||
batch := re.NewRedisBatchCommands()
|
||||
|
||||
for _, key := range ckeys {
|
||||
batch.Add("SISMEMBER", id, key)
|
||||
}
|
||||
|
||||
values, err := conn.ExecuteBatch(batch)
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
|
||||
err = redis.ScanSlice(values.([]interface{}), &results)
|
||||
if err != nil {
|
||||
return results, errors.WithStack(err)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
Reference in New Issue
Block a user