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  }