github.com/ystia/yorc/v4@v4.3.0/storage/store_mgr_test.go (about) 1 // Copyright 2019 Bull S.A.S. Atos Technologies - Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois, France. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package storage 16 17 import ( 18 "encoding/json" 19 "os" 20 "path" 21 "reflect" 22 "strings" 23 "testing" 24 25 "github.com/hashicorp/consul/sdk/testutil" 26 "github.com/stretchr/testify/require" 27 28 "github.com/ystia/yorc/v4/config" 29 "github.com/ystia/yorc/v4/helper/consulutil" 30 "github.com/ystia/yorc/v4/storage/store" 31 "github.com/ystia/yorc/v4/storage/types" 32 ) 33 34 // The aim of this function is to run all package tests with consul server dependency with only one consul server start 35 func TestRunConsulStoragePackageTests(t *testing.T) { 36 cfg := store.SetupTestConfig(t) 37 srv, _ := store.NewTestConsulInstance(t, &cfg) 38 defer func() { 39 srv.Stop() 40 os.RemoveAll(cfg.WorkingDirectory) 41 }() 42 43 t.Run("groupStorage", func(t *testing.T) { 44 t.Run("testLoadStoresWithNoStorageConfig", func(t *testing.T) { 45 testLoadStoresWithNoStorageConfig(t, srv, cfg) 46 }) 47 t.Run("testLoadStoresWithPartialStorageConfig", func(t *testing.T) { 48 testLoadStoresWithPartialStorageConfig(t, srv, cfg) 49 }) 50 t.Run("testLoadStoresWithPartialStorageConfig2", func(t *testing.T) { 51 testLoadStoresWithPartialStorageConfig2(t, srv, cfg) 52 }) 53 t.Run("testLoadStoresWithMissingPassphraseForCipherFileCache", func(t *testing.T) { 54 testLoadStoresWithMissingPassphraseForCipherFileCache(t, srv, cfg) 55 }) 56 t.Run("testLoadStoresWithMissingMandatoryParameters", func(t *testing.T) { 57 testLoadStoresWithMissingMandatoryParameters(t, srv, cfg) 58 }) 59 t.Run("testLoadStoresWithGeneratedName", func(t *testing.T) { 60 testLoadStoresWithGeneratedName(t, srv, cfg) 61 }) 62 }) 63 } 64 65 func testLoadStoresWithNoStorageConfig(t *testing.T, srv1 *testutil.TestServer, cfg config.Configuration) { 66 err := LoadStores(cfg) 67 require.NoError(t, err) 68 69 // Check default configuration has been saved in Consul 70 MapStores, err := consulutil.List(consulutil.StoresPrefix) 71 require.NoError(t, err) 72 require.NotNil(t, MapStores) 73 require.Len(t, MapStores, 2) 74 75 defaultStores := getDefaultConfigStores(cfg) 76 require.NotNil(t, defaultStores) 77 require.Len(t, defaultStores, 2) 78 79 for k, v := range MapStores { 80 key := path.Base(k) 81 switch key { 82 case "defaultConsulStore": 83 s := new(config.Store) 84 err = json.Unmarshal(v, s) 85 if !reflect.DeepEqual(*s, defaultStores[1]) { 86 t.Errorf("LoadStores() = %v, want %v", v, defaultStores[1]) 87 } 88 case "defaultFileStoreWithCache": 89 s := new(config.Store) 90 err = json.Unmarshal(v, s) 91 if !reflect.DeepEqual(*s, defaultStores[0]) { 92 t.Errorf("LoadStores() = %v, want %v", v, defaultStores[0]) 93 } 94 default: 95 t.Errorf("unexpected key:%q", key) 96 } 97 } 98 99 } 100 101 func testLoadStoresWithPartialStorageConfig2(t *testing.T, srv1 *testutil.TestServer, cfg config.Configuration) { 102 // Reset once to allow reload config 103 once.Reset() 104 105 deploymentID := t.Name() 106 107 obj := map[string]string{ 108 "key1": "content1", 109 "key2": "content2", 110 "key3": "content3", 111 } 112 b, err := json.Marshal(obj) 113 require.NoError(t, err) 114 115 logKeys := []string{path.Join(consulutil.LogsPrefix, deploymentID, "log0001"), 116 path.Join(consulutil.LogsPrefix, deploymentID, "log0002"), 117 path.Join(consulutil.LogsPrefix, deploymentID, "log0003")} 118 119 eventKeys := []string{path.Join(consulutil.EventsPrefix, deploymentID, "event0001"), 120 path.Join(consulutil.LogsPrefix, deploymentID, "event0002"), 121 path.Join(consulutil.LogsPrefix, deploymentID, "event0003")} 122 123 keys := append(logKeys, eventKeys...) 124 for _, key := range keys { 125 srv1.PopulateKV(t, map[string][]byte{key: b}) 126 } 127 128 srv1.PopulateKV(t, map[string][]byte{ 129 path.Join(consulutil.LogsPrefix, deploymentID, "log0001"): b, 130 path.Join(consulutil.LogsPrefix, deploymentID, "log0002"): b, 131 path.Join(consulutil.LogsPrefix, deploymentID, "log0003"): b, 132 path.Join(consulutil.EventsPrefix, deploymentID, "event0001"): b, 133 path.Join(consulutil.EventsPrefix, deploymentID, "event0002"): b, 134 path.Join(consulutil.EventsPrefix, deploymentID, "event0003"): b, 135 }) 136 137 myStore := config.Store{ 138 Name: "myPersonalStore", 139 MigrateDataFromConsul: true, 140 Implementation: "file", 141 Types: []string{"Log", "Event"}, 142 } 143 144 cfg.Storage = config.Storage{ 145 Reset: true, 146 Stores: []config.Store{myStore}, 147 } 148 149 err = LoadStores(cfg) 150 require.NoError(t, err) 151 152 // Check custom configuration + default complement has been saved in Consul 153 MapStores, err := consulutil.List(consulutil.StoresPrefix) 154 require.NoError(t, err) 155 require.NotNil(t, MapStores) 156 require.Len(t, MapStores, 2) 157 158 defaultStores := getDefaultConfigStores(cfg) 159 require.NotNil(t, defaultStores) 160 require.Len(t, defaultStores, 2) 161 162 for k, v := range MapStores { 163 key := path.Base(k) 164 switch key { 165 case "myPersonalStore": 166 s := new(config.Store) 167 err = json.Unmarshal(v, s) 168 require.NoError(t, err) 169 170 require.Equal(t, myStore.Implementation, s.Implementation) 171 require.Equal(t, myStore.Name, s.Name) 172 require.Equal(t, myStore.MigrateDataFromConsul, s.MigrateDataFromConsul) 173 require.Equal(t, myStore.Types, s.Types) 174 require.Equal(t, path.Join(cfg.WorkingDirectory, defaultRelativeRootDir), s.Properties["root_dir"]) 175 require.Equal(t, defaultCacheNumCounters, s.Properties["cache_num_counters"]) 176 require.Equal(t, defaultCacheMaxCost, s.Properties["cache_max_cost"]) 177 require.Equal(t, defaultCacheBufferItems, s.Properties["cache_buffer_items"]) 178 case "defaultFileStoreWithCache": 179 s := new(config.Store) 180 err = json.Unmarshal(v, s) 181 if !reflect.DeepEqual(*s, defaultStores[0]) { 182 t.Errorf("LoadStores() = %v, want %v", *s, defaultStores[0]) 183 } 184 default: 185 t.Errorf("unexpected key:%q", key) 186 } 187 } 188 189 value := new(map[string]string) 190 for _, key := range logKeys { 191 exist, err := GetStore(types.StoreTypeLog).Get(key, value) 192 require.NoError(t, err) 193 require.True(t, exist) 194 require.NotNil(t, value) 195 val := *value 196 require.Equal(t, "content1", val["key1"]) 197 } 198 for _, key := range eventKeys { 199 exist, err := GetStore(types.StoreTypeEvent).Get(key, value) 200 require.NoError(t, err) 201 require.True(t, exist) 202 require.NotNil(t, value) 203 val := *value 204 require.Equal(t, "content1", val["key1"]) 205 } 206 } 207 208 func testLoadStoresWithPartialStorageConfig(t *testing.T, srv1 *testutil.TestServer, cfg config.Configuration) { 209 // Reset once to allow reload config 210 once.Reset() 211 212 deploymentID := t.Name() 213 214 obj := map[string]string{ 215 "key1": "content1", 216 "key2": "content2", 217 "key3": "content3", 218 } 219 b, err := json.Marshal(obj) 220 require.NoError(t, err) 221 222 logKeys := []string{path.Join(consulutil.LogsPrefix, deploymentID, "log0001"), 223 path.Join(consulutil.LogsPrefix, deploymentID, "log0002"), 224 path.Join(consulutil.LogsPrefix, deploymentID, "log0003")} 225 226 eventKeys := []string{path.Join(consulutil.EventsPrefix, deploymentID, "event0001"), 227 path.Join(consulutil.LogsPrefix, deploymentID, "event0002"), 228 path.Join(consulutil.LogsPrefix, deploymentID, "event0003")} 229 230 keys := append(logKeys, eventKeys...) 231 for _, key := range keys { 232 srv1.PopulateKV(t, map[string][]byte{key: b}) 233 } 234 235 srv1.PopulateKV(t, map[string][]byte{ 236 path.Join(consulutil.LogsPrefix, deploymentID, "log0001"): b, 237 path.Join(consulutil.LogsPrefix, deploymentID, "log0002"): b, 238 path.Join(consulutil.LogsPrefix, deploymentID, "log0003"): b, 239 path.Join(consulutil.EventsPrefix, deploymentID, "event0001"): b, 240 path.Join(consulutil.EventsPrefix, deploymentID, "event0002"): b, 241 path.Join(consulutil.EventsPrefix, deploymentID, "event0003"): b, 242 }) 243 244 myStore := config.Store{ 245 Name: "myPersonalStore", 246 MigrateDataFromConsul: true, 247 Implementation: "cipherFileCache", 248 Types: []string{"Log", "Event"}, 249 Properties: config.DynamicMap{ 250 "passphrase": "myverystrongpasswordo32bitlength", 251 }, 252 } 253 254 cfg.Storage = config.Storage{ 255 Reset: true, 256 Stores: []config.Store{myStore}, 257 } 258 259 err = LoadStores(cfg) 260 require.NoError(t, err) 261 262 // Check custom configuration + default complement has been saved in Consul 263 MapStores, err := consulutil.List(consulutil.StoresPrefix) 264 require.NoError(t, err) 265 require.NotNil(t, MapStores) 266 require.Len(t, MapStores, 2) 267 268 defaultStores := getDefaultConfigStores(cfg) 269 require.NotNil(t, defaultStores) 270 require.Len(t, defaultStores, 2) 271 272 for k, v := range MapStores { 273 key := path.Base(k) 274 switch key { 275 case "myPersonalStore": 276 s := new(config.Store) 277 err = json.Unmarshal(v, s) 278 require.NoError(t, err) 279 280 require.Equal(t, myStore.Implementation, s.Implementation) 281 require.Equal(t, myStore.Name, s.Name) 282 require.Equal(t, myStore.MigrateDataFromConsul, s.MigrateDataFromConsul) 283 require.Equal(t, myStore.Types, s.Types) 284 require.Equal(t, myStore.Properties["passphrase"], s.Properties["passphrase"]) 285 require.Equal(t, path.Join(cfg.WorkingDirectory, defaultRelativeRootDir), s.Properties["root_dir"]) 286 require.Equal(t, defaultCacheNumCounters, s.Properties["cache_num_counters"]) 287 require.Equal(t, defaultCacheMaxCost, s.Properties["cache_max_cost"]) 288 require.Equal(t, defaultCacheBufferItems, s.Properties["cache_buffer_items"]) 289 case "defaultFileStoreWithCache": 290 s := new(config.Store) 291 err = json.Unmarshal(v, s) 292 if !reflect.DeepEqual(*s, defaultStores[0]) { 293 t.Errorf("LoadStores() = %v, want %v", *s, defaultStores[0]) 294 } 295 default: 296 t.Errorf("unexpected key:%q", key) 297 } 298 } 299 300 value := new(map[string]string) 301 for _, key := range logKeys { 302 exist, err := GetStore(types.StoreTypeLog).Get(key, value) 303 require.NoError(t, err) 304 require.True(t, exist) 305 require.NotNil(t, value) 306 val := *value 307 require.Equal(t, "content1", val["key1"]) 308 } 309 for _, key := range eventKeys { 310 exist, err := GetStore(types.StoreTypeEvent).Get(key, value) 311 require.NoError(t, err) 312 require.True(t, exist) 313 require.NotNil(t, value) 314 val := *value 315 require.Equal(t, "content1", val["key1"]) 316 } 317 } 318 319 func testLoadStoresWithMissingPassphraseForCipherFileCache(t *testing.T, srv1 *testutil.TestServer, cfg config.Configuration) { 320 // Reset once to allow reload config 321 once.Reset() 322 323 myStore := config.Store{ 324 Name: "myPersonalStore", 325 Implementation: "cipherFileCache", 326 Types: []string{"Log", "Event"}, 327 Properties: config.DynamicMap{ 328 // "passphrase": "myverystrongpasswordo32bitlength", 329 }, 330 } 331 332 cfg.Storage = config.Storage{ 333 Reset: true, 334 Stores: []config.Store{myStore}, 335 } 336 337 err := LoadStores(cfg) 338 require.Error(t, err) 339 340 // Check stores config has been cleared in Consul 341 MapStores, err := consulutil.List(consulutil.StoresPrefix) 342 require.NoError(t, err) 343 require.NotNil(t, MapStores) 344 require.Len(t, MapStores, 0) 345 } 346 347 func testLoadStoresWithMissingMandatoryParameters(t *testing.T, srv1 *testutil.TestServer, cfg config.Configuration) { 348 tests := []struct { 349 name string 350 myStores []config.Store 351 }{ 352 {"storeWithoutImplementation", []config.Store{{ 353 Name: "myStore", 354 Types: []string{"Log", "Event"}, 355 }}}, 356 {"storeWithoutTypes", []config.Store{{ 357 Name: "myStore", 358 Implementation: "consul", 359 }}}, 360 {"storeWithoutTypes2", []config.Store{{ 361 Name: "myStore", 362 Implementation: "consul", 363 Types: []string{}, 364 }}}, 365 {"TwoStoreWithTheSameName", []config.Store{{ 366 Name: "myStore", 367 Implementation: "consul", 368 Types: []string{"Log", "Event"}, 369 }, 370 { 371 Name: "myStore", 372 Implementation: "consul", 373 Types: []string{"Log", "Event"}, 374 }}}, 375 } 376 for _, tt := range tests { 377 t.Run(tt.name, func(t *testing.T) { 378 // Reset once to allow reload config 379 once.Reset() 380 381 cfg.Storage = config.Storage{ 382 Reset: true, 383 Stores: tt.myStores, 384 } 385 386 err := LoadStores(cfg) 387 require.Error(t, err) 388 389 // Check stores config has been cleared in Consul 390 MapStores, err := consulutil.List(consulutil.StoresPrefix) 391 require.NoError(t, err) 392 require.NotNil(t, MapStores) 393 require.Len(t, MapStores, 0) 394 }) 395 } 396 397 } 398 399 func testLoadStoresWithGeneratedName(t *testing.T, srv1 *testutil.TestServer, cfg config.Configuration) { 400 tests := []struct { 401 name string 402 myStores []config.Store 403 }{ 404 {"storeWithoutName", []config.Store{{ 405 Name: "", 406 Implementation: "consul", 407 Types: []string{"Log", "Event"}, 408 }, 409 { 410 Name: "", 411 Implementation: "consul", 412 Types: []string{"Log", "Event"}, 413 }, 414 }}, 415 } 416 for _, tt := range tests { 417 t.Run(tt.name, func(t *testing.T) { 418 // Reset once to allow reload config 419 once.Reset() 420 421 cfg.Storage = config.Storage{ 422 Reset: true, 423 Stores: tt.myStores, 424 } 425 426 err := LoadStores(cfg) 427 require.NoError(t, err) 428 MapStores, err := consulutil.List(consulutil.StoresPrefix) 429 require.NoError(t, err) 430 require.NotNil(t, MapStores) 431 require.Len(t, MapStores, 2) 432 433 for k, _ := range MapStores { 434 if !strings.Contains(k, "default") { 435 store := new(config.Store) 436 err = json.Unmarshal(MapStores[k], store) 437 require.True(t, strings.HasPrefix(store.Name, "consulLogEvent-")) 438 require.NoError(t, err) 439 } 440 } 441 }) 442 } 443 }