github.com/m3db/m3@v1.5.0/src/cmd/services/m3aggregator/config/runtime_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 config
    22  
    23  import (
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/m3db/m3/src/aggregator/aggregator"
    28  	"github.com/m3db/m3/src/aggregator/runtime"
    29  	"github.com/m3db/m3/src/cluster/client"
    30  	"github.com/m3db/m3/src/cluster/generated/proto/commonpb"
    31  	"github.com/m3db/m3/src/cluster/kv/mem"
    32  	"github.com/m3db/m3/src/cluster/placement"
    33  	xtest "github.com/m3db/m3/src/x/test"
    34  
    35  	"github.com/golang/mock/gomock"
    36  	"github.com/stretchr/testify/require"
    37  	yaml "gopkg.in/yaml.v2"
    38  )
    39  
    40  func TestRuntimeOptionsConfigurationNewRuntimeOptionsManager(t *testing.T) {
    41  	ctrl := gomock.NewController(t)
    42  	defer ctrl.Finish()
    43  
    44  	config := `
    45  kvConfig:
    46    zone: test
    47    environment: production
    48  writeValuesPerMetricLimitPerSecondKey: rate-limit-key
    49  writeValuesPerMetricLimitPerSecond: 0
    50  writeNewMetricLimitClusterPerSecondKey: new-metric-limit-key
    51  writeNewMetricLimitClusterPerSecond: 0
    52  writeNewMetricNoLimitWarmupDuration: 10m
    53  `
    54  	var cfg RuntimeOptionsConfiguration
    55  	require.NoError(t, yaml.Unmarshal([]byte(config), &cfg))
    56  	require.Equal(t, "test", cfg.KVConfig.Zone)
    57  	require.Equal(t, "production", cfg.KVConfig.Environment)
    58  	require.Equal(t, "rate-limit-key", cfg.WriteValuesPerMetricLimitPerSecondKey)
    59  	require.Equal(t, int64(0), cfg.WriteValuesPerMetricLimitPerSecond)
    60  	require.Equal(t, "new-metric-limit-key", cfg.WriteNewMetricLimitClusterPerSecondKey)
    61  	require.Equal(t, int64(0), cfg.WriteNewMetricLimitClusterPerSecond)
    62  	require.Equal(t, 10*time.Minute, cfg.WriteNewMetricNoLimitWarmupDuration)
    63  
    64  	initialValueLimit := int64(100)
    65  	proto := &commonpb.Int64Proto{Value: initialValueLimit}
    66  	memStore := mem.NewStore()
    67  	_, err := memStore.Set("rate-limit-key", proto)
    68  	require.NoError(t, err)
    69  
    70  	initialNewMetricLimit := int64(32)
    71  	proto = &commonpb.Int64Proto{Value: initialNewMetricLimit}
    72  	_, err = memStore.Set("new-metric-limit-key", proto)
    73  	require.NoError(t, err)
    74  
    75  	runtimeOptsManager := cfg.NewRuntimeOptionsManager()
    76  	testShards := []uint32{0, 1, 2, 3}
    77  	testPlacement := placement.NewPlacement().SetReplicaFactor(2).SetShards(testShards)
    78  	testPlacementManager := aggregator.NewMockPlacementManager(ctrl)
    79  	testPlacementManager.EXPECT().Placement().Return(testPlacement, nil).AnyTimes()
    80  
    81  	mockClient := client.NewMockClient(ctrl)
    82  	mockClient.EXPECT().Store(gomock.Any()).Return(memStore, nil)
    83  	logger := xtest.NewLogger(t)
    84  	cfg.WatchRuntimeOptionChanges(mockClient, runtimeOptsManager, testPlacementManager, logger)
    85  	runtimeOpts := runtimeOptsManager.RuntimeOptions()
    86  	expectedOpts := runtime.NewOptions().
    87  		SetWriteValuesPerMetricLimitPerSecond(initialValueLimit).
    88  		SetWriteNewMetricLimitPerShardPerSecond(4).
    89  		SetWriteNewMetricNoLimitWarmupDuration(10 * time.Minute)
    90  	require.Equal(t, expectedOpts, runtimeOpts)
    91  
    92  	// Set a new value limit.
    93  	newValueLimit := int64(1000)
    94  	proto.Value = newValueLimit
    95  	_, err = memStore.Set("rate-limit-key", proto)
    96  	require.NoError(t, err)
    97  	expectedOpts = runtime.NewOptions().
    98  		SetWriteValuesPerMetricLimitPerSecond(1000).
    99  		SetWriteNewMetricLimitPerShardPerSecond(4).
   100  		SetWriteNewMetricNoLimitWarmupDuration(10 * time.Minute)
   101  	for {
   102  		runtimeOpts = runtimeOptsManager.RuntimeOptions()
   103  		if compareRuntimeOptions(expectedOpts, runtimeOpts) {
   104  			break
   105  		}
   106  		time.Sleep(10 * time.Millisecond)
   107  	}
   108  
   109  	// Revert value limit to initial limit.
   110  	newValueLimit = 100
   111  	proto.Value = newValueLimit
   112  	_, err = memStore.Set("rate-limit-key", proto)
   113  	require.NoError(t, err)
   114  	expectedOpts = runtime.NewOptions().
   115  		SetWriteValuesPerMetricLimitPerSecond(100).
   116  		SetWriteNewMetricLimitPerShardPerSecond(4).
   117  		SetWriteNewMetricNoLimitWarmupDuration(10 * time.Minute)
   118  	for {
   119  		runtimeOpts = runtimeOptsManager.RuntimeOptions()
   120  		if compareRuntimeOptions(expectedOpts, runtimeOpts) {
   121  			break
   122  		}
   123  		time.Sleep(10 * time.Millisecond)
   124  	}
   125  
   126  	// Set a new new-metric limit.
   127  	newNewMetricLimit := int64(128)
   128  	proto.Value = newNewMetricLimit
   129  	_, err = memStore.Set("new-metric-limit-key", proto)
   130  	require.NoError(t, err)
   131  	expectedOpts = runtime.NewOptions().
   132  		SetWriteValuesPerMetricLimitPerSecond(100).
   133  		SetWriteNewMetricLimitPerShardPerSecond(16).
   134  		SetWriteNewMetricNoLimitWarmupDuration(10 * time.Minute)
   135  	for {
   136  		runtimeOpts = runtimeOptsManager.RuntimeOptions()
   137  		if compareRuntimeOptions(expectedOpts, runtimeOpts) {
   138  			break
   139  		}
   140  		time.Sleep(10 * time.Millisecond)
   141  	}
   142  
   143  	// Revert to default new-metric limit.
   144  	newNewMetricLimit = int64(32)
   145  	proto.Value = newNewMetricLimit
   146  	_, err = memStore.Set("new-metric-limit-key", proto)
   147  	require.NoError(t, err)
   148  	expectedOpts = runtime.NewOptions().
   149  		SetWriteValuesPerMetricLimitPerSecond(100).
   150  		SetWriteNewMetricLimitPerShardPerSecond(4).
   151  		SetWriteNewMetricNoLimitWarmupDuration(10 * time.Minute)
   152  	for {
   153  		runtimeOpts = runtimeOptsManager.RuntimeOptions()
   154  		if compareRuntimeOptions(expectedOpts, runtimeOpts) {
   155  			break
   156  		}
   157  		time.Sleep(10 * time.Millisecond)
   158  	}
   159  }
   160  
   161  func compareRuntimeOptions(expected, actual runtime.Options) bool {
   162  	return expected.WriteNewMetricLimitPerShardPerSecond() == actual.WriteNewMetricLimitPerShardPerSecond() &&
   163  		expected.WriteNewMetricNoLimitWarmupDuration() == actual.WriteNewMetricNoLimitWarmupDuration() &&
   164  		expected.WriteValuesPerMetricLimitPerSecond() == actual.WriteValuesPerMetricLimitPerSecond()
   165  }