github.com/m3db/m3@v1.5.0/src/dbnode/storage/namespace_bootstrap_data_accumulator_test.go (about) 1 // Copyright (c) 2019 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package storage 22 23 import ( 24 "errors" 25 "testing" 26 27 "github.com/m3db/m3/src/dbnode/storage/bootstrap" 28 "github.com/m3db/m3/src/dbnode/storage/series" 29 "github.com/m3db/m3/src/x/ident" 30 xtest "github.com/m3db/m3/src/x/test" 31 32 "github.com/stretchr/testify/require" 33 ) 34 35 var ( 36 id = ident.StringID("foo") 37 idErr = ident.StringID("bar") 38 tagIter ident.TagIterator 39 ) 40 41 type seriesTestResolver struct { 42 series bootstrap.SeriesRef 43 releaseCalls int 44 uniqueIndex uint64 45 } 46 47 func (r *seriesTestResolver) SeriesRef() (bootstrap.SeriesRef, error) { 48 return r.series, nil 49 } 50 51 func (r *seriesTestResolver) ReleaseRef() { 52 r.releaseCalls++ 53 } 54 55 func (r *seriesTestResolver) UniqueIndex() uint64 { 56 return r.uniqueIndex 57 } 58 59 type checkoutFn func(bootstrap.NamespaceDataAccumulator, uint32, 60 ident.ID, ident.TagIterator) (bootstrap.CheckoutSeriesResult, error) 61 62 func checkoutWithLock( 63 acc bootstrap.NamespaceDataAccumulator, 64 shardID uint32, 65 id ident.ID, 66 tags ident.TagIterator, 67 ) (bootstrap.CheckoutSeriesResult, error) { 68 res, _, err := acc.CheckoutSeriesWithLock(shardID, id, tags) 69 return res, err 70 } 71 72 func checkoutWithoutLock( 73 acc bootstrap.NamespaceDataAccumulator, 74 shardID uint32, 75 id ident.ID, 76 tags ident.TagIterator, 77 ) (bootstrap.CheckoutSeriesResult, error) { 78 res, _, err := acc.CheckoutSeriesWithoutLock(shardID, id, tags) 79 return res, err 80 } 81 82 func TestCheckoutSeries(t *testing.T) { 83 testCheckoutSeries(t, checkoutWithoutLock) 84 } 85 86 func TestCheckoutSeriesWithLock(t *testing.T) { 87 testCheckoutSeries(t, checkoutWithLock) 88 } 89 90 func testCheckoutSeries(t *testing.T, checkoutFn checkoutFn) { 91 ctrl := xtest.NewController(t) 92 defer ctrl.Finish() 93 var ( 94 ns = NewMockdatabaseNamespace(ctrl) 95 mockSeries = series.NewMockDatabaseSeries(ctrl) 96 acc = NewDatabaseNamespaceDataAccumulator(ns) 97 uniqueIdx = uint64(10) 98 shardID = uint32(7) 99 resolver = &seriesTestResolver{series: mockSeries, uniqueIndex: uniqueIdx} 100 ) 101 102 mockSeries.EXPECT().UniqueIndex().Return(uniqueIdx).AnyTimes() 103 ns.EXPECT().SeriesRefResolver(shardID, id, tagIter).Return(resolver, true, nil) 104 ns.EXPECT().SeriesRefResolver(shardID, idErr, tagIter). 105 Return(nil, false, errors.New("err")) 106 107 _, err := checkoutFn(acc, shardID, idErr, tagIter) 108 require.Error(t, err) 109 110 seriesResult, err := checkoutFn(acc, shardID, id, tagIter) 111 require.NoError(t, err) 112 seriesRef, err := seriesResult.Resolver.SeriesRef() 113 require.NoError(t, err) 114 require.Equal(t, mockSeries, seriesRef) 115 require.Equal(t, uniqueIdx, seriesRef.UniqueIndex()) 116 require.Equal(t, shardID, seriesResult.Shard) 117 118 cast, ok := acc.(*namespaceDataAccumulator) 119 require.True(t, ok) 120 require.Equal(t, 1, len(cast.needsRelease)) 121 require.Equal(t, resolver, cast.needsRelease[0]) 122 // Ensure it hasn't been released. 123 require.Zero(t, resolver.releaseCalls) 124 } 125 126 func TestAccumulatorRelease(t *testing.T) { 127 testAccumulatorRelease(t, checkoutWithoutLock) 128 } 129 130 func TestAccumulatorReleaseWithLock(t *testing.T) { 131 testAccumulatorRelease(t, checkoutWithLock) 132 } 133 134 func testAccumulatorRelease(t *testing.T, checkoutFn checkoutFn) { 135 ctrl := xtest.NewController(t) 136 defer ctrl.Finish() 137 138 var ( 139 err error 140 ns = NewMockdatabaseNamespace(ctrl) 141 acc = NewDatabaseNamespaceDataAccumulator(ns) 142 shardID = uint32(1337) 143 resolver = &seriesTestResolver{series: series.NewMockDatabaseSeries(ctrl)} 144 ) 145 146 ns.EXPECT().SeriesRefResolver(shardID, id, tagIter).Return(resolver, true, nil) 147 _, err = checkoutFn(acc, shardID, id, tagIter) 148 require.NoError(t, err) 149 150 cast, ok := acc.(*namespaceDataAccumulator) 151 require.True(t, ok) 152 require.Equal(t, 1, len(cast.needsRelease)) 153 require.Equal(t, resolver, cast.needsRelease[0]) 154 155 require.NoError(t, acc.Close()) 156 require.Zero(t, len(cast.needsRelease)) 157 // ensure release has been called. 158 require.Equal(t, 1, resolver.releaseCalls) 159 // ensure double-close errors. 160 require.Error(t, acc.Close()) 161 }