toolbox/kvmemcache/cache_test.go

150 lines
2.6 KiB
Go
Raw Normal View History

2021-04-02 15:14:32 +00:00
package kvmemcache
import (
2021-04-06 06:58:17 +00:00
"errors"
2021-04-02 15:14:32 +00:00
"fmt"
"testing"
"time"
)
2021-04-06 06:58:17 +00:00
type State struct {
Keys []string
Stats Stats
}
2021-04-02 15:14:32 +00:00
2021-04-06 06:58:17 +00:00
func (c *Cache) assert(state State) error {
c.lock.Lock()
defer c.lock.Unlock()
2021-04-02 15:14:32 +00:00
2021-04-06 06:58:17 +00:00
if len(c.cache) != len(state.Keys) {
return fmt.Errorf(
"Expected %d keys but found %d.",
len(state.Keys),
len(c.cache))
}
2021-04-02 15:14:32 +00:00
2021-04-06 06:58:17 +00:00
for _, k := range state.Keys {
if _, ok := c.cache[k]; !ok {
return fmt.Errorf(
"Expected key %s not found.",
k)
2021-04-02 15:14:32 +00:00
}
}
2021-04-06 06:58:17 +00:00
if c.stats.Hits != state.Stats.Hits {
return fmt.Errorf(
"Expected %d hits, but found %d.",
state.Stats.Hits,
c.stats.Hits)
2021-04-02 15:14:32 +00:00
}
2021-04-06 06:58:17 +00:00
if c.stats.Misses != state.Stats.Misses {
return fmt.Errorf(
"Expected %d misses, but found %d.",
state.Stats.Misses,
c.stats.Misses)
2021-04-02 15:14:32 +00:00
}
2021-04-06 06:58:17 +00:00
return nil
2021-04-02 15:14:32 +00:00
}
2021-04-06 06:58:17 +00:00
var TestError = errors.New("Hello")
2021-04-02 18:57:08 +00:00
2021-04-06 06:58:17 +00:00
func TestCache_Basic(t *testing.T) {
2021-04-02 18:57:08 +00:00
c := New(Config{
2021-04-06 06:58:17 +00:00
MaxSize: 4,
TTL: 50 * time.Millisecond,
2021-04-02 18:57:08 +00:00
Src: func(key string) (interface{}, error) {
2021-04-06 06:58:17 +00:00
if key == "err" {
return nil, TestError
}
2021-04-02 18:57:08 +00:00
return key, nil
},
})
2021-04-06 06:58:17 +00:00
type testCase struct {
name string
sleep time.Duration
key string
state State
}
2021-04-02 18:57:08 +00:00
2021-04-06 06:58:17 +00:00
cases := []testCase{
{
name: "get a",
key: "a",
state: State{
Keys: []string{"a"},
Stats: Stats{Hits: 0, Misses: 1},
},
}, {
name: "get a again",
key: "a",
state: State{
Keys: []string{"a"},
Stats: Stats{Hits: 1, Misses: 1},
},
}, {
name: "sleep, then get a again",
sleep: 55 * time.Millisecond,
key: "a",
state: State{
Keys: []string{"a"},
Stats: Stats{Hits: 1, Misses: 2},
},
}, {
name: "get b",
key: "b",
state: State{
Keys: []string{"a", "b"},
Stats: Stats{Hits: 1, Misses: 3},
},
}, {
name: "get c",
key: "c",
state: State{
Keys: []string{"a", "b", "c"},
Stats: Stats{Hits: 1, Misses: 4},
},
}, {
name: "get d",
key: "d",
state: State{
Keys: []string{"a", "b", "c", "d"},
Stats: Stats{Hits: 1, Misses: 5},
},
}, {
name: "get e",
key: "e",
state: State{
Keys: []string{"b", "c", "d", "e"},
Stats: Stats{Hits: 1, Misses: 6},
},
}, {
name: "get c again",
key: "c",
state: State{
Keys: []string{"b", "c", "d", "e"},
Stats: Stats{Hits: 2, Misses: 6},
},
},
2021-04-02 18:57:08 +00:00
}
2021-04-06 06:58:17 +00:00
for _, tc := range cases {
time.Sleep(tc.sleep)
val, err := c.Get(tc.key)
if tc.key == "err" && err != TestError {
t.Fatal(tc.name, val)
}
if tc.key != "err" && val.(string) != tc.key {
t.Fatal(tc.name, tc.key, val)
}
2021-04-02 18:57:08 +00:00
2021-04-06 06:58:17 +00:00
if err := c.assert(tc.state); err != nil {
t.Fatal(err)
}
2021-04-02 18:57:08 +00:00
}
}
2021-04-06 06:58:17 +00:00
// TODO: Test thundering herd mitigation.