1 package diskv
2
3 import (
4 "bytes"
5 "errors"
6 "testing"
7 "time"
8 )
9
10 func cmpBytes(a, b []byte) bool {
11 if len(a) != len(b) {
12 return false
13 }
14 for i := 0; i < len(a); i++ {
15 if a[i] != b[i] {
16 return false
17 }
18 }
19 return true
20 }
21
22 func (d *Diskv) isCached(key string) bool {
23 d.mu.RLock()
24 defer d.mu.RUnlock()
25 _, ok := d.cache[key]
26 return ok
27 }
28
29 func TestWriteReadErase(t *testing.T) {
30 d := New(Options{
31 BasePath: "test-data",
32 CacheSizeMax: 1024,
33 })
34 defer d.EraseAll()
35 k, v := "a", []byte{'b'}
36 if err := d.Write(k, v); err != nil {
37 t.Fatalf("write: %s", err)
38 }
39 if readVal, err := d.Read(k); err != nil {
40 t.Fatalf("read: %s", err)
41 } else if bytes.Compare(v, readVal) != 0 {
42 t.Fatalf("read: expected %s, got %s", v, readVal)
43 }
44 if err := d.Erase(k); err != nil {
45 t.Fatalf("erase: %s", err)
46 }
47 }
48
49 func TestWRECache(t *testing.T) {
50 d := New(Options{
51 BasePath: "test-data",
52 CacheSizeMax: 1024,
53 })
54 defer d.EraseAll()
55 k, v := "xxx", []byte{' ', ' ', ' '}
56 if d.isCached(k) {
57 t.Fatalf("key cached before Write and Read")
58 }
59 if err := d.Write(k, v); err != nil {
60 t.Fatalf("write: %s", err)
61 }
62 if d.isCached(k) {
63 t.Fatalf("key cached before Read")
64 }
65 if readVal, err := d.Read(k); err != nil {
66 t.Fatalf("read: %s", err)
67 } else if bytes.Compare(v, readVal) != 0 {
68 t.Fatalf("read: expected %s, got %s", v, readVal)
69 }
70 for i := 0; i < 10 && !d.isCached(k); i++ {
71 time.Sleep(10 * time.Millisecond)
72 }
73 if !d.isCached(k) {
74 t.Fatalf("key not cached after Read")
75 }
76 if err := d.Erase(k); err != nil {
77 t.Fatalf("erase: %s", err)
78 }
79 if d.isCached(k) {
80 t.Fatalf("key cached after Erase")
81 }
82 }
83
84 func TestStrings(t *testing.T) {
85 d := New(Options{
86 BasePath: "test-data",
87 CacheSizeMax: 1024,
88 })
89 defer d.EraseAll()
90
91 keys := map[string]bool{"a": false, "b": false, "c": false, "d": false}
92 v := []byte{'1'}
93 for k := range keys {
94 if err := d.Write(k, v); err != nil {
95 t.Fatalf("write: %s: %s", k, err)
96 }
97 }
98
99 for k := range d.Keys(nil) {
100 if _, present := keys[k]; present {
101 t.Logf("got: %s", k)
102 keys[k] = true
103 } else {
104 t.Fatalf("strings() returns unknown key: %s", k)
105 }
106 }
107
108 for k, found := range keys {
109 if !found {
110 t.Errorf("never got %s", k)
111 }
112 }
113 }
114
115 func TestZeroByteCache(t *testing.T) {
116 d := New(Options{
117 BasePath: "test-data",
118 CacheSizeMax: 0,
119 })
120 defer d.EraseAll()
121
122 k, v := "a", []byte{'1', '2', '3'}
123 if err := d.Write(k, v); err != nil {
124 t.Fatalf("Write: %s", err)
125 }
126
127 if d.isCached(k) {
128 t.Fatalf("key cached, expected not-cached")
129 }
130
131 if _, err := d.Read(k); err != nil {
132 t.Fatalf("Read: %s", err)
133 }
134
135 if d.isCached(k) {
136 t.Fatalf("key cached, expected not-cached")
137 }
138 }
139
140 func TestOneByteCache(t *testing.T) {
141 d := New(Options{
142 BasePath: "test-data",
143 CacheSizeMax: 1,
144 })
145 defer d.EraseAll()
146
147 k1, k2, v1, v2 := "a", "b", []byte{'1'}, []byte{'1', '2'}
148 if err := d.Write(k1, v1); err != nil {
149 t.Fatal(err)
150 }
151
152 if v, err := d.Read(k1); err != nil {
153 t.Fatal(err)
154 } else if !cmpBytes(v, v1) {
155 t.Fatalf("Read: expected %s, got %s", string(v1), string(v))
156 }
157
158 for i := 0; i < 10 && !d.isCached(k1); i++ {
159 time.Sleep(10 * time.Millisecond)
160 }
161 if !d.isCached(k1) {
162 t.Fatalf("expected 1-byte value to be cached, but it wasn't")
163 }
164
165 if err := d.Write(k2, v2); err != nil {
166 t.Fatal(err)
167 }
168 if _, err := d.Read(k2); err != nil {
169 t.Fatalf("--> %s", err)
170 }
171
172 for i := 0; i < 10 && (!d.isCached(k1) || d.isCached(k2)); i++ {
173 time.Sleep(10 * time.Millisecond)
174 }
175 if !d.isCached(k1) {
176 t.Fatalf("1-byte value was uncached for no reason")
177 }
178
179 if d.isCached(k2) {
180 t.Fatalf("2-byte value was cached, but cache max size is 1")
181 }
182 }
183
184 func TestStaleCache(t *testing.T) {
185 d := New(Options{
186 BasePath: "test-data",
187 CacheSizeMax: 1,
188 })
189 defer d.EraseAll()
190
191 k, first, second := "a", "first", "second"
192 if err := d.Write(k, []byte(first)); err != nil {
193 t.Fatal(err)
194 }
195
196 v, err := d.Read(k)
197 if err != nil {
198 t.Fatal(err)
199 }
200 if string(v) != first {
201 t.Errorf("expected '%s', got '%s'", first, v)
202 }
203
204 if err := d.Write(k, []byte(second)); err != nil {
205 t.Fatal(err)
206 }
207
208 v, err = d.Read(k)
209 if err != nil {
210 t.Fatal(err)
211 }
212
213 if string(v) != second {
214 t.Errorf("expected '%s', got '%s'", second, v)
215 }
216 }
217
218 func TestHas(t *testing.T) {
219 d := New(Options{
220 BasePath: "test-data",
221 CacheSizeMax: 1024,
222 })
223 defer d.EraseAll()
224
225 for k, v := range map[string]string{
226 "a": "1",
227 "foo": "2",
228 "012345": "3",
229 } {
230 d.Write(k, []byte(v))
231 }
232
233 d.Read("foo")
234 if !d.isCached("foo") {
235 t.Errorf("'foo' didn't get cached")
236 }
237
238 for _, tuple := range []struct {
239 key string
240 expected bool
241 }{
242 {"a", true},
243 {"b", false},
244 {"foo", true},
245 {"bar", false},
246 {"01234", false},
247 {"012345", true},
248 {"0123456", false},
249 } {
250 if expected, got := tuple.expected, d.Has(tuple.key); expected != got {
251 t.Errorf("Has(%s): expected %v, got %v", tuple.key, expected, got)
252 }
253 }
254 }
255
256 type BrokenReader struct{}
257
258 func (BrokenReader) Read(p []byte) (n int, err error) {
259 return 0, errors.New("failed to read")
260 }
261
262 func TestRemovesIncompleteFiles(t *testing.T) {
263 opts := Options{
264 BasePath: "test-data",
265 CacheSizeMax: 1024,
266 }
267 d := New(opts)
268 defer d.EraseAll()
269
270 key, stream, sync := "key", BrokenReader{}, false
271
272 if err := d.WriteStream(key, stream, sync); err == nil {
273 t.Fatalf("Expected i/o copy error, none received.")
274 }
275
276 if _, err := d.Read(key); err == nil {
277 t.Fatal("Could read the key, but it shouldn't exist")
278 }
279 }
280
281 func TestTempDir(t *testing.T) {
282 opts := Options{
283 BasePath: "test-data",
284 TempDir: "test-data-temp",
285 CacheSizeMax: 1024,
286 }
287 d := New(opts)
288 defer d.EraseAll()
289
290 k, v := "a", []byte{'b'}
291 if err := d.Write(k, v); err != nil {
292 t.Fatalf("write: %s", err)
293 }
294 if readVal, err := d.Read(k); err != nil {
295 t.Fatalf("read: %s", err)
296 } else if bytes.Compare(v, readVal) != 0 {
297 t.Fatalf("read: expected %s, got %s", v, readVal)
298 }
299 if err := d.Erase(k); err != nil {
300 t.Fatalf("erase: %s", err)
301 }
302 }
303
304 type CrashingReader struct{}
305
306 func (CrashingReader) Read(p []byte) (n int, err error) {
307 panic("System has crashed while reading the stream")
308 }
309
310 func TestAtomicWrite(t *testing.T) {
311 opts := Options{
312 BasePath: "test-data",
313
314 TempDir: "test-data-temp",
315 CacheSizeMax: 1024,
316 }
317 d := New(opts)
318 defer d.EraseAll()
319
320 key := "key"
321 func() {
322 defer func() {
323 recover()
324 }()
325
326 stream := CrashingReader{}
327 d.WriteStream(key, stream, false)
328 }()
329
330 if d.Has(key) {
331 t.Fatal("Has key, but it shouldn't exist")
332 }
333 if _, ok := <-d.Keys(nil); ok {
334 t.Fatal("Store isn't empty")
335 }
336 }
337
View as plain text