github.com/m3db/m3@v1.5.0/src/cluster/placement/placements_watcher_test.go (about) 1 // Copyright (c) 2021 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 placement 22 23 import ( 24 "testing" 25 "time" 26 27 "github.com/stretchr/testify/assert" 28 "github.com/stretchr/testify/require" 29 30 "github.com/m3db/m3/src/cluster/kv" 31 "github.com/m3db/m3/src/cluster/kv/mem" 32 ) 33 34 const ( 35 testPlacementKey = "testPlacementKey" 36 ) 37 38 func TestWatcherWatchAlreadyWatching(t *testing.T) { 39 watcher, _ := testWatcher(t) 40 watcher.watching.Store(true) 41 require.Equal(t, errWatcherIsWatching, watcher.Watch()) 42 } 43 44 func TestWatcherWatchSuccess(t *testing.T) { 45 watcher, _ := testWatcher(t) 46 require.NoError(t, watcher.Watch()) 47 } 48 49 func TestWatcherGetNotWatching(t *testing.T) { 50 watcher, _ := testWatcher(t) 51 52 _, err := watcher.Get() 53 require.Equal(t, errWatcherIsNotWatching, err) 54 } 55 56 func TestWatcherGetSuccess(t *testing.T) { 57 watcher, _ := testWatcher(t) 58 require.NoError(t, watcher.Watch()) 59 actual, err := watcher.Get() 60 require.NoError(t, err) 61 expected := testLatestPlacement(t) 62 expected.SetVersion(1) 63 require.Equal(t, expected, actual) 64 } 65 66 func TestWatcherUnwatchNotWatching(t *testing.T) { 67 watcher, _ := testWatcher(t) 68 require.Equal(t, errWatcherIsNotWatching, watcher.Unwatch()) 69 } 70 71 func TestWatcherUnwatchSuccess(t *testing.T) { 72 watcher, _ := testWatcher(t) 73 watcher.watching.Store(true) 74 require.NoError(t, watcher.Unwatch()) 75 require.False(t, watcher.watching.Load()) 76 require.Nil(t, watcher.valuePayload.Load()) 77 } 78 79 func TestWatcherToStagedPlacementNotWatching(t *testing.T) { 80 watcher, _ := testWatcher(t) 81 _, err := watcher.unmarshalAsPlacementSnapshots(nil) 82 require.Equal(t, errWatcherIsNotWatching, err) 83 } 84 85 func TestWatcherToPlacementNilValue(t *testing.T) { 86 watcher, _ := testWatcher(t) 87 watcher.watching.Store(true) 88 _, err := watcher.unmarshalAsPlacementSnapshots(nil) 89 require.Equal(t, errNilValue, err) 90 } 91 92 func TestWatcherToStagedPlacementUnmarshalError(t *testing.T) { 93 watcher, _ := testWatcher(t) 94 _, err := watcher.unmarshalAsPlacementSnapshots(mem.NewValueWithData(1, []byte("abcd"))) 95 require.Error(t, err) 96 } 97 98 func TestWatcherUnmarshalAsPlacementSnapshots(t *testing.T) { 99 watcher, store := testWatcher(t) 100 watcher.watching.Store(true) 101 val, err := store.Get(testPlacementKey) 102 require.NoError(t, err) 103 p, err := watcher.unmarshalAsPlacementSnapshots(val) 104 require.NoError(t, err) 105 actual, ok := p.(*placement) 106 require.True(t, ok) 107 108 expected := testLatestPlacement(t) 109 expected.SetVersion(1) 110 111 require.Equal(t, 1, actual.version) 112 require.Equal(t, expected, actual) 113 } 114 115 func TestWatcherProcessNotWatching(t *testing.T) { 116 watcher, _ := testWatcher(t) 117 require.Equal(t, errWatcherIsNotWatching, watcher.process(nil)) 118 } 119 120 func TestWatcherProcessSuccess(t *testing.T) { 121 p := testLatestPlacement(t) 122 testCases := []struct { 123 name string 124 expectedPrev Placement 125 expectedCurr Placement 126 }{ 127 { 128 name: "previous_placement_must_be_nil", 129 expectedPrev: nil, 130 expectedCurr: p, 131 }, { 132 name: "previous_placement_must_not_be_nil", 133 expectedPrev: p, 134 expectedCurr: p, 135 }, 136 } 137 138 for _, tc := range testCases { 139 t.Run(tc.name, func(t *testing.T) { 140 var numCalls int 141 opts := testWatcherOptions(). 142 SetOnPlacementChangedFn( 143 func(prev, curr Placement) { 144 numCalls++ 145 assert.Equal(t, tc.expectedPrev, prev) // nolint: scopelint 146 assert.Equal(t, tc.expectedCurr, curr) // nolint: scopelint 147 }) 148 149 watcher := testWatcherWithOpts(t, opts) 150 watcher.watching.Store(true) 151 if tc.expectedPrev != nil { // nolint: scopelint 152 watcher.valuePayload.Store(payload{placement: p}) 153 } 154 155 require.NoError(t, watcher.process(p)) 156 require.NotNil(t, watcher.valuePayload) 157 require.Equal(t, 1, numCalls) 158 }) 159 } 160 } 161 162 func testWatcher(t *testing.T) (*placementsWatcher, kv.Store) { 163 t.Helper() 164 opts := testWatcherOptions() 165 watcher := testWatcherWithOpts(t, opts) 166 167 return watcher, opts.StagedPlacementStore() 168 } 169 170 func testWatcherWithOpts(t *testing.T, opts WatcherOptions) *placementsWatcher { 171 t.Helper() 172 _, err := opts.StagedPlacementStore(). 173 SetIfNotExists(testPlacementKey, testStagedPlacementProto) 174 require.NoError(t, err) 175 176 watcher := NewPlacementsWatcher(opts) 177 return watcher.(*placementsWatcher) 178 } 179 180 func testWatcherOptions() WatcherOptions { 181 return NewWatcherOptions(). 182 SetInitWatchTimeout(100 * time.Millisecond). 183 SetStagedPlacementKey(testPlacementKey). 184 SetStagedPlacementStore(mem.NewStore()) 185 }