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