github.com/m3db/m3@v1.5.0/src/query/storage/m3/cluster_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 m3
    22  
    23  import (
    24  	"fmt"
    25  	"strings"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/m3db/m3/src/dbnode/client"
    30  	"github.com/m3db/m3/src/dbnode/namespace"
    31  	"github.com/m3db/m3/src/query/storage/m3/storagemetadata"
    32  	"github.com/m3db/m3/src/x/ident"
    33  	"github.com/m3db/m3/src/x/instrument"
    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 TestNewClustersWithDuplicateAggregatedClusterNamespace(t *testing.T) {
    42  	ctrl := xtest.NewController(t)
    43  	defer ctrl.Finish()
    44  
    45  	_, err := NewClusters(UnaggregatedClusterNamespaceDefinition{
    46  		NamespaceID: ident.StringID("metrics_unagg"),
    47  		Session:     client.NewMockSession(ctrl),
    48  		Retention:   2 * 24 * time.Hour,
    49  	}, AggregatedClusterNamespaceDefinition{
    50  		NamespaceID: ident.StringID("metrics_agg0"),
    51  		Session:     client.NewMockSession(ctrl),
    52  		Retention:   7 * 24 * time.Hour,
    53  		Resolution:  time.Minute,
    54  	}, AggregatedClusterNamespaceDefinition{
    55  		NamespaceID: ident.StringID("metrics_agg1"),
    56  		Session:     client.NewMockSession(ctrl),
    57  		Retention:   7 * 24 * time.Hour,
    58  		Resolution:  time.Minute,
    59  	})
    60  	require.Error(t, err)
    61  
    62  	str := err.Error()
    63  	assert.True(t, strings.Contains(str, "duplicate aggregated namespace"),
    64  		fmt.Sprintf("unexpected error: %s", err.Error()))
    65  }
    66  
    67  func TestNewClustersFromConfig(t *testing.T) {
    68  	ctrl := xtest.NewController(t)
    69  	defer ctrl.Finish()
    70  
    71  	newClient1, mockSession1, _ := newTestClientFromConfig(ctrl)
    72  	newClient2, mockSession2, _ := newTestClientFromConfig(ctrl)
    73  	cfg := ClustersStaticConfiguration{
    74  		ClusterStaticConfiguration{
    75  			NewClientFromConfig: newClient1,
    76  			Namespaces: []ClusterStaticNamespaceConfiguration{
    77  				{
    78  					Namespace: "unaggregated",
    79  					Type:      storagemetadata.UnaggregatedMetricsType,
    80  					Retention: 7 * 24 * time.Hour,
    81  				},
    82  			},
    83  		},
    84  		ClusterStaticConfiguration{
    85  			NewClientFromConfig: newClient2,
    86  			Namespaces: []ClusterStaticNamespaceConfiguration{
    87  				{
    88  					Namespace:  "aggregated0",
    89  					Type:       storagemetadata.AggregatedMetricsType,
    90  					Retention:  30 * 24 * time.Hour,
    91  					Resolution: time.Minute,
    92  				},
    93  				{
    94  					Namespace:  "aggregated1",
    95  					Type:       storagemetadata.AggregatedMetricsType,
    96  					Retention:  365 * 24 * time.Hour,
    97  					Resolution: 10 * time.Minute,
    98  				},
    99  			},
   100  		},
   101  	}
   102  
   103  	clusters, err := cfg.NewStaticClusters(
   104  		instrument.NewOptions(),
   105  		ClustersStaticConfigurationOptions{},
   106  		NewClusterNamespacesWatcher())
   107  	require.NoError(t, err)
   108  
   109  	// Resolve expected clusters and check attributes
   110  	unaggregatedNs, initialized := clusters.UnaggregatedClusterNamespace()
   111  	assert.True(t, initialized)
   112  	assert.Equal(t, "unaggregated", unaggregatedNs.NamespaceID().String())
   113  	assert.Equal(t, storagemetadata.Attributes{
   114  		MetricsType: storagemetadata.UnaggregatedMetricsType,
   115  		Retention:   7 * 24 * time.Hour,
   116  	}, unaggregatedNs.Options().Attributes())
   117  	assert.True(t, mockSession1 == unaggregatedNs.Session())
   118  
   119  	aggregated1Month1Minute, ok := clusters.AggregatedClusterNamespace(RetentionResolution{
   120  		Retention:  30 * 24 * time.Hour,
   121  		Resolution: time.Minute,
   122  	})
   123  	require.True(t, ok)
   124  	assert.Equal(t, "aggregated0", aggregated1Month1Minute.NamespaceID().String())
   125  	assert.Equal(t, storagemetadata.Attributes{
   126  		MetricsType: storagemetadata.AggregatedMetricsType,
   127  		Retention:   30 * 24 * time.Hour,
   128  		Resolution:  time.Minute,
   129  	}, aggregated1Month1Minute.Options().Attributes())
   130  	assert.True(t, mockSession2 == aggregated1Month1Minute.Session())
   131  
   132  	aggregated1Year10Minute, ok := clusters.AggregatedClusterNamespace(RetentionResolution{
   133  		Retention:  365 * 24 * time.Hour,
   134  		Resolution: 10 * time.Minute,
   135  	})
   136  	require.True(t, ok)
   137  	assert.Equal(t, "aggregated1", aggregated1Year10Minute.NamespaceID().String())
   138  	assert.Equal(t, storagemetadata.Attributes{
   139  		MetricsType: storagemetadata.AggregatedMetricsType,
   140  		Retention:   365 * 24 * time.Hour,
   141  		Resolution:  10 * time.Minute,
   142  	}, aggregated1Year10Minute.Options().Attributes())
   143  	assert.True(t, mockSession2 == aggregated1Year10Minute.Session())
   144  
   145  	// Ensure cannot resolve unexpected clusters
   146  	_, ok = clusters.AggregatedClusterNamespace(RetentionResolution{
   147  		Retention:  time.Hour,
   148  		Resolution: time.Minute,
   149  	})
   150  	require.False(t, ok)
   151  
   152  	// Close sessions at most once each
   153  	mockSession1.EXPECT().Close().Return(nil).Times(1)
   154  	mockSession2.EXPECT().Close().Return(nil).Times(1)
   155  
   156  	err = clusters.Close()
   157  	require.NoError(t, err)
   158  }
   159  
   160  func TestNewDynamicClusters(t *testing.T) {
   161  	ctrl := xtest.NewController(t)
   162  	defer ctrl.Finish()
   163  
   164  	newClient1, session1, client1 := newTestClientFromConfigWithNamespaceInitializer(ctrl, true)
   165  	newClient2, session2, client2 := newTestClientFromConfigWithNamespaceInitializer(ctrl, true)
   166  	cfg := ClustersStaticConfiguration{
   167  		ClusterStaticConfiguration{
   168  			NewClientFromConfig: newClient1,
   169  		},
   170  		ClusterStaticConfiguration{
   171  			NewClientFromConfig: newClient2,
   172  		},
   173  	}
   174  
   175  	clusters, err := cfg.newDynamicClusters(
   176  		newNoopCluster,
   177  		instrument.NewOptions(),
   178  		ClustersStaticConfigurationOptions{},
   179  		NewClusterNamespacesWatcher())
   180  	require.NoError(t, err)
   181  
   182  	noopCluster := clusters.(*noopCluster)
   183  	sessions := []client.Session{session1, session2}
   184  	nsInits := []namespace.Initializer{client1.Options().NamespaceInitializer(), client2.Options().NamespaceInitializer()}
   185  	for i, cfg := range noopCluster.cfgs {
   186  		require.Equal(t, sessions[i], cfg.session)
   187  		require.Equal(t, nsInits[i], cfg.nsInitializer)
   188  	}
   189  }
   190  
   191  type noopCluster struct {
   192  	cfgs []DynamicClusterNamespaceConfiguration
   193  }
   194  
   195  func newNoopCluster(options DynamicClusterOptions) (Clusters, error) {
   196  	return &noopCluster{
   197  		cfgs: options.DynamicClusterNamespaceConfiguration(),
   198  	}, nil
   199  }
   200  
   201  func (n *noopCluster) Close() error {
   202  	panic("implement me")
   203  }
   204  
   205  func (n *noopCluster) ClusterNamespaces() ClusterNamespaces {
   206  	panic("implement me")
   207  }
   208  
   209  func (n *noopCluster) NonReadyClusterNamespaces() ClusterNamespaces {
   210  	panic("implement me")
   211  }
   212  
   213  func (n *noopCluster) UnaggregatedClusterNamespace() (ClusterNamespace, bool) {
   214  	panic("implement me")
   215  }
   216  
   217  func (n *noopCluster) AggregatedClusterNamespace(RetentionResolution) (ClusterNamespace, bool) {
   218  	panic("implement me")
   219  }
   220  
   221  func (n *noopCluster) ConfigType() ClusterConfigType {
   222  	panic("implement me")
   223  }
   224  
   225  func newTestClientFromConfig(ctrl *gomock.Controller) (
   226  	NewClientFromConfig,
   227  	*client.MockSession,
   228  	*client.MockClient,
   229  ) {
   230  	return newTestClientFromConfigWithNamespaceInitializer(ctrl, false)
   231  }
   232  
   233  func newTestClientFromConfigWithNamespaceInitializer(ctrl *gomock.Controller, withNsInit bool) (
   234  	NewClientFromConfig,
   235  	*client.MockSession,
   236  	*client.MockClient,
   237  ) {
   238  	mockSession := client.NewMockSession(ctrl)
   239  
   240  	mockClient := client.NewMockClient(ctrl)
   241  	mockClient.EXPECT().DefaultSession().Return(mockSession, nil).AnyTimes()
   242  
   243  	if withNsInit {
   244  		nsInit := namespace.NewMockInitializer(ctrl)
   245  		opts := client.NewOptions().
   246  			SetNamespaceInitializer(nsInit)
   247  		mockClient.EXPECT().Options().Return(opts).AnyTimes()
   248  	}
   249  
   250  	newClientFn := func(
   251  		_ client.Configuration,
   252  		_ client.ConfigurationParameters,
   253  		_ ...client.CustomAdminOption,
   254  	) (client.Client, error) {
   255  		return mockClient, nil
   256  	}
   257  
   258  	return newClientFn, mockSession, mockClient
   259  }