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  }