github.com/m3db/m3@v1.5.0/src/query/api/v1/handler/namespace/common_test.go (about)

     1  // Copyright (c) 2018 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 namespace
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/m3db/m3/src/cluster/kv"
    30  	nsproto "github.com/m3db/m3/src/dbnode/generated/proto/namespace"
    31  	"github.com/m3db/m3/src/dbnode/namespace"
    32  	"github.com/m3db/m3/src/dbnode/retention"
    33  	"github.com/m3db/m3/src/x/ident"
    34  	xtest "github.com/m3db/m3/src/x/test"
    35  
    36  	"github.com/golang/mock/gomock"
    37  	"github.com/stretchr/testify/assert"
    38  	"github.com/stretchr/testify/require"
    39  )
    40  
    41  func init() {
    42  	namespace.RegisterExtendedOptionsConverter("testExtendedOptions", xtest.ConvertToTestExtendedOptions)
    43  }
    44  
    45  type storeOptionsMatcher struct {
    46  	zone        string
    47  	namespace   string
    48  	environment string
    49  }
    50  
    51  func (s storeOptionsMatcher) Matches(x interface{}) bool {
    52  	opts := x.(kv.OverrideOptions)
    53  	if s.zone != "" && s.zone != opts.Zone() {
    54  		return false
    55  	}
    56  	if s.namespace != "" && s.namespace != opts.Namespace() {
    57  		return false
    58  	}
    59  	if s.environment != "" && s.environment != opts.Environment() {
    60  		return false
    61  	}
    62  	return true
    63  }
    64  
    65  func (s storeOptionsMatcher) String() string {
    66  	return fmt.Sprintf("checks that zone=%s, namespace=%s, environment=%s", s.zone, s.namespace, s.environment)
    67  }
    68  
    69  func newStoreOptionsMatcher(zone, namespace, environment string) gomock.Matcher {
    70  	return storeOptionsMatcher{
    71  		zone:        zone,
    72  		namespace:   namespace,
    73  		environment: environment,
    74  	}
    75  }
    76  
    77  func TestMetadata(t *testing.T) {
    78  	ctrl := gomock.NewController(t)
    79  	defer ctrl.Finish()
    80  
    81  	mockKV := kv.NewMockStore(ctrl)
    82  	require.NotNil(t, mockKV)
    83  
    84  	// Test KV get error
    85  	mockKV.EXPECT().Get(M3DBNodeNamespacesKey).Return(nil, errors.New("unable to get key"))
    86  	meta, version, err := Metadata(mockKV)
    87  	assert.Nil(t, meta)
    88  	assert.Equal(t, -1, version)
    89  	assert.EqualError(t, err, "unable to get key")
    90  
    91  	// Test empty namespace
    92  	mockKV.EXPECT().Get(M3DBNodeNamespacesKey).Return(nil, kv.ErrNotFound)
    93  	meta, version, err = Metadata(mockKV)
    94  	assert.NotNil(t, meta)
    95  	assert.Equal(t, 0, version)
    96  	assert.Len(t, meta, 0)
    97  	assert.NoError(t, err)
    98  
    99  	registry := nsproto.Registry{
   100  		Namespaces: map[string]*nsproto.NamespaceOptions{
   101  			"metrics-ns1": {
   102  				BootstrapEnabled:  true,
   103  				FlushEnabled:      true,
   104  				WritesToCommitLog: false,
   105  				CleanupEnabled:    false,
   106  				RepairEnabled:     false,
   107  				RetentionOptions: &nsproto.RetentionOptions{
   108  					RetentionPeriodNanos:                     200000000000,
   109  					BlockSizeNanos:                           100000000000,
   110  					BufferFutureNanos:                        3000000000,
   111  					BufferPastNanos:                          4000000000,
   112  					BlockDataExpiry:                          true,
   113  					BlockDataExpiryAfterNotAccessPeriodNanos: 5000000000,
   114  				},
   115  			},
   116  			"metrics-ns2": {
   117  				BootstrapEnabled:  true,
   118  				FlushEnabled:      true,
   119  				WritesToCommitLog: true,
   120  				CleanupEnabled:    true,
   121  				RepairEnabled:     false,
   122  				RetentionOptions: &nsproto.RetentionOptions{
   123  					RetentionPeriodNanos:                     400000000000,
   124  					BlockSizeNanos:                           300000000000,
   125  					BufferFutureNanos:                        8000000000,
   126  					BufferPastNanos:                          9000000000,
   127  					BlockDataExpiry:                          false,
   128  					BlockDataExpiryAfterNotAccessPeriodNanos: 10000000000,
   129  				},
   130  			},
   131  		},
   132  	}
   133  	mockMetaValue := kv.NewMockValue(ctrl)
   134  	mockMetaValue.EXPECT().Unmarshal(gomock.Not(nil)).Return(nil).SetArg(0, registry)
   135  	mockMetaValue.EXPECT().Version().Return(0)
   136  
   137  	// Test namespaces
   138  	mockKV.EXPECT().Get(M3DBNodeNamespacesKey).Return(mockMetaValue, nil)
   139  	meta, version, err = Metadata(mockKV)
   140  	assert.NotNil(t, meta)
   141  	assert.Equal(t, 0, version)
   142  	assert.Len(t, meta, 2)
   143  	assert.NoError(t, err)
   144  }
   145  
   146  func TestValidateAggregationOptionsUniqueResolutionAndRetention(t *testing.T) {
   147  	// Validate that non-unique (resolution, retention) fails.
   148  	dsOpts := namespace.NewDownsampleOptions(true)
   149  	attrs, err := namespace.NewAggregatedAttributes(5*time.Minute, dsOpts)
   150  	require.NoError(t, err)
   151  
   152  	agg := namespace.NewAggregatedAggregation(attrs)
   153  	aggOpts := namespace.NewAggregationOptions().
   154  		SetAggregations([]namespace.Aggregation{agg})
   155  
   156  	nsOpts := namespace.NewOptions().
   157  		SetAggregationOptions(aggOpts).
   158  		SetRetentionOptions(retention.NewOptions().
   159  			SetRetentionPeriod(24 * time.Hour))
   160  
   161  	md1, err := namespace.NewMetadata(ident.StringID("ns1"), nsOpts)
   162  	require.NoError(t, err)
   163  
   164  	md2, err := namespace.NewMetadata(ident.StringID("ns2"), nsOpts)
   165  	require.NoError(t, err)
   166  
   167  	err = validateNamespaceAggregationOptions([]namespace.Metadata{md1, md2})
   168  	require.Error(t, err)
   169  
   170  	// Validate that unique (resolution, retention) is fine.
   171  	nsOpts2 := namespace.NewOptions().
   172  		SetAggregationOptions(aggOpts).
   173  		SetRetentionOptions(retention.NewOptions().
   174  			SetRetentionPeriod(48 * time.Hour))
   175  
   176  	md2, err = namespace.NewMetadata(ident.StringID("ns2"), nsOpts2)
   177  	require.NoError(t, err)
   178  
   179  	err = validateNamespaceAggregationOptions([]namespace.Metadata{md1, md2})
   180  	require.NoError(t, err)
   181  }