Skip to content

Commit eeec324

Browse files
authored
increase code coverage (#152)
* unit tests for transaction_registry_redis * replacing mocks with miniredis * add redis_cache tests * increase code coverage * increase coverage * increase config code coverage * fix from PR's comments * add mistaken conf tests * fix negative config tests Co-authored-by: christophe.kalenzaga <[email protected]>
1 parent c859f2a commit eeec324

9 files changed

+639
-222
lines changed

cache/async_cache.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package cache
22

33
import (
4+
"fmt"
5+
"time"
6+
47
"github.com/contentsquare/chproxy/clients"
58
"github.com/contentsquare/chproxy/config"
69
"github.com/go-redis/redis/v8"
7-
"time"
810
)
911

1012
// AsyncCache is a transactional cache allowing the results from concurrent queries.
@@ -79,6 +81,8 @@ func NewAsyncCache(cfg config.Cache) (*AsyncCache, error) {
7981
redisClient, err = clients.NewRedisClient(cfg.Redis)
8082
cache = newRedisCache(redisClient, cfg)
8183
transaction = newRedisTransactionRegistry(redisClient, time.Duration(cfg.GraceTime))
84+
default:
85+
return nil, fmt.Errorf("unknown config mode")
8286
}
8387

8488
if err != nil {

cache/async_cache_test.go

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package cache
22

33
import (
4-
"github.com/contentsquare/chproxy/config"
4+
"log"
55
"os"
66
"testing"
77
"time"
8+
9+
"github.com/alicebob/miniredis/v2"
10+
"github.com/contentsquare/chproxy/config"
811
)
912

1013
const asyncTestDir = "./async-test-data"
@@ -134,3 +137,86 @@ func newAsyncTestCache(t *testing.T, graceTime time.Duration) *AsyncCache {
134137
}
135138
return asyncC
136139
}
140+
141+
func TestAsyncCache_FilesystemCache_instantiation(t *testing.T) {
142+
const testDirAsync = "./test-data-async"
143+
fileSystemCfg := config.Cache{
144+
Name: "test",
145+
Mode: "file_system",
146+
FileSystem: config.FileSystemCacheConfig{
147+
Dir: asyncTestDir,
148+
MaxSize: 8192,
149+
},
150+
Expire: config.Duration(time.Minute),
151+
}
152+
if err := os.RemoveAll(testDirAsync); err != nil {
153+
log.Fatalf("cannot remove %q: %s", testDirAsync, err)
154+
}
155+
_, err := NewAsyncCache(fileSystemCfg)
156+
if err != nil {
157+
t.Fatalf("could not instanciate filsystem async cache because of the following error: %s", err)
158+
}
159+
}
160+
161+
func TestAsyncCache_FilesystemCache_wrong_instantiation(t *testing.T) {
162+
fileSystemCfg := config.Cache{
163+
Name: "test",
164+
Mode: "file_system",
165+
FileSystem: config.FileSystemCacheConfig{
166+
Dir: "",
167+
MaxSize: 8192,
168+
},
169+
Expire: config.Duration(time.Minute),
170+
}
171+
_, err := NewAsyncCache(fileSystemCfg)
172+
if err == nil {
173+
t.Fatalf("the instanciate of filsystem async cache should have crashed")
174+
}
175+
}
176+
177+
func TestAsyncCache_RedisCache_instantiation(t *testing.T) {
178+
s := miniredis.RunT(t)
179+
var redisCfg = config.Cache{
180+
Name: "test",
181+
Mode: "redis",
182+
Redis: config.RedisCacheConfig{
183+
Addresses: []string{s.Addr()},
184+
},
185+
Expire: config.Duration(cacheTTL),
186+
}
187+
188+
_, err := NewAsyncCache(redisCfg)
189+
if err != nil {
190+
t.Fatalf("could not instanciate redis async cache because of the following error: %s", err)
191+
}
192+
}
193+
194+
func TestAsyncCache_RedisCache_wrong_instantiation(t *testing.T) {
195+
var redisCfg = config.Cache{
196+
Name: "test",
197+
Mode: "redis",
198+
Redis: config.RedisCacheConfig{
199+
// fake address
200+
Addresses: []string{"127.12.0.10:1024"},
201+
},
202+
}
203+
204+
_, err := NewAsyncCache(redisCfg)
205+
if err == nil {
206+
t.Fatalf("the redis instanciation should have crashed")
207+
}
208+
}
209+
210+
func TestAsyncCache_Unkown_instantiation(t *testing.T) {
211+
var redisCfg = config.Cache{
212+
Name: "test",
213+
Mode: "Unkown Mode",
214+
Redis: config.RedisCacheConfig{},
215+
Expire: config.Duration(cacheTTL),
216+
}
217+
218+
_, err := NewAsyncCache(redisCfg)
219+
if err == nil {
220+
t.Fatalf("The instanciation should have crash")
221+
}
222+
}

cache/filesystem_cache_test.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,16 @@ func TestCacheClose(t *testing.T) {
4747
}
4848
}
4949

50-
func TestCacheAddGet(t *testing.T) {
50+
func TestFilesystemCacheAddGet(t *testing.T) {
5151
c := newTestCache(t)
5252
defer c.Close()
53+
c1 := newTestCache(t)
54+
defer c1.Close()
55+
cacheAddGetHelper(t, c, c1)
56+
}
57+
58+
// metatest used for both filesystem and redis Cache
59+
func cacheAddGetHelper(t *testing.T, c Cache, c1 Cache) {
5360

5461
for i := 0; i < 10; i++ {
5562
key := &Key{
@@ -104,9 +111,6 @@ func TestCacheAddGet(t *testing.T) {
104111
}
105112

106113
// Verify the cache may be re-opened.
107-
c1 := newTestCache(t)
108-
defer c1.Close()
109-
110114
for i := 0; i < 10; i++ {
111115
key := &Key{
112116
Query: []byte(fmt.Sprintf("SELECT %d", i)),
@@ -141,10 +145,14 @@ func TestCacheAddGet(t *testing.T) {
141145
}
142146
}
143147

144-
func TestCacheMiss(t *testing.T) {
148+
func TestFilesystemCacheMiss(t *testing.T) {
145149
c := newTestCache(t)
146150
defer c.Close()
151+
cacheMissHelper(t, c)
152+
}
147153

154+
// metatest used for both filesystem and redis Cache
155+
func cacheMissHelper(t *testing.T, c Cache) {
148156
for i := 0; i < 10; i++ {
149157
key := &Key{
150158
Query: []byte(fmt.Sprintf("SELECT %d cache miss", i)),

cache/redis_cache_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package cache
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/alicebob/miniredis/v2"
8+
"github.com/go-redis/redis/v8"
9+
10+
"github.com/contentsquare/chproxy/config"
11+
)
12+
13+
const cacheTTL = time.Duration(10 * time.Second)
14+
15+
var redisConf = config.Cache{
16+
Name: "foobar",
17+
Redis: config.RedisCacheConfig{
18+
Addresses: []string{"http://localhost:8080"},
19+
},
20+
Expire: config.Duration(cacheTTL),
21+
}
22+
23+
func TestCacheSize(t *testing.T) {
24+
redisCache := generateRedisClientAndServer(t)
25+
nbKeys := redisCache.nbOfKeys()
26+
if nbKeys > 0 {
27+
t.Fatalf("the cache should be empty")
28+
}
29+
30+
cacheSize := redisCache.nbOfBytes()
31+
if cacheSize > 0 {
32+
t.Fatalf("the cache should be empty")
33+
}
34+
35+
trw := &testResponseWriter{}
36+
crw := NewBufferedResponseWriter(trw)
37+
buffer := crw.Reader()
38+
39+
if _, err := redisCache.Put(buffer, ContentMetadata{}, &Key{Query: []byte("SELECT 1")}); err != nil {
40+
t.Fatalf("failed to put it to cache: %s", err)
41+
}
42+
if _, err := redisCache.Put(buffer, ContentMetadata{}, &Key{Query: []byte("SELECT 2")}); err != nil {
43+
t.Fatalf("failed to put it to cache: %s", err)
44+
}
45+
if _, err := redisCache.Put(buffer, ContentMetadata{}, &Key{Query: []byte("SELECT 2")}); err != nil {
46+
t.Fatalf("failed to put it to cache: %s", err)
47+
}
48+
49+
stats := redisCache.Stats()
50+
if stats.Items != 2 {
51+
t.Fatalf("cache should contain 2 items")
52+
}
53+
// because of the use of miniredis to simulate a real redis server
54+
// we can't check stats.Size because miniredis doesn't handle the memory usage of redis
55+
}
56+
57+
func generateRedisClientAndServer(t *testing.T) *redisCache {
58+
s := miniredis.RunT(t)
59+
redisClient := redis.NewUniversalClient(&redis.UniversalOptions{
60+
Addrs: []string{s.Addr()},
61+
})
62+
redisCache := newRedisCache(redisClient, redisConf)
63+
return redisCache
64+
}
65+
66+
func TestRedisCacheAddGet(t *testing.T) {
67+
c := generateRedisClientAndServer(t)
68+
c1 := generateRedisClientAndServer(t)
69+
defer func() {
70+
c1.Close()
71+
c.Close()
72+
}()
73+
cacheAddGetHelper(t, c, c1)
74+
}
75+
76+
func TestRedisCacheMiss(t *testing.T) {
77+
c := generateRedisClientAndServer(t)
78+
cacheMissHelper(t, c)
79+
}

cache/transaction_registry_redis.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package cache
22

33
import (
44
"context"
5+
"time"
6+
57
"github.com/contentsquare/chproxy/log"
68
"github.com/go-redis/redis/v8"
7-
"time"
89
)
910

1011
// pendingTransactionVal
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package cache
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/alicebob/miniredis/v2"
8+
"github.com/go-redis/redis/v8"
9+
)
10+
11+
func TestRedisTransaction(t *testing.T) {
12+
s := miniredis.RunT(t)
13+
14+
redisClient := redis.NewUniversalClient(&redis.UniversalOptions{
15+
Addrs: []string{s.Addr()},
16+
})
17+
18+
graceTime := 10 * time.Second
19+
key := &Key{
20+
Query: []byte("SELECT pending entries"),
21+
}
22+
23+
redisTransaction := newRedisTransactionRegistry(redisClient, graceTime)
24+
25+
if err := redisTransaction.Register(key); err != nil {
26+
t.Fatalf("unexpected error: %s while registering new transaction", err)
27+
}
28+
29+
isDone := redisTransaction.IsDone(key)
30+
if isDone {
31+
t.Fatalf("unexpected: transaction should be pending")
32+
}
33+
34+
if err := redisTransaction.Unregister(key); err != nil {
35+
t.Fatalf("unexpected error: %s while unregistering transaction", err)
36+
}
37+
38+
isDone = redisTransaction.IsDone(key)
39+
if !isDone {
40+
t.Fatalf("unexpected: transaction should be done")
41+
}
42+
43+
}

0 commit comments

Comments
 (0)