Skip to content

Commit

Permalink
Add tests for cache
Browse files Browse the repository at this point in the history
  • Loading branch information
oklahomer committed Nov 27, 2016
1 parent fa09ff5 commit 1b094eb
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 31 deletions.
12 changes: 8 additions & 4 deletions bot.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package sarah

import (
"github.com/oklahomer/go-sarah/log"
"golang.org/x/net/context"
"strings"
"time"
)

// Bot provides interface for each bot implementation.
Expand Down Expand Up @@ -47,11 +47,11 @@ type bot struct {
pluginConfigDir string
}

func newBot(adapter Adapter, configDir string) Bot {
func newBot(adapter Adapter, cacheConfig *CacheConfig, configDir string) Bot {
return &bot{
adapter: adapter,
commands: NewCommands(),
userContextCache: NewCachedUserContexts(3*time.Minute, 10*time.Minute),
userContextCache: NewCachedUserContexts(cacheConfig),
pluginConfigDir: configDir,
}
}
Expand All @@ -62,7 +62,11 @@ func (bot *bot) BotType() BotType {

func (bot *bot) Respond(ctx context.Context, input Input) error {
senderKey := input.SenderKey()
userContext := bot.userContextCache.Get(senderKey)
userContext, cacheErr := bot.userContextCache.Get(senderKey)
if cacheErr != nil {
log.Error(cacheErr.Error())
return nil
}

var res *CommandResponse
var err error
Expand Down
14 changes: 7 additions & 7 deletions bot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (bot *DummyBot) PluginConfigDir() string {

func Test_newBot(t *testing.T) {
adapter := &DummyAdapter{}
myBot := newBot(adapter, "")
myBot := newBot(adapter, NewCacheConfig(), "")
if _, ok := myBot.(*bot); !ok {
t.Errorf("newBot did not return bot instance: %#v.", myBot)
}
Expand All @@ -56,7 +56,7 @@ func TestBot_BotType(t *testing.T) {
var botType BotType = "slack"
adapter := &DummyAdapter{}
adapter.BotTypeValue = botType
bot := newBot(adapter, "")
bot := newBot(adapter, NewCacheConfig(), "")

if bot.BotType() != botType {
t.Errorf("Bot type is wrong: %s.", bot.BotType())
Expand All @@ -66,7 +66,7 @@ func TestBot_BotType(t *testing.T) {
func TestBot_PluginConfigDir(t *testing.T) {
dummyPluginDir := "/dummy/path/to/config"
adapter := &DummyAdapter{}
bot := newBot(adapter, dummyPluginDir)
bot := newBot(adapter, NewCacheConfig(), dummyPluginDir)

if bot.PluginConfigDir() != dummyPluginDir {
t.Errorf("Plugin configuration file's location is wrong: %s.", bot.PluginConfigDir())
Expand All @@ -75,7 +75,7 @@ func TestBot_PluginConfigDir(t *testing.T) {

func TestBot_AppendCommand(t *testing.T) {
adapter := &DummyAdapter{}
myBot := newBot(adapter, "")
myBot := newBot(adapter, NewCacheConfig(), "")

command := &DummyCommand{}
myBot.AppendCommand(command)
Expand All @@ -92,7 +92,7 @@ func TestBot_Respond(t *testing.T) {
adapter.SendMessageFunc = func(_ context.Context, _ Output) {
adapterProcessed = true
}
bot := newBot(adapter, "")
bot := newBot(adapter, NewCacheConfig(), "")

command := &DummyCommand{}
command.MatchFunc = func(str string) bool {
Expand Down Expand Up @@ -123,7 +123,7 @@ func TestBot_Run(t *testing.T) {
adapter.RunFunc = func(_ context.Context, _ chan<- Input, _ chan<- error) {
adapterProcessed = true
}
bot := newBot(adapter, "")
bot := newBot(adapter, NewCacheConfig(), "")

inputReceiver := make(chan Input)
errCh := make(chan error)
Expand All @@ -143,7 +143,7 @@ func TestBot_SendMessage(t *testing.T) {
adapter.SendMessageFunc = func(_ context.Context, _ Output) {
adapterProcessed = true
}
bot := newBot(adapter, "")
bot := newBot(adapter, NewCacheConfig(), "")

output := NewOutputMessage(struct{}{}, struct{}{})
bot.SendMessage(context.TODO(), output)
Expand Down
27 changes: 19 additions & 8 deletions cache.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
package sarah

import (
"github.com/oklahomer/go-sarah/log"
"fmt"
"github.com/patrickmn/go-cache"
"time"
)

type CacheConfig struct {
ExpiresIn time.Duration
CleanupInterval time.Duration
}

func NewCacheConfig() *CacheConfig {
return &CacheConfig{
ExpiresIn: 3 * time.Minute,
CleanupInterval: 10 * time.Minute,
}
}

type UserContext struct {
Next ContextualFunc
}
Expand All @@ -20,24 +32,23 @@ type CachedUserContexts struct {
cache *cache.Cache
}

func NewCachedUserContexts(expire, cleanupInterval time.Duration) *CachedUserContexts {
func NewCachedUserContexts(config *CacheConfig) *CachedUserContexts {
return &CachedUserContexts{
cache: cache.New(expire, cleanupInterval),
cache: cache.New(config.ExpiresIn, config.CleanupInterval),
}
}

func (contexts *CachedUserContexts) Get(key string) *UserContext {
func (contexts *CachedUserContexts) Get(key string) (*UserContext, error) {
val, hasKey := contexts.cache.Get(key)
if !hasKey || val == nil {
return nil
return nil, nil
}

switch v := val.(type) {
case *UserContext:
return v
return v, nil
default:
log.Errorf("cached value has illegal type of %#v", v)
return nil
return nil, fmt.Errorf("cached value has illegal type of %T", v)
}
}

Expand Down
28 changes: 19 additions & 9 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,47 @@ import (
)

func TestNewCachedUserContexts(t *testing.T) {
contexts := NewCachedUserContexts(3*time.Minute, 10*time.Minute)
contexts := NewCachedUserContexts(NewCacheConfig())
if contexts.cache == nil {
t.Fatal("cache is not initialized.")
t.Fatal("Cache is not initialized.")
}

if contexts.cache.ItemCount() > 0 {
t.Fatal("some value is stored by default.")
t.Fatal("Some value is stored by default.")
}
}

func TestCachedUserContexts_CRUD(t *testing.T) {
contexts := NewCachedUserContexts(3*time.Minute, 10*time.Minute)
contexts := NewCachedUserContexts(NewCacheConfig())

key := "myKey"
if empty := contexts.Get(key); empty != nil {
if empty, _ := contexts.Get(key); empty != nil {
t.Fatalf("nil should return on empty cache. %#v.", empty)
}

contexts.Set(key, NewUserContext(func(ctx context.Context, input Input) (*CommandResponse, error) { return nil, nil }))
if val := contexts.Get(key); val == nil {
t.Fatal("expected value is not stored")
if val, _ := contexts.Get(key); val == nil {
t.Fatal("Expected value is not stored.")
}

contexts.Delete(key)
if empty := contexts.Get(key); empty != nil {
if empty, _ := contexts.Get(key); empty != nil {
t.Fatalf("nil should return after cache deletion. %#v.", empty)
}

contexts.Set(key, NewUserContext(func(ctx context.Context, input Input) (*CommandResponse, error) { return nil, nil }))
contexts.Flush()
if contexts.cache.ItemCount() > 0 {
t.Fatal("some value is stored after flush.")
t.Fatal("Some value is stored after flush.")
}

invalidKey := "invalidStoredType"
contexts.cache.Set(invalidKey, &struct{}{}, 10*time.Second)
invalidVal, getErr := contexts.Get(invalidKey)
if getErr == nil {
t.Error("Error must be returnd for invalid stored value.")
}
if invalidVal != nil {
t.Errorf("Invalid stored value shouldn't be returned: %T", invalidVal)
}
}
8 changes: 5 additions & 3 deletions runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import (
)

type Config struct {
Worker *worker.Config
Worker *worker.Config
CacheConfig *CacheConfig
}

func NewConfig() *Config {
return &Config{
Worker: worker.NewConfig(),
Worker: worker.NewConfig(),
CacheConfig: NewCacheConfig(),
}
}

Expand Down Expand Up @@ -58,7 +60,7 @@ func (runner *Runner) RegisterAdapter(adapter Adapter, pluginConfigDir string) {
}
}

bot := newBot(adapter, pluginConfigDir)
bot := newBot(adapter, runner.config.CacheConfig, pluginConfigDir)
runner.RegisterBot(bot)
}

Expand Down

0 comments on commit 1b094eb

Please sign in to comment.