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  }