7939: Move daemonize to _run_standalone() after llfuse.init(), preserving open
[arvados.git] / services / keepstore / handlers_with_generic_volume_test.go
1 package main
2
3 import (
4         "bytes"
5 )
6
7 // A TestableVolumeManagerFactory creates a volume manager with at least two TestableVolume instances.
8 // The factory function, and the TestableVolume instances it returns, can use "t" to write
9 // logs, fail the current test, etc.
10 type TestableVolumeManagerFactory func(t TB) (*RRVolumeManager, []TestableVolume)
11
12 // DoHandlersWithGenericVolumeTests runs a set of handler tests with a
13 // Volume Manager comprised of TestableVolume instances.
14 // It calls factory to create a volume manager with TestableVolume
15 // instances for each test case, to avoid leaking state between tests.
16 func DoHandlersWithGenericVolumeTests(t TB, factory TestableVolumeManagerFactory) {
17         testGetBlock(t, factory, TestHash, TestBlock)
18         testGetBlock(t, factory, EmptyHash, EmptyBlock)
19         testPutRawBadDataGetBlock(t, factory, TestHash, TestBlock, []byte("baddata"))
20         testPutRawBadDataGetBlock(t, factory, EmptyHash, EmptyBlock, []byte("baddata"))
21         testPutBlock(t, factory, TestHash, TestBlock)
22         testPutBlock(t, factory, EmptyHash, EmptyBlock)
23         testPutBlockCorrupt(t, factory, TestHash, TestBlock, []byte("baddata"))
24         testPutBlockCorrupt(t, factory, EmptyHash, EmptyBlock, []byte("baddata"))
25 }
26
27 // Setup RRVolumeManager with TestableVolumes
28 func setupHandlersWithGenericVolumeTest(t TB, factory TestableVolumeManagerFactory) []TestableVolume {
29         vm, testableVolumes := factory(t)
30         KeepVM = vm
31
32         for _, v := range testableVolumes {
33                 defer v.Teardown()
34         }
35         defer KeepVM.Close()
36
37         return testableVolumes
38 }
39
40 // Put a block using PutRaw in just one volume and Get it using GetBlock
41 func testGetBlock(t TB, factory TestableVolumeManagerFactory, testHash string, testBlock []byte) {
42         testableVolumes := setupHandlersWithGenericVolumeTest(t, factory)
43
44         // Put testBlock in one volume
45         testableVolumes[1].PutRaw(testHash, testBlock)
46
47         // Get should pass
48         buf, err := GetBlock(testHash)
49         if err != nil {
50                 t.Fatalf("Error while getting block %s", err)
51         }
52         if bytes.Compare(buf, testBlock) != 0 {
53                 t.Errorf("Put succeeded but Get returned %+v, expected %+v", buf, testBlock)
54         }
55 }
56
57 // Put a bad block using PutRaw and get it.
58 func testPutRawBadDataGetBlock(t TB, factory TestableVolumeManagerFactory,
59         testHash string, testBlock []byte, badData []byte) {
60         testableVolumes := setupHandlersWithGenericVolumeTest(t, factory)
61
62         // Put bad data for testHash in both volumes
63         testableVolumes[0].PutRaw(testHash, badData)
64         testableVolumes[1].PutRaw(testHash, badData)
65
66         // Get should fail
67         _, err := GetBlock(testHash)
68         if err == nil {
69                 t.Fatalf("Expected error while getting corrupt block %v", testHash)
70         }
71 }
72
73 // Invoke PutBlock twice to ensure CompareAndTouch path is tested.
74 func testPutBlock(t TB, factory TestableVolumeManagerFactory, testHash string, testBlock []byte) {
75         setupHandlersWithGenericVolumeTest(t, factory)
76
77         // PutBlock
78         if _, err := PutBlock(testBlock, testHash); err != nil {
79                 t.Fatalf("Error during PutBlock: %s", err)
80         }
81
82         // Check that PutBlock succeeds again even after CompareAndTouch
83         if _, err := PutBlock(testBlock, testHash); err != nil {
84                 t.Fatalf("Error during PutBlock: %s", err)
85         }
86
87         // Check that PutBlock stored the data as expected
88         buf, err := GetBlock(testHash)
89         if err != nil {
90                 t.Fatalf("Error during GetBlock for %q: %s", testHash, err)
91         } else if bytes.Compare(buf, testBlock) != 0 {
92                 t.Errorf("Get response incorrect. Expected %q; found %q", testBlock, buf)
93         }
94 }
95
96 // Put a bad block using PutRaw, overwrite it using PutBlock and get it.
97 func testPutBlockCorrupt(t TB, factory TestableVolumeManagerFactory,
98         testHash string, testBlock []byte, badData []byte) {
99         testableVolumes := setupHandlersWithGenericVolumeTest(t, factory)
100
101         // Put bad data for testHash in both volumes
102         testableVolumes[0].PutRaw(testHash, badData)
103         testableVolumes[1].PutRaw(testHash, badData)
104
105         // Check that PutBlock with good data succeeds
106         if _, err := PutBlock(testBlock, testHash); err != nil {
107                 t.Fatalf("Error during PutBlock for %q: %s", testHash, err)
108         }
109
110         // Put succeeded and overwrote the badData in one volume,
111         // and Get should return the testBlock now, ignoring the bad data.
112         buf, err := GetBlock(testHash)
113         if err != nil {
114                 t.Fatalf("Error during GetBlock for %q: %s", testHash, err)
115         } else if bytes.Compare(buf, testBlock) != 0 {
116                 t.Errorf("Get response incorrect. Expected %q; found %q", testBlock, buf)
117         }
118 }