github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/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 }