up: add more unit tests

This commit is contained in:
inhere
2021-06-30 13:45:22 +08:00
parent 1af54fad12
commit 5e02b7557a
17 changed files with 240 additions and 57 deletions

View File

@@ -25,11 +25,14 @@ Generic cache use and cache manager for golang. Provide a unified usage API by p
- `gocache` https://github.com/patrickmn/go-cache - `gocache` https://github.com/patrickmn/go-cache
- `bigcache` https://github.com/allegro/bigcache - `bigcache` https://github.com/allegro/bigcache
internal: Internal:
- file internal driver [driver_file.go](driver_file.go) - file internal driver [driver_file.go](driver_file.go)
- memory internal driver [driver_memory.go](driver_memory.go) - memory internal driver [driver_memory.go](driver_memory.go)
> Notice: The built-in implementation is relatively simple and is not recommended for production environments;
> the production environment recommends using the third-party drivers listed above.
## GoDoc ## GoDoc
- [doc on gowalker](https://gowalker.org/github.com/gookit/cache) - [doc on gowalker](https://gowalker.org/github.com/gookit/cache)
@@ -53,8 +56,6 @@ type Cache interface {
// basic operation // basic operation
Has(key string) bool Has(key string) bool
Get(key string) interface{} Get(key string) interface{}
// GetAs get cache value and unmarshal to an object ptr.
GetAs(key string, ptr interface{}) error
Set(key string, val interface{}, ttl time.Duration) (err error) Set(key string, val interface{}, ttl time.Duration) (err error)
Del(key string) error Del(key string) error
// multi operation // multi operation

View File

@@ -26,11 +26,13 @@ Golang 通用的缓存管理使用库。
- `gocache` https://github.com/patrickmn/go-cache - `gocache` https://github.com/patrickmn/go-cache
- `bigcache` https://github.com/allegro/bigcache - `bigcache` https://github.com/allegro/bigcache
internal: Internal:
- file 简单的文件缓存(_当前包的内置实现_) - file 简单的文件缓存(_当前包的内置实现_)
- memory 简单的内存缓存(_当前包的内置实现_) - memory 简单的内存缓存(_当前包的内置实现_)
> 注意:内置实现比较简单,不推荐生产环境使用;生产环境推荐使用上面列出的三方驱动。
## GoDoc ## GoDoc
- [doc on gowalker](https://gowalker.org/github.com/gookit/cache) - [doc on gowalker](https://gowalker.org/github.com/gookit/cache)
@@ -53,8 +55,6 @@ type Cache interface {
// basic op // basic op
Has(key string) bool Has(key string) bool
Get(key string) interface{} Get(key string) interface{}
// GetAs get cache value and unmarshal to an object ptr.
GetAs(key string, ptr interface{}) error
Set(key string, val interface{}, ttl time.Duration) (err error) Set(key string, val interface{}, ttl time.Duration) (err error)
Del(key string) error Del(key string) error
// multi op // multi op

View File

@@ -8,6 +8,7 @@ import (
"go.etcd.io/bbolt" "go.etcd.io/bbolt"
) )
// Name driver name
const Name = "boltDB" const Name = "boltDB"
// BoltDB definition // BoltDB definition

View File

@@ -10,6 +10,7 @@ import (
// Memory open a file that does not persist to disk. // Memory open a file that does not persist to disk.
const Memory = ":memory:" const Memory = ":memory:"
// Name driver name
const Name = "buntDB" const Name = "buntDB"
// BuntDB definition. // BuntDB definition.

View File

@@ -88,13 +88,13 @@ func Register(name string, driver Cache) *Manager {
} }
// Unregister an cache driver // Unregister an cache driver
func Unregister(name string) { func Unregister(name string) int {
std.Unregister(name) return std.Unregister(name)
} }
// UnregisterAll cache drivers // UnregisterAll cache drivers
func UnregisterAll(fn ...func(cache Cache)) { func UnregisterAll(fn ...func(cache Cache)) int {
std.UnregisterAll(fn...) return std.UnregisterAll(fn...)
} }
// SetDefName set default driver name. // SetDefName set default driver name.
@@ -124,6 +124,11 @@ func Driver(driverName string) Cache {
return std.Driver(driverName) return std.Driver(driverName)
} }
// Std get default cache manager instance
func Std() *Manager {
return std
}
// DefManager get default cache manager instance // DefManager get default cache manager instance
func DefManager() *Manager { func DefManager() *Manager {
return std return std
@@ -139,6 +144,11 @@ func Close() error {
return std.Close() return std.Close()
} }
// ClearAll all drivers caches
func ClearAll() error {
return std.ClearAll()
}
/************************************************************* /*************************************************************
* quick use by default cache driver * quick use by default cache driver
*************************************************************/ *************************************************************/

View File

@@ -49,15 +49,9 @@ func NewFileCache(dir string, pfxAndKey ...string) *FileCache {
return c return c
} }
// Has cache key. // Has cache key. will check expire time
// TODO decode value, and check expire time
func (c *FileCache) Has(key string) bool { func (c *FileCache) Has(key string) bool {
if c.MemoryCache.Has(key) { return c.get(key) != nil
return true
}
path := c.GetFilename(key)
return fileExists(path)
} }
// Get value by key // Get value by key
@@ -87,15 +81,14 @@ func (c *FileCache) get(key string) interface{} {
return nil return nil
} }
// check expire time // check expired
if item.Exp == 0 || item.Exp > time.Now().Unix() { if item.Expired() {
c.caches[key] = item // save to memory. c.SetLastErr(c.del(key))
return item.Val return nil
} }
// has been expired. delete it. c.caches[key] = item // save to memory.
c.SetLastErr(c.del(key)) return item.Val
return nil
} }
// Set value by key // Set value by key
@@ -107,8 +100,8 @@ func (c *FileCache) Set(key string, val interface{}, ttl time.Duration) (err err
} }
func (c *FileCache) set(key string, val interface{}, ttl time.Duration) (err error) { func (c *FileCache) set(key string, val interface{}, ttl time.Duration) (err error) {
if err = c.MemoryCache.set(key, val, ttl); err != nil { err = c.MemoryCache.set(key, val, ttl)
c.SetLastErr(err) if err != nil {
return return
} }
@@ -132,10 +125,7 @@ func (c *FileCache) set(key string, val interface{}, ttl time.Duration) (err err
} }
defer f.Close() defer f.Close()
if _, err = f.Write(bs); err != nil { _, err = f.Write(bs)
return err
}
return return
} }
@@ -165,12 +155,12 @@ func (c *FileCache) GetMulti(keys []string) map[string]interface{} {
c.lock.RLock() c.lock.RLock()
defer c.lock.RUnlock() defer c.lock.RUnlock()
values := make(map[string]interface{}, len(keys)) data := make(map[string]interface{}, len(keys))
for _, key := range keys { for _, key := range keys {
values[key] = c.get(key) data[key] = c.get(key)
} }
return values return data
} }
// SetMulti values by multi key // SetMulti values by multi key

View File

@@ -5,16 +5,6 @@ import (
"time" "time"
) )
// MemoryCache definition.
type MemoryCache struct {
// locker
lock sync.RWMutex
// cache data in memory. or use sync.Map
caches map[string]*Item
// TODO set max cache number
MaxCacheNum int
}
// Item for memory cache // Item for memory cache
type Item struct { type Item struct {
// Exp expire time // Exp expire time
@@ -23,9 +13,19 @@ type Item struct {
Val interface{} Val interface{}
} }
// Invalid check whether expired // Expired check whether expired
func (item Item) Invalid() bool { func (item Item) Expired() bool {
return item.Exp != 0 && item.Exp < time.Now().Unix() return item.Exp > 1 && item.Exp < time.Now().Unix()
}
// MemoryCache definition.
type MemoryCache struct {
// locker
lock sync.RWMutex
// cache data in memory. or use sync.Map
caches map[string]*Item
// CacheSize TODO set max cache size
CacheSize int
} }
// NewMemoryCache create a memory cache instance // NewMemoryCache create a memory cache instance
@@ -53,9 +53,8 @@ func (c *MemoryCache) Get(key string) interface{} {
func (c *MemoryCache) get(key string) interface{} { func (c *MemoryCache) get(key string) interface{} {
if item, ok := c.caches[key]; ok { if item, ok := c.caches[key]; ok {
// check expire time // check expire time. if has been expired, remove it.
// if has been expired, remove it. if item.Expired() {
if item.Invalid() {
_ = c.del(key) _ = c.del(key)
} }

View File

@@ -122,3 +122,33 @@ func TestFileCache_object(t *testing.T) {
// val2 := c.GetAs() // val2 := c.GetAs()
// dump.P("cache get:", val) // dump.P("cache get:", val)
} }
func TestDefManager(t *testing.T) {
is := assert.New(t)
num := cache.UnregisterAll()
is.Equal(0, num)
is.Equal(0, cache.Unregister("not_exist"))
cache.Register(cache.DvrMemory, cache.NewMemoryCache())
is.Equal(cache.DvrMemory, cache.Std().DefName())
key := "name"
// set
err := cache.Set(key, "cache value", cache.TwoMinutes)
is.NoError(err)
is.True(cache.Has(key))
// get
val := cache.Get(key)
is.Equal("cache value", val)
// del
is.NoError(cache.Del(key))
is.False(cache.Has(key))
is.NoError(cache.Clear())
num = cache.UnregisterAll()
is.GreaterOrEqual(1, num)
}

View File

@@ -17,7 +17,7 @@ func Example() {
cache.Register(goredis.Name, goredis.Connect("127.0.0.1:6379", "", 0)) cache.Register(goredis.Name, goredis.Connect("127.0.0.1:6379", "", 0))
// setting default driver name // setting default driver name
cache.DefaultUse(cache.DvrRedis) cache.DefaultUse(goredis.Name)
// quick use.(it is default driver) // quick use.(it is default driver)
// //

View File

@@ -7,6 +7,9 @@ import (
"github.com/bluele/gcache" "github.com/bluele/gcache"
) )
// Name driver name
const Name = "gcache"
// GCache driver definition // GCache driver definition
type GCache struct { type GCache struct {
// cache.BaseDriver // cache.BaseDriver

122
gcache/gcache_test.go Normal file
View File

@@ -0,0 +1,122 @@
package gcache_test
import (
"fmt"
"testing"
"time"
"github.com/gookit/cache"
"github.com/gookit/cache/gcache"
"github.com/gookit/goutil/dump"
"github.com/gookit/goutil/strutil"
"github.com/stretchr/testify/assert"
)
func Example() {
c := gcache.New(12)
key := "name"
// set
c.Set(key, "cache value", cache.Seconds2)
fmt.Println(c.Has(key))
// get
val := c.Get(key)
fmt.Println(val)
time.Sleep(2 * time.Second)
// get expired
val2 := c.Get(key)
fmt.Println(val2)
// del
c.Del(key)
fmt.Println(c.Has(key))
// Output:
// true
// cache value
// <nil>
// false
}
func ExampleGCache_in_cachePkg() {
cache.Register(gcache.Name, gcache.New(12))
defer cache.UnregisterAll()
key := "name1"
// set
cache.Set(key, "cache value", cache.Seconds2)
fmt.Println(cache.Has(key))
// get
val := cache.Get(key)
fmt.Println(val)
time.Sleep(2 * time.Second)
// get expired
val2 := cache.Get(key)
fmt.Println(val2)
// del
cache.Del(key)
fmt.Println(cache.Has(key))
// Output:
// true
// cache value
// <nil>
// false
}
func TestGCache_usage(t *testing.T) {
is := assert.New(t)
c := gcache.New(12)
defer c.Clear()
key := strutil.RandomCharsV2(12)
is.False(c.Has(key))
err := c.Set(key, "value", cache.Seconds3)
is.NoError(err)
is.True(c.Has(key))
val := c.Get(key)
is.Equal("value", val)
// del
err = c.Del(key)
is.NoError(err)
is.False(c.Has(key))
}
type user struct {
Age int
Name string
}
func TestGCache_object(t *testing.T) {
is := assert.New(t)
c := gcache.New(12)
defer c.Clear()
b1 := user {
Age: 1,
Name: "inhere",
}
key := strutil.RandomCharsV2(12)
dump.P("cache key: " + key)
is.False(c.Has(key))
err := c.Set(key, b1, cache.Seconds3)
is.NoError(err)
is.True(c.Has(key))
b2 := c.Get(key).(user)
dump.P(b2)
is.Equal("inhere", b2.Name)
}

View File

@@ -12,7 +12,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func ExampleGoCache() { func Example() {
c := gocache.New() c := gocache.New()
key := "name" key := "name"
@@ -41,7 +41,7 @@ func ExampleGoCache() {
// false // false
} }
func ExampleNewGoCache_cachePkg() { func ExampleGoCache_in_cachePkg() {
c1 := gocache.NewGoCache(cache.OneDay, cache.FiveMinutes) c1 := gocache.NewGoCache(cache.OneDay, cache.FiveMinutes)
cache.Register(gocache.Name, c1) cache.Register(gocache.Name, c1)
defer cache.UnregisterAll() defer cache.UnregisterAll()

View File

@@ -7,6 +7,9 @@ import (
"github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb"
) )
// Name driver name
const Name = "leveldb"
// LevelDB definition // LevelDB definition
type LevelDB struct { type LevelDB struct {
// cache.BaseDriver // cache.BaseDriver

View File

@@ -43,13 +43,18 @@ func (m *Manager) Register(name string, driver Cache) *Manager {
} }
// Unregister an cache driver // Unregister an cache driver
func (m *Manager) Unregister(name string) { func (m *Manager) Unregister(name string) int {
if _, ok := m.drivers[name]; !ok {
return 0
}
delete(m.drivers, name) delete(m.drivers, name)
// reset default driver name. // reset default driver name.
if m.defName == name { if m.defName == name {
m.defName = "" m.defName = ""
} }
return 1
} }
// SetDefName set default driver name. alias of DefaultUse() // SetDefName set default driver name. alias of DefaultUse()
@@ -106,10 +111,20 @@ func (m *Manager) Close() (err error) {
return err return err
} }
// UnregisterAll cache drivers // ClearAll all drivers caches
func (m *Manager) UnregisterAll(fn ...func(cache Cache)) { func (m *Manager) ClearAll() (err error) {
m.defName = "" for _, cache := range m.drivers {
err = cache.Clear()
}
return err
}
// UnregisterAll cache drivers
func (m *Manager) UnregisterAll(fn ...func(cache Cache)) int {
num := len(m.drivers)
// unregister
m.defName = ""
for name, driver := range m.drivers { for name, driver := range m.drivers {
if len(fn) > 0 { if len(fn) > 0 {
fn[0](driver) fn[0](driver)
@@ -117,6 +132,7 @@ func (m *Manager) UnregisterAll(fn ...func(cache Cache)) {
delete(m.drivers, name) delete(m.drivers, name)
} }
return num
} }
/************************************************************* /*************************************************************

View File

@@ -8,6 +8,9 @@ import (
"github.com/gookit/cache" "github.com/gookit/cache"
) )
// Name driver name
const Name = "memCached"
// MemCached definition // MemCached definition
type MemCached struct { type MemCached struct {
cache.BaseDriver cache.BaseDriver

View File

@@ -5,6 +5,9 @@ import (
"time" "time"
) )
// Name driver name
const Name = "nutsdb"
// NutsDB definition TODO // NutsDB definition TODO
type NutsDB struct { type NutsDB struct {
// cache.BaseDriver // cache.BaseDriver

View File

@@ -11,6 +11,7 @@ import (
"github.com/gookit/cache" "github.com/gookit/cache"
) )
// Name driver name
const Name = "redigo" const Name = "redigo"
// RedisCache fallback alias // RedisCache fallback alias