dda7edcec3509e683465a93d5eb775bf18f16d19
[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 := make([]byte, len(testBlock))
49         n, err := GetBlock(testHash, buf, nil)
50         if err != nil {
51                 t.Fatalf("Error while getting block %s", err)
52         }
53         if bytes.Compare(buf[:n], testBlock) != 0 {
54                 t.Errorf("Put succeeded but Get returned %+v, expected %+v", buf[:n], testBlock)
55         }
56 }
57
58 // Put a bad block using PutRaw and get it.
59 func testPutRawBadDataGetBlock(t TB, factory TestableVolumeManagerFactory,
60         testHash string, testBlock []byte, badData []byte) {
61         testableVolumes := setupHandlersWithGenericVolumeTest(t, factory)
62
63         // Put bad data for testHash in both volumes
64         testableVolumes[0].PutRaw(testHash, badData)
65         testableVolumes[1].PutRaw(testHash, badData)
66
67         // Get should fail
68         buf := make([]byte, BlockSize)
69         size, err := GetBlock(testHash, buf, nil)
70         if err == nil {
71                 t.Fatalf("Got %+q, expected error while getting corrupt block %v", buf[:size], testHash)
72         }
73 }
74
75 // Invoke PutBlock twice to ensure CompareAndTouch path is tested.
76 func testPutBlock(t TB, factory TestableVolumeManagerFactory, testHash string, testBlock []byte) {
77         setupHandlersWithGenericVolumeTest(t, factory)
78
79         // PutBlock
80         if _, err := PutBlock(testBlock, testHash); err != nil {
81                 t.Fatalf("Error during PutBlock: %s", err)
82         }
83
84         // Check that PutBlock succeeds again even after CompareAndTouch
85         if _, err := PutBlock(testBlock, testHash); err != nil {
86                 t.Fatalf("Error during PutBlock: %s", err)
87         }
88
89         // Check that PutBlock stored the data as expected
90         buf := make([]byte, BlockSize)
91         size, err := GetBlock(testHash, buf, nil)
92         if err != nil {
93                 t.Fatalf("Error during GetBlock for %q: %s", testHash, err)
94         } else if bytes.Compare(buf[:size], testBlock) != 0 {
95                 t.Errorf("Get response incorrect. Expected %q; found %q", testBlock, buf[:size])
96         }
97 }
98
99 // Put a bad block using PutRaw, overwrite it using PutBlock and get it.
100 func testPutBlockCorrupt(t TB, factory TestableVolumeManagerFactory,
101         testHash string, testBlock []byte, badData []byte) {
102         testableVolumes := setupHandlersWithGenericVolumeTest(t, factory)
103
104         // Put bad data for testHash in both volumes
105         testableVolumes[0].PutRaw(testHash, badData)
106         testableVolumes[1].PutRaw(testHash, badData)
107
108         // Check that PutBlock with good data succeeds
109         if _, err := PutBlock(testBlock, testHash); err != nil {
110                 t.Fatalf("Error during PutBlock for %q: %s", testHash, err)
111         }
112
113         // Put succeeded and overwrote the badData in one volume,
114         // and Get should return the testBlock now, ignoring the bad data.
115         buf := make([]byte, BlockSize)
116         size, err := GetBlock(testHash, buf, nil)
117         if err != nil {
118                 t.Fatalf("Error during GetBlock for %q: %s", testHash, err)
119         } else if bytes.Compare(buf[:size], testBlock) != 0 {
120                 t.Errorf("Get response incorrect. Expected %q; found %q", testBlock, buf[:size])
121         }
122 }