1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
12 // A TestableVolumeManagerFactory creates a volume manager with at least two TestableVolume instances.
13 // The factory function, and the TestableVolume instances it returns, can use "t" to write
14 // logs, fail the current test, etc.
15 type TestableVolumeManagerFactory func(t TB) (*RRVolumeManager, []TestableVolume)
17 // DoHandlersWithGenericVolumeTests runs a set of handler tests with a
18 // Volume Manager comprised of TestableVolume instances.
19 // It calls factory to create a volume manager with TestableVolume
20 // instances for each test case, to avoid leaking state between tests.
21 func DoHandlersWithGenericVolumeTests(t TB, factory TestableVolumeManagerFactory) {
22 testGetBlock(t, factory, TestHash, TestBlock)
23 testGetBlock(t, factory, EmptyHash, EmptyBlock)
24 testPutRawBadDataGetBlock(t, factory, TestHash, TestBlock, []byte("baddata"))
25 testPutRawBadDataGetBlock(t, factory, EmptyHash, EmptyBlock, []byte("baddata"))
26 testPutBlock(t, factory, TestHash, TestBlock)
27 testPutBlock(t, factory, EmptyHash, EmptyBlock)
28 testPutBlockCorrupt(t, factory, TestHash, TestBlock, []byte("baddata"))
29 testPutBlockCorrupt(t, factory, EmptyHash, EmptyBlock, []byte("baddata"))
32 // Setup RRVolumeManager with TestableVolumes
33 func setupHandlersWithGenericVolumeTest(t TB, factory TestableVolumeManagerFactory) []TestableVolume {
34 vm, testableVolumes := factory(t)
37 for _, v := range testableVolumes {
42 return testableVolumes
45 // Put a block using PutRaw in just one volume and Get it using GetBlock
46 func testGetBlock(t TB, factory TestableVolumeManagerFactory, testHash string, testBlock []byte) {
47 testableVolumes := setupHandlersWithGenericVolumeTest(t, factory)
49 // Put testBlock in one volume
50 testableVolumes[1].PutRaw(testHash, testBlock)
53 buf := make([]byte, len(testBlock))
54 n, err := GetBlock(context.Background(), testHash, buf, nil)
56 t.Fatalf("Error while getting block %s", err)
58 if bytes.Compare(buf[:n], testBlock) != 0 {
59 t.Errorf("Put succeeded but Get returned %+v, expected %+v", buf[:n], testBlock)
63 // Put a bad block using PutRaw and get it.
64 func testPutRawBadDataGetBlock(t TB, factory TestableVolumeManagerFactory,
65 testHash string, testBlock []byte, badData []byte) {
66 testableVolumes := setupHandlersWithGenericVolumeTest(t, factory)
68 // Put bad data for testHash in both volumes
69 testableVolumes[0].PutRaw(testHash, badData)
70 testableVolumes[1].PutRaw(testHash, badData)
73 buf := make([]byte, BlockSize)
74 size, err := GetBlock(context.Background(), testHash, buf, nil)
76 t.Fatalf("Got %+q, expected error while getting corrupt block %v", buf[:size], testHash)
80 // Invoke PutBlock twice to ensure CompareAndTouch path is tested.
81 func testPutBlock(t TB, factory TestableVolumeManagerFactory, testHash string, testBlock []byte) {
82 setupHandlersWithGenericVolumeTest(t, factory)
85 if _, err := PutBlock(context.Background(), testBlock, testHash); err != nil {
86 t.Fatalf("Error during PutBlock: %s", err)
89 // Check that PutBlock succeeds again even after CompareAndTouch
90 if _, err := PutBlock(context.Background(), testBlock, testHash); err != nil {
91 t.Fatalf("Error during PutBlock: %s", err)
94 // Check that PutBlock stored the data as expected
95 buf := make([]byte, BlockSize)
96 size, err := GetBlock(context.Background(), testHash, buf, nil)
98 t.Fatalf("Error during GetBlock for %q: %s", testHash, err)
99 } else if bytes.Compare(buf[:size], testBlock) != 0 {
100 t.Errorf("Get response incorrect. Expected %q; found %q", testBlock, buf[:size])
104 // Put a bad block using PutRaw, overwrite it using PutBlock and get it.
105 func testPutBlockCorrupt(t TB, factory TestableVolumeManagerFactory,
106 testHash string, testBlock []byte, badData []byte) {
107 testableVolumes := setupHandlersWithGenericVolumeTest(t, factory)
109 // Put bad data for testHash in both volumes
110 testableVolumes[0].PutRaw(testHash, badData)
111 testableVolumes[1].PutRaw(testHash, badData)
113 // Check that PutBlock with good data succeeds
114 if _, err := PutBlock(context.Background(), testBlock, testHash); err != nil {
115 t.Fatalf("Error during PutBlock for %q: %s", testHash, err)
118 // Put succeeded and overwrote the badData in one volume,
119 // and Get should return the testBlock now, ignoring the bad data.
120 buf := make([]byte, BlockSize)
121 size, err := GetBlock(context.Background(), testHash, buf, nil)
123 t.Fatalf("Error during GetBlock for %q: %s", testHash, err)
124 } else if bytes.Compare(buf[:size], testBlock) != 0 {
125 t.Errorf("Get response incorrect. Expected %q; found %q", testBlock, buf[:size])