1package physical
2
3import (
4	"context"
5	"reflect"
6	"sort"
7	"testing"
8	"time"
9)
10
11func ExerciseBackend(t testing.TB, b Backend) {
12	t.Helper()
13
14	// Should be empty
15	keys, err := b.List(context.Background(), "")
16	if err != nil {
17		t.Fatalf("initial list failed: %v", err)
18	}
19	if len(keys) != 0 {
20		t.Errorf("initial not empty: %v", keys)
21	}
22
23	// Delete should work if it does not exist
24	err = b.Delete(context.Background(), "foo")
25	if err != nil {
26		t.Fatalf("idempotent delete: %v", err)
27	}
28
29	// Get should not fail, but be nil
30	out, err := b.Get(context.Background(), "foo")
31	if err != nil {
32		t.Fatalf("initial get failed: %v", err)
33	}
34	if out != nil {
35		t.Errorf("initial get was not nil: %v", out)
36	}
37
38	// Make an entry
39	e := &Entry{Key: "foo", Value: []byte("test")}
40	err = b.Put(context.Background(), e)
41	if err != nil {
42		t.Fatalf("put failed: %v", err)
43	}
44
45	// Get should work
46	out, err = b.Get(context.Background(), "foo")
47	if err != nil {
48		t.Fatalf("get failed: %v", err)
49	}
50	if !reflect.DeepEqual(out, e) {
51		t.Errorf("bad: %v expected: %v", out, e)
52	}
53
54	// List should not be empty
55	keys, err = b.List(context.Background(), "")
56	if err != nil {
57		t.Fatalf("list failed: %v", err)
58	}
59	if len(keys) != 1 || keys[0] != "foo" {
60		t.Errorf("keys[0] did not equal foo: %v", keys)
61	}
62
63	// Delete should work
64	err = b.Delete(context.Background(), "foo")
65	if err != nil {
66		t.Fatalf("delete: %v", err)
67	}
68
69	// Should be empty
70	keys, err = b.List(context.Background(), "")
71	if err != nil {
72		t.Fatalf("list after delete: %v", err)
73	}
74	if len(keys) != 0 {
75		t.Errorf("list after delete not empty: %v", keys)
76	}
77
78	// Get should fail
79	out, err = b.Get(context.Background(), "foo")
80	if err != nil {
81		t.Fatalf("get after delete: %v", err)
82	}
83	if out != nil {
84		t.Errorf("get after delete not nil: %v", out)
85	}
86
87	// Multiple Puts should work; GH-189
88	e = &Entry{Key: "foo", Value: []byte("test")}
89	err = b.Put(context.Background(), e)
90	if err != nil {
91		t.Fatalf("multi put 1 failed: %v", err)
92	}
93	e = &Entry{Key: "foo", Value: []byte("test")}
94	err = b.Put(context.Background(), e)
95	if err != nil {
96		t.Fatalf("multi put 2 failed: %v", err)
97	}
98
99	// Make a nested entry
100	e = &Entry{Key: "foo/bar", Value: []byte("baz")}
101	err = b.Put(context.Background(), e)
102	if err != nil {
103		t.Fatalf("nested put failed: %v", err)
104	}
105
106	// Get should work
107	out, err = b.Get(context.Background(), "foo/bar")
108	if err != nil {
109		t.Fatalf("get failed: %v", err)
110	}
111	if !reflect.DeepEqual(out, e) {
112		t.Errorf("bad: %v expected: %v", out, e)
113	}
114
115	keys, err = b.List(context.Background(), "")
116	if err != nil {
117		t.Fatalf("list multi failed: %v", err)
118	}
119	sort.Strings(keys)
120	if len(keys) != 2 || keys[0] != "foo" || keys[1] != "foo/" {
121		t.Errorf("expected 2 keys [foo, foo/]: %v", keys)
122	}
123
124	// Delete with children should work
125	err = b.Delete(context.Background(), "foo")
126	if err != nil {
127		t.Fatalf("delete after multi: %v", err)
128	}
129
130	// Get should return the child
131	out, err = b.Get(context.Background(), "foo/bar")
132	if err != nil {
133		t.Fatalf("get after multi delete: %v", err)
134	}
135	if out == nil {
136		t.Errorf("get after multi delete not nil: %v", out)
137	}
138
139	// Removal of nested secret should not leave artifacts
140	e = &Entry{Key: "foo/nested1/nested2/nested3", Value: []byte("baz")}
141	err = b.Put(context.Background(), e)
142	if err != nil {
143		t.Fatalf("deep nest: %v", err)
144	}
145
146	err = b.Delete(context.Background(), "foo/nested1/nested2/nested3")
147	if err != nil {
148		t.Fatalf("failed to remove deep nest: %v", err)
149	}
150
151	keys, err = b.List(context.Background(), "foo/")
152	if err != nil {
153		t.Fatalf("err: %v", err)
154	}
155	if len(keys) != 1 || keys[0] != "bar" {
156		t.Errorf("should be exactly 1 key == bar: %v", keys)
157	}
158
159	// Make a second nested entry to test prefix removal
160	e = &Entry{Key: "foo/zip", Value: []byte("zap")}
161	err = b.Put(context.Background(), e)
162	if err != nil {
163		t.Fatalf("failed to create second nested: %v", err)
164	}
165
166	// Delete should not remove the prefix
167	err = b.Delete(context.Background(), "foo/bar")
168	if err != nil {
169		t.Fatalf("failed to delete nested prefix: %v", err)
170	}
171
172	keys, err = b.List(context.Background(), "")
173	if err != nil {
174		t.Fatalf("list nested prefix: %v", err)
175	}
176	if len(keys) != 1 || keys[0] != "foo/" {
177		t.Errorf("should be exactly 1 key == foo/: %v", keys)
178	}
179
180	// Delete should remove the prefix
181	err = b.Delete(context.Background(), "foo/zip")
182	if err != nil {
183		t.Fatalf("failed to delete second prefix: %v", err)
184	}
185
186	keys, err = b.List(context.Background(), "")
187	if err != nil {
188		t.Fatalf("listing after second delete failed: %v", err)
189	}
190	if len(keys) != 0 {
191		t.Errorf("should be empty at end: %v", keys)
192	}
193
194	// When the root path is empty, adding and removing deep nested values should not break listing
195	e = &Entry{Key: "foo/nested1/nested2/value1", Value: []byte("baz")}
196	err = b.Put(context.Background(), e)
197	if err != nil {
198		t.Fatalf("deep nest: %v", err)
199	}
200
201	e = &Entry{Key: "foo/nested1/nested2/value2", Value: []byte("baz")}
202	err = b.Put(context.Background(), e)
203	if err != nil {
204		t.Fatalf("deep nest: %v", err)
205	}
206
207	err = b.Delete(context.Background(), "foo/nested1/nested2/value2")
208	if err != nil {
209		t.Fatalf("failed to remove deep nest: %v", err)
210	}
211
212	keys, err = b.List(context.Background(), "")
213	if err != nil {
214		t.Fatalf("listing of root failed after deletion: %v", err)
215	}
216	if len(keys) == 0 {
217		t.Errorf("root is returning empty after deleting a single nested value, expected nested1/: %v", keys)
218		keys, err = b.List(context.Background(), "foo/nested1")
219		if err != nil {
220			t.Fatalf("listing of expected nested path 'foo/nested1' failed: %v", err)
221		}
222		// prove that the root should not be empty and that foo/nested1 exists
223		if len(keys) != 0 {
224			t.Logf("  keys can still be listed from nested1/ so it's not empty, expected nested2/: %v", keys)
225		}
226	}
227
228	// cleanup left over listing bug test value
229	err = b.Delete(context.Background(), "foo/nested1/nested2/value1")
230	if err != nil {
231		t.Fatalf("failed to remove deep nest: %v", err)
232	}
233
234	keys, err = b.List(context.Background(), "")
235	if err != nil {
236		t.Fatalf("listing of root failed after delete of deep nest: %v", err)
237	}
238	if len(keys) != 0 {
239		t.Errorf("should be empty at end: %v", keys)
240	}
241}
242
243func ExerciseBackend_ListPrefix(t testing.TB, b Backend) {
244	t.Helper()
245
246	e1 := &Entry{Key: "foo", Value: []byte("test")}
247	e2 := &Entry{Key: "foo/bar", Value: []byte("test")}
248	e3 := &Entry{Key: "foo/bar/baz", Value: []byte("test")}
249
250	defer func() {
251		b.Delete(context.Background(), "foo")
252		b.Delete(context.Background(), "foo/bar")
253		b.Delete(context.Background(), "foo/bar/baz")
254	}()
255
256	err := b.Put(context.Background(), e1)
257	if err != nil {
258		t.Fatalf("failed to put entry 1: %v", err)
259	}
260	err = b.Put(context.Background(), e2)
261	if err != nil {
262		t.Fatalf("failed to put entry 2: %v", err)
263	}
264	err = b.Put(context.Background(), e3)
265	if err != nil {
266		t.Fatalf("failed to put entry 3: %v", err)
267	}
268
269	// Scan the root
270	keys, err := b.List(context.Background(), "")
271	if err != nil {
272		t.Fatalf("list root: %v", err)
273	}
274	sort.Strings(keys)
275	if len(keys) != 2 || keys[0] != "foo" || keys[1] != "foo/" {
276		t.Errorf("root expected [foo foo/]: %v", keys)
277	}
278
279	// Scan foo/
280	keys, err = b.List(context.Background(), "foo/")
281	if err != nil {
282		t.Fatalf("list level 1: %v", err)
283	}
284	sort.Strings(keys)
285	if len(keys) != 2 || keys[0] != "bar" || keys[1] != "bar/" {
286		t.Errorf("level 1 expected [bar bar/]: %v", keys)
287	}
288
289	// Scan foo/bar/
290	keys, err = b.List(context.Background(), "foo/bar/")
291	if err != nil {
292		t.Fatalf("list level 2: %v", err)
293	}
294	sort.Strings(keys)
295	if len(keys) != 1 || keys[0] != "baz" {
296		t.Errorf("level 1 expected [baz]: %v", keys)
297	}
298}
299
300func ExerciseHABackend(t testing.TB, b HABackend, b2 HABackend) {
301	t.Helper()
302
303	// Get the lock
304	lock, err := b.LockWith("foo", "bar")
305	if err != nil {
306		t.Fatalf("initial lock: %v", err)
307	}
308
309	// Attempt to lock
310	leaderCh, err := lock.Lock(nil)
311	if err != nil {
312		t.Fatalf("lock attempt 1: %v", err)
313	}
314	if leaderCh == nil {
315		t.Fatalf("missing leaderCh")
316	}
317
318	// Check the value
319	held, val, err := lock.Value()
320	if err != nil {
321		t.Fatalf("err: %v", err)
322	}
323	if !held {
324		t.Errorf("should be held")
325	}
326	if val != "bar" {
327		t.Errorf("expected value bar: %v", err)
328	}
329
330	// Second acquisition should fail
331	lock2, err := b2.LockWith("foo", "baz")
332	if err != nil {
333		t.Fatalf("lock 2: %v", err)
334	}
335
336	// Cancel attempt in 50 msec
337	stopCh := make(chan struct{})
338	time.AfterFunc(50*time.Millisecond, func() {
339		close(stopCh)
340	})
341
342	// Attempt to lock
343	leaderCh2, err := lock2.Lock(stopCh)
344	if err != nil {
345		t.Fatalf("stop lock 2: %v", err)
346	}
347	if leaderCh2 != nil {
348		t.Errorf("should not have gotten leaderCh: %v", leaderCh2)
349	}
350
351	// Release the first lock
352	lock.Unlock()
353
354	// Attempt to lock should work
355	leaderCh2, err = lock2.Lock(nil)
356	if err != nil {
357		t.Fatalf("lock 2 lock: %v", err)
358	}
359	if leaderCh2 == nil {
360		t.Errorf("should get leaderCh")
361	}
362
363	// Check the value
364	held, val, err = lock2.Value()
365	if err != nil {
366		t.Fatalf("value: %v", err)
367	}
368	if !held {
369		t.Errorf("should still be held")
370	}
371	if val != "baz" {
372		t.Errorf("expected: baz, got: %v", val)
373	}
374
375	// Cleanup
376	lock2.Unlock()
377}
378
379func ExerciseTransactionalBackend(t testing.TB, b Backend) {
380	t.Helper()
381	tb, ok := b.(Transactional)
382	if !ok {
383		t.Fatal("Not a transactional backend")
384	}
385
386	txns := SetupTestingTransactions(t, b)
387
388	if err := tb.Transaction(context.Background(), txns); err != nil {
389		t.Fatal(err)
390	}
391
392	keys, err := b.List(context.Background(), "")
393	if err != nil {
394		t.Fatal(err)
395	}
396
397	expected := []string{"foo", "zip"}
398
399	sort.Strings(keys)
400	sort.Strings(expected)
401	if !reflect.DeepEqual(keys, expected) {
402		t.Fatalf("mismatch: expected\n%#v\ngot\n%#v\n", expected, keys)
403	}
404
405	entry, err := b.Get(context.Background(), "foo")
406	if err != nil {
407		t.Fatal(err)
408	}
409	if entry == nil {
410		t.Fatal("got nil entry")
411	}
412	if entry.Value == nil {
413		t.Fatal("got nil value")
414	}
415	if string(entry.Value) != "bar3" {
416		t.Fatal("updates did not apply correctly")
417	}
418
419	entry, err = b.Get(context.Background(), "zip")
420	if err != nil {
421		t.Fatal(err)
422	}
423	if entry == nil {
424		t.Fatal("got nil entry")
425	}
426	if entry.Value == nil {
427		t.Fatal("got nil value")
428	}
429	if string(entry.Value) != "zap3" {
430		t.Fatal("updates did not apply correctly")
431	}
432}
433
434func SetupTestingTransactions(t testing.TB, b Backend) []*TxnEntry {
435	t.Helper()
436	// Add a few keys so that we test rollback with deletion
437	if err := b.Put(context.Background(), &Entry{
438		Key:   "foo",
439		Value: []byte("bar"),
440	}); err != nil {
441		t.Fatal(err)
442	}
443	if err := b.Put(context.Background(), &Entry{
444		Key:   "zip",
445		Value: []byte("zap"),
446	}); err != nil {
447		t.Fatal(err)
448	}
449	if err := b.Put(context.Background(), &Entry{
450		Key: "deleteme",
451	}); err != nil {
452		t.Fatal(err)
453	}
454	if err := b.Put(context.Background(), &Entry{
455		Key: "deleteme2",
456	}); err != nil {
457		t.Fatal(err)
458	}
459
460	txns := []*TxnEntry{
461		&TxnEntry{
462			Operation: PutOperation,
463			Entry: &Entry{
464				Key:   "foo",
465				Value: []byte("bar2"),
466			},
467		},
468		&TxnEntry{
469			Operation: DeleteOperation,
470			Entry: &Entry{
471				Key: "deleteme",
472			},
473		},
474		&TxnEntry{
475			Operation: PutOperation,
476			Entry: &Entry{
477				Key:   "foo",
478				Value: []byte("bar3"),
479			},
480		},
481		&TxnEntry{
482			Operation: DeleteOperation,
483			Entry: &Entry{
484				Key: "deleteme2",
485			},
486		},
487		&TxnEntry{
488			Operation: PutOperation,
489			Entry: &Entry{
490				Key:   "zip",
491				Value: []byte("zap3"),
492			},
493		},
494	}
495
496	return txns
497}
498