first commit
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
andrey1s
2021-04-26 17:13:36 +03:00
commit 7da0cd57ce
45 changed files with 3703 additions and 0 deletions

84
test/helpers.go Normal file
View File

@@ -0,0 +1,84 @@
package test
import (
"context"
"os"
"path/filepath"
"runtime"
"time"
gom "github.com/bradfitz/gomemcache/memcache"
"github.com/cockroachdb/pebble"
"github.com/dgraph-io/ristretto"
redigo "github.com/gomodule/redigo/redis"
"gitoa.ru/go-4devs/cache/provider/redis"
)
// RedisClient created redis client.
func RedisClient() func(ctx context.Context) (redis.Conn, error) {
host, ok := os.LookupEnv("FDEVS_CACHE_REDIS_HOST")
if !ok {
host = ":6379"
}
client := &redigo.Pool{
DialContext: func(ctx context.Context) (redigo.Conn, error) {
return redigo.DialContext(ctx, "tcp", host)
},
}
return redis.NewPool(client)
}
// MemcacheClient created memcached client.
func MemcacheClient() *gom.Client {
host, ok := os.LookupEnv("FDEVS_CACHE_MEMCACHE_HOST")
if !ok {
host = "localhost:11211"
}
return gom.New(host)
}
// RistrettoClient creates ristretto client.
func RistrettoClient() *ristretto.Cache {
cache, _ := ristretto.NewCache(&ristretto.Config{
NumCounters: 1e7, // number of keys to track frequency of (10M).
MaxCost: 1 << 30, // maximum cost of cache (1GB).
BufferItems: 64, // number of keys per Get buffer.
})
return cache
}
// PebbleDB creates pebble DB.
func PebbleDB() (*pebble.DB, func()) {
path := "demo.test"
if _, filename, _, ok := runtime.Caller(0); ok {
path = filepath.Dir(filename) + "/" + path
}
db, _ := pebble.Open(path, &pebble.Options{})
return db, func() {
os.RemoveAll(path)
}
}
// User tested user data.
type User struct {
ID int
Name string
UpdateAt time.Time
CreatedAt time.Time
}
// NewUser create mocks data user.
func NewUser(id int) User {
return User{
ID: id,
Name: "andrey",
UpdateAt: time.Date(2020, 2, 1, 1, 2, 3, 4, time.UTC),
CreatedAt: time.Date(1999, 2, 1, 1, 2, 3, 4, time.UTC),
}
}

57
test/provider.go Normal file
View File

@@ -0,0 +1,57 @@
package test
import (
"context"
"fmt"
"testing"
"gitoa.ru/go-4devs/cache"
)
var _ cache.Provider = NewProviderMock(&testing.T{})
// OptionMock configure mock.
type OptionMock func(*ProviderMock)
// WithDelete sets delete method.
func WithDelete(f func(t *testing.T) func(ctx context.Context, item *cache.Item) error) OptionMock {
return func(pm *ProviderMock) { pm.operations[cache.OperationDelete] = f }
}
// WithGet sets get method.
func WithGet(f func(t *testing.T) func(ctx context.Context, item *cache.Item) error) OptionMock {
return func(pm *ProviderMock) { pm.operations[cache.OperationGet] = f }
}
// WithSet sets set method.
func WithSet(f func(t *testing.T) func(ctx context.Context, item *cache.Item) error) OptionMock {
return func(pm *ProviderMock) { pm.operations[cache.OperationSet] = f }
}
// NewProviderMock create new mock provider.
func NewProviderMock(t *testing.T, opts ...OptionMock) cache.Provider {
t.Helper()
pm := &ProviderMock{
t: t,
operations: make(map[string]func(t *testing.T) func(ctx context.Context, item *cache.Item) error, 3),
}
for _, o := range opts {
o(pm)
}
return func(ctx context.Context, operation string, item *cache.Item) error {
if m, ok := pm.operations[operation]; ok {
return m(pm.t)(ctx, item)
}
return fmt.Errorf("%w: %s", cache.ErrOperationNotAllwed, operation)
}
}
// ProviderMock mock.
type ProviderMock struct {
t *testing.T
operations map[string]func(t *testing.T) func(ctx context.Context, item *cache.Item) error
}

133
test/sute.go Normal file
View File

@@ -0,0 +1,133 @@
package test
import (
"context"
"errors"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"gitoa.ru/go-4devs/cache"
)
const (
expire = time.Second
waitExpire = expire * 2
)
// Option configure sute.
type Option func(*ProviderSuite)
// WithExpire sets expired errors.
func WithExpire(err error) Option {
return func(ps *ProviderSuite) { ps.expire = err }
}
func WithWaitGet(f func()) Option {
return func(ps *ProviderSuite) { ps.waitGet = f }
}
// RunSute run test by provider.
func RunSute(t *testing.T, provider cache.Provider, opts ...Option) {
t.Helper()
cs := &ProviderSuite{
provider: provider,
expire: cache.ErrCacheExpired,
waitGet: func() {},
}
for _, o := range opts {
o(cs)
}
suite.Run(t, cs)
}
// ProviderSuite for testing providers.
type ProviderSuite struct {
provider cache.Provider
expire error
waitGet func()
suite.Suite
}
// TestGet tested get.
func (s *ProviderSuite) TestGet() {
s.T().Parallel()
ctx := context.Background()
var val string
require.Nil(s.T(), s.provider(ctx, cache.OperationSet, cache.NewItem("get", "some value")))
s.waitGet()
require.Nil(s.T(), s.provider(ctx, cache.OperationGet, cache.NewItem("get", &val)))
require.Equal(s.T(), "some value", val)
var user User
cachedUser := NewUser(1)
require.Nil(s.T(), s.provider(ctx, cache.OperationSet, cache.NewItem("get_user", cachedUser)))
s.waitGet()
require.Nil(s.T(), s.provider(ctx, cache.OperationGet, cache.NewItem("get_user", &user)))
require.Equal(s.T(), cachedUser, user)
}
// TestCacheMiss tested cache miss error.
func (s *ProviderSuite) TestCacheMiss() {
s.T().Parallel()
ctx := context.Background()
require.True(s.T(),
errors.Is(s.provider(ctx, cache.OperationGet, cache.NewItem("cache_miss", nil)), cache.ErrCacheMiss),
"failed expect errors",
)
}
// TestExpired tested error expired.
func (s *ProviderSuite) TestExpired() {
s.T().Parallel()
ctx := context.Background()
var val string
require.Nil(s.T(), s.provider(ctx, cache.OperationSet, cache.NewItem("expired", "some value", cache.WithTTL(expire))))
time.Sleep(waitExpire)
err := s.provider(ctx, cache.OperationGet, cache.NewItem("expired", nil))
require.Truef(s.T(), errors.Is(err, s.expire), "failed expired error got:%s", err)
require.Equal(s.T(), "", val)
}
// TestTTL tested set ttl.
func (s *ProviderSuite) TestTTL() {
s.T().Parallel()
ctx := context.Background()
var val string
require.Nil(s.T(), s.provider(ctx, cache.OperationSet, cache.NewItem("ttl", "some ttl value", cache.WithTTL(time.Hour))))
s.waitGet()
require.Nil(s.T(), s.provider(ctx, cache.OperationGet, cache.NewItem("ttl", &val)))
require.Equal(s.T(), "some ttl value", val)
}
// TestDelete tested delete method.
func (s *ProviderSuite) TestDelete() {
s.T().Parallel()
ctx := context.Background()
require.Nil(s.T(), s.provider(ctx, cache.OperationSet, cache.NewItem("delete:key", "some delete value")))
require.Nil(s.T(), s.provider(ctx, cache.OperationDelete, cache.NewItem("delete:key", nil)))
require.True(s.T(),
errors.Is(s.provider(ctx, cache.OperationGet, cache.NewItem("cache_miss", nil)), cache.ErrCacheMiss),
"failed delete errors",
)
}