github.com/m3db/m3@v1.5.0/src/cluster/kv/util/runtime/value_test.go (about) 1 // Copyright (c) 2017 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 runtime 22 23 import ( 24 "errors" 25 "testing" 26 "time" 27 28 "github.com/m3db/m3/src/cluster/generated/proto/commonpb" 29 "github.com/m3db/m3/src/cluster/kv" 30 "github.com/m3db/m3/src/cluster/kv/mem" 31 "github.com/m3db/m3/src/x/instrument" 32 "github.com/m3db/m3/src/x/watch" 33 34 "github.com/fortytw2/leaktest" 35 "github.com/golang/mock/gomock" 36 "github.com/stretchr/testify/require" 37 ) 38 39 const ( 40 testValueKey = "testValue" 41 ) 42 43 func TestValueWatchAlreadyWatching(t *testing.T) { 44 defer leaktest.Check(t)() 45 46 ctrl := gomock.NewController(t) 47 defer ctrl.Finish() 48 49 notifyCh := make(chan struct{}) 50 mockWatch := kv.NewMockValueWatch(ctrl) 51 mockWatch.EXPECT().C().Return(notifyCh).MinTimes(1) 52 53 mockStore, rv := testValueWithMockStore(ctrl) 54 mockStore.EXPECT().Watch(rv.key).Return(mockWatch, nil) 55 56 err := rv.Watch() 57 require.Error(t, err) 58 59 _, ok := err.(watch.InitValueError) 60 require.True(t, ok) 61 require.NoError(t, rv.Watch()) 62 63 mockWatch.EXPECT().Close().Do(func() { close(notifyCh) }) 64 rv.Unwatch() 65 } 66 67 func TestValueWatchCreateWatchError(t *testing.T) { 68 defer leaktest.Check(t)() 69 70 ctrl := gomock.NewController(t) 71 defer ctrl.Finish() 72 73 store, rv := testValueWithMockStore(ctrl) 74 errWatch := errors.New("error creating watch") 75 store.EXPECT().Watch(rv.key).Return(nil, errWatch) 76 77 err := rv.Watch() 78 require.Error(t, err) 79 80 _, ok := err.(watch.CreateWatchError) 81 require.True(t, ok) 82 store.EXPECT().Watch(rv.key).Return(nil, errWatch) 83 84 err = rv.Watch() 85 require.Error(t, err) 86 _, ok = err.(watch.CreateWatchError) 87 require.True(t, ok) 88 89 rv.Unwatch() 90 } 91 92 func TestValueWatchWatchTimeout(t *testing.T) { 93 defer leaktest.Check(t)() 94 95 ctrl := gomock.NewController(t) 96 defer ctrl.Finish() 97 98 store, rv := testValueWithMockStore(ctrl) 99 notifyCh := make(chan struct{}) 100 mockWatch := kv.NewMockValueWatch(ctrl) 101 mockWatch.EXPECT().C().Return(notifyCh).MinTimes(1) 102 store.EXPECT().Watch(rv.key).Return(mockWatch, nil) 103 104 err := rv.Watch() 105 require.Error(t, err) 106 _, ok := err.(watch.InitValueError) 107 require.True(t, ok) 108 109 mockWatch.EXPECT().Close().Do(func() { close(notifyCh) }) 110 rv.Unwatch() 111 } 112 113 func TestValueWatchUpdateError(t *testing.T) { 114 defer leaktest.Check(t)() 115 116 ctrl := gomock.NewController(t) 117 defer ctrl.Finish() 118 119 store, rv := testValueWithMockStore(ctrl) 120 errUpdate := errors.New("error updating") 121 rv.updateFn = func(interface{}) error { 122 return errUpdate 123 } 124 rv.initValue() 125 notifyCh := make(chan struct{}, 1) 126 notifyCh <- struct{}{} 127 mockWatch := kv.NewMockValueWatch(ctrl) 128 mockWatch.EXPECT().C().Return(notifyCh).MinTimes(1) 129 mockWatch.EXPECT().Get().Return(mem.NewValue(1, nil)) 130 store.EXPECT().Watch(rv.key).Return(mockWatch, nil) 131 132 err := rv.Watch() 133 require.Error(t, err) 134 _, ok := err.(watch.InitValueError) 135 require.True(t, ok) 136 require.Contains(t, err.Error(), errUpdate.Error()) 137 138 mockWatch.EXPECT().Close().Do(func() { close(notifyCh) }) 139 rv.Unwatch() 140 } 141 142 func TestValueWatchSuccess(t *testing.T) { 143 defer leaktest.Check(t)() 144 145 ctrl := gomock.NewController(t) 146 defer ctrl.Finish() 147 148 store, rv := testValueWithMockStore(ctrl) 149 rv.updateFn = func(interface{}) error { return nil } 150 rv.initValue() 151 notifyCh := make(chan struct{}, 1) 152 notifyCh <- struct{}{} 153 mockWatch := kv.NewMockValueWatch(ctrl) 154 mockWatch.EXPECT().C().Return(notifyCh).MinTimes(1) 155 mockWatch.EXPECT().Get().Return(mem.NewValue(1, nil)) 156 store.EXPECT().Watch(rv.key).Return(mockWatch, nil) 157 158 require.NoError(t, rv.Watch()) 159 160 mockWatch.EXPECT().Close().Do(func() { close(notifyCh) }) 161 rv.Unwatch() 162 } 163 164 func TestValueWatchUnWatchMultipleTimes(t *testing.T) { 165 defer leaktest.Check(t)() 166 167 store, rv := testValueWithMemStore() 168 rv.updateFn = func(interface{}) error { return nil } 169 rv.initValue() 170 _, err := store.SetIfNotExists(testValueKey, &commonpb.BoolProto{}) 171 require.NoError(t, err) 172 173 iter := 10 174 for i := 0; i < iter; i++ { 175 require.NoError(t, rv.Watch()) 176 rv.Unwatch() 177 } 178 } 179 180 func TestValueUpdateStaleUpdate(t *testing.T) { 181 defer leaktest.Check(t)() 182 183 ctrl := gomock.NewController(t) 184 defer ctrl.Finish() 185 186 _, rv := testValueWithMockStore(ctrl) 187 currValue := mem.NewValue(3, nil) 188 rv.currValue = currValue 189 newValue := mem.NewValue(3, nil) 190 require.NoError(t, rv.updateFn(newValue)) 191 require.Equal(t, currValue, rv.currValue) 192 } 193 194 func TestValueUpdateUnmarshalError(t *testing.T) { 195 defer leaktest.Check(t)() 196 197 ctrl := gomock.NewController(t) 198 defer ctrl.Finish() 199 200 _, rv := testValueWithMockStore(ctrl) 201 errUnmarshal := errors.New("error unmarshaling") 202 rv.unmarshalFn = func(v kv.Value) (interface{}, error) { return nil, errUnmarshal } 203 204 require.Error(t, rv.updateFn(mem.NewValue(3, nil))) 205 require.Nil(t, rv.currValue) 206 } 207 208 func TestValueUpdateProcessError(t *testing.T) { 209 defer leaktest.Check(t)() 210 211 ctrl := gomock.NewController(t) 212 defer ctrl.Finish() 213 214 _, rv := testValueWithMockStore(ctrl) 215 errProcess := errors.New("error processing") 216 rv.unmarshalFn = func(v kv.Value) (interface{}, error) { return nil, nil } 217 rv.processFn = func(v interface{}) error { return errProcess } 218 219 require.Error(t, rv.updateFn(mem.NewValue(3, nil))) 220 require.Nil(t, rv.currValue) 221 } 222 223 func TestValueUpdateSuccess(t *testing.T) { 224 defer leaktest.Check(t)() 225 226 ctrl := gomock.NewController(t) 227 defer ctrl.Finish() 228 229 var outputs []kv.Value 230 _, rv := testValueWithMockStore(ctrl) 231 rv.currValue = mem.NewValue(2, nil) 232 rv.unmarshalFn = func(v kv.Value) (interface{}, error) { return v, nil } 233 rv.processFn = func(v interface{}) error { 234 outputs = append(outputs, v.(kv.Value)) 235 return nil 236 } 237 238 input := mem.NewValue(3, nil) 239 require.NoError(t, rv.update(input)) 240 require.Equal(t, []kv.Value{input}, outputs) 241 require.Equal(t, input, rv.currValue) 242 } 243 244 func testValueOptions(store kv.Store) Options { 245 return NewOptions(). 246 SetInstrumentOptions(instrument.NewOptions()). 247 SetInitWatchTimeout(100 * time.Millisecond). 248 SetKVStore(store). 249 SetUnmarshalFn(nil). 250 SetProcessFn(nil) 251 } 252 253 func testValueWithMockStore(ctrl *gomock.Controller) (*kv.MockStore, *value) { 254 store := kv.NewMockStore(ctrl) 255 opts := testValueOptions(store) 256 return store, NewValue(testValueKey, opts).(*value) 257 } 258 259 func testValueWithMemStore() (kv.Store, *value) { 260 store := mem.NewStore() 261 opts := testValueOptions(store) 262 return store, NewValue(testValueKey, opts).(*value) 263 }