github.com/ashishbhate/mattermost-server@v5.11.1+incompatible/config/memory_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package config_test
     5  
     6  import (
     7  	"os"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  
    14  	"github.com/mattermost/mattermost-server/config"
    15  	"github.com/mattermost/mattermost-server/model"
    16  )
    17  
    18  func setupConfigMemory(t *testing.T) {
    19  	t.Helper()
    20  	os.Clearenv()
    21  }
    22  
    23  func TestMemoryStoreNew(t *testing.T) {
    24  	t.Run("no existing configuration - initialization required", func(t *testing.T) {
    25  		ms, err := config.NewMemoryStore()
    26  		require.NoError(t, err)
    27  		defer ms.Close()
    28  
    29  		assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ms.Get().ServiceSettings.SiteURL)
    30  	})
    31  
    32  	t.Run("existing config, initialization required", func(t *testing.T) {
    33  		setupConfigMemory(t)
    34  
    35  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: testConfig})
    36  		require.NoError(t, err)
    37  		defer ms.Close()
    38  
    39  		assert.Equal(t, "http://TestStoreNew", *ms.Get().ServiceSettings.SiteURL)
    40  	})
    41  
    42  	t.Run("already minimally configured", func(t *testing.T) {
    43  		setupConfigMemory(t)
    44  
    45  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: minimalConfig})
    46  		require.NoError(t, err)
    47  		defer ms.Close()
    48  
    49  		assert.Equal(t, "http://minimal", *ms.Get().ServiceSettings.SiteURL)
    50  	})
    51  
    52  	t.Run("invalid config, validation enabled", func(t *testing.T) {
    53  		_, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: invalidConfig})
    54  		require.Error(t, err)
    55  	})
    56  
    57  	t.Run("invalid config, validation disabled", func(t *testing.T) {
    58  		_, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: invalidConfig, SkipValidation: true})
    59  		require.NoError(t, err)
    60  	})
    61  }
    62  
    63  func TestMemoryStoreGet(t *testing.T) {
    64  	setupConfigMemory(t)
    65  
    66  	ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: testConfig})
    67  	require.NoError(t, err)
    68  	defer ms.Close()
    69  
    70  	cfg := ms.Get()
    71  	assert.Equal(t, "http://TestStoreNew", *cfg.ServiceSettings.SiteURL)
    72  
    73  	cfg2 := ms.Get()
    74  	assert.Equal(t, "http://TestStoreNew", *cfg.ServiceSettings.SiteURL)
    75  
    76  	assert.True(t, cfg == cfg2, "Get() returned different configuration instances")
    77  
    78  	newCfg := &model.Config{}
    79  	oldCfg, err := ms.Set(newCfg)
    80  	require.NoError(t, err)
    81  
    82  	assert.True(t, oldCfg == cfg, "returned config after set() changed original")
    83  	assert.False(t, newCfg == cfg, "returned config should have been different from original")
    84  }
    85  
    86  func TestMemoryStoreGetEnivironmentOverrides(t *testing.T) {
    87  	setupConfigMemory(t)
    88  
    89  	ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: testConfig})
    90  	require.NoError(t, err)
    91  	defer ms.Close()
    92  
    93  	assert.Equal(t, "http://TestStoreNew", *ms.Get().ServiceSettings.SiteURL)
    94  	assert.Empty(t, ms.GetEnvironmentOverrides())
    95  
    96  	os.Setenv("MM_SERVICESETTINGS_SITEURL", "http://override")
    97  
    98  	ms, err = config.NewMemoryStore()
    99  	require.NoError(t, err)
   100  	defer ms.Close()
   101  
   102  	assert.Equal(t, "http://override", *ms.Get().ServiceSettings.SiteURL)
   103  	assert.Equal(t, map[string]interface{}{"ServiceSettings": map[string]interface{}{"SiteURL": true}}, ms.GetEnvironmentOverrides())
   104  }
   105  
   106  func TestMemoryStoreSet(t *testing.T) {
   107  	t.Run("set same pointer value", func(t *testing.T) {
   108  		t.Skip("not yet implemented")
   109  
   110  		setupConfigMemory(t)
   111  
   112  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: emptyConfig})
   113  		require.NoError(t, err)
   114  		defer ms.Close()
   115  
   116  		_, err = ms.Set(ms.Get())
   117  		if assert.Error(t, err) {
   118  			assert.EqualError(t, err, "old configuration modified instead of cloning")
   119  		}
   120  	})
   121  
   122  	t.Run("defaults required", func(t *testing.T) {
   123  		setupConfigMemory(t)
   124  
   125  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: minimalConfig})
   126  		require.NoError(t, err)
   127  		defer ms.Close()
   128  
   129  		oldCfg := ms.Get()
   130  
   131  		newCfg := &model.Config{}
   132  
   133  		retCfg, err := ms.Set(newCfg)
   134  		require.NoError(t, err)
   135  		assert.Equal(t, oldCfg, retCfg)
   136  
   137  		assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ms.Get().ServiceSettings.SiteURL)
   138  	})
   139  
   140  	t.Run("desanitization required", func(t *testing.T) {
   141  		setupConfigMemory(t)
   142  
   143  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: ldapConfig})
   144  		require.NoError(t, err)
   145  		defer ms.Close()
   146  
   147  		oldCfg := ms.Get()
   148  
   149  		newCfg := &model.Config{}
   150  		newCfg.LdapSettings.BindPassword = sToP(model.FAKE_SETTING)
   151  
   152  		retCfg, err := ms.Set(newCfg)
   153  		require.NoError(t, err)
   154  		assert.Equal(t, oldCfg, retCfg)
   155  
   156  		assert.Equal(t, "password", *ms.Get().LdapSettings.BindPassword)
   157  	})
   158  
   159  	t.Run("invalid", func(t *testing.T) {
   160  		setupConfigMemory(t)
   161  
   162  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: emptyConfig})
   163  		require.NoError(t, err)
   164  		defer ms.Close()
   165  
   166  		newCfg := &model.Config{}
   167  		newCfg.ServiceSettings.SiteURL = sToP("invalid")
   168  
   169  		_, err = ms.Set(newCfg)
   170  		if assert.Error(t, err) {
   171  			assert.EqualError(t, err, "new configuration is invalid: Config.IsValid: model.config.is_valid.site_url.app_error, ")
   172  		}
   173  
   174  		assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ms.Get().ServiceSettings.SiteURL)
   175  	})
   176  
   177  	t.Run("read-only ignored", func(t *testing.T) {
   178  		setupConfigMemory(t)
   179  
   180  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: readOnlyConfig})
   181  		require.NoError(t, err)
   182  		defer ms.Close()
   183  
   184  		newCfg := &model.Config{
   185  			ServiceSettings: model.ServiceSettings{
   186  				SiteURL: sToP("http://new"),
   187  			},
   188  		}
   189  
   190  		_, err = ms.Set(newCfg)
   191  		require.NoError(t, err)
   192  
   193  		assert.Equal(t, "http://new", *ms.Get().ServiceSettings.SiteURL)
   194  	})
   195  
   196  	t.Run("listeners notified", func(t *testing.T) {
   197  		setupConfigMemory(t)
   198  
   199  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: emptyConfig})
   200  		require.NoError(t, err)
   201  		defer ms.Close()
   202  
   203  		oldCfg := ms.Get()
   204  
   205  		called := make(chan bool, 1)
   206  		callback := func(oldfg, newCfg *model.Config) {
   207  			called <- true
   208  		}
   209  		ms.AddListener(callback)
   210  
   211  		newCfg := &model.Config{}
   212  
   213  		retCfg, err := ms.Set(newCfg)
   214  		require.NoError(t, err)
   215  		assert.Equal(t, oldCfg, retCfg)
   216  
   217  		select {
   218  		case <-called:
   219  		case <-time.After(5 * time.Second):
   220  			t.Fatal("callback should have been called when config written")
   221  		}
   222  	})
   223  }
   224  
   225  func TestMemoryStoreLoad(t *testing.T) {
   226  	t.Run("honour environment", func(t *testing.T) {
   227  		setupConfigMemory(t)
   228  
   229  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: minimalConfig})
   230  		require.NoError(t, err)
   231  		defer ms.Close()
   232  
   233  		os.Setenv("MM_SERVICESETTINGS_SITEURL", "http://override")
   234  
   235  		err = ms.Load()
   236  		require.NoError(t, err)
   237  		assert.Equal(t, "http://override", *ms.Get().ServiceSettings.SiteURL)
   238  		assert.Equal(t, map[string]interface{}{"ServiceSettings": map[string]interface{}{"SiteURL": true}}, ms.GetEnvironmentOverrides())
   239  	})
   240  
   241  	t.Run("fixes required", func(t *testing.T) {
   242  		setupConfigMemory(t)
   243  
   244  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: fixesRequiredConfig})
   245  		require.NoError(t, err)
   246  		defer ms.Close()
   247  
   248  		err = ms.Load()
   249  		require.NoError(t, err)
   250  		assert.Equal(t, "http://trailingslash", *ms.Get().ServiceSettings.SiteURL)
   251  	})
   252  
   253  	t.Run("listeners notifed", func(t *testing.T) {
   254  		setupConfigMemory(t)
   255  
   256  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: emptyConfig})
   257  		require.NoError(t, err)
   258  		defer ms.Close()
   259  
   260  		called := make(chan bool, 1)
   261  		callback := func(oldfg, newCfg *model.Config) {
   262  			called <- true
   263  		}
   264  		ms.AddListener(callback)
   265  
   266  		err = ms.Load()
   267  		require.NoError(t, err)
   268  
   269  		select {
   270  		case <-called:
   271  		case <-time.After(5 * time.Second):
   272  			t.Fatal("callback should have been called when config loaded")
   273  		}
   274  	})
   275  }
   276  
   277  func TestMemoryGetFile(t *testing.T) {
   278  	setupConfigMemory(t)
   279  
   280  	ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{
   281  		InitialConfig: minimalConfig,
   282  		InitialFiles: map[string][]byte{
   283  			"empty-file": []byte{},
   284  			"test-file":  []byte("test"),
   285  		},
   286  	})
   287  	require.NoError(t, err)
   288  	defer ms.Close()
   289  
   290  	t.Run("get empty filename", func(t *testing.T) {
   291  		_, err := ms.GetFile("")
   292  		require.Error(t, err)
   293  	})
   294  
   295  	t.Run("get non-existent file", func(t *testing.T) {
   296  		_, err := ms.GetFile("unknown")
   297  		require.Error(t, err)
   298  	})
   299  
   300  	t.Run("get empty file", func(t *testing.T) {
   301  		data, err := ms.GetFile("empty-file")
   302  		require.NoError(t, err)
   303  		require.Empty(t, data)
   304  	})
   305  
   306  	t.Run("get non-empty file", func(t *testing.T) {
   307  		data, err := ms.GetFile("test-file")
   308  		require.NoError(t, err)
   309  		require.Equal(t, []byte("test"), data)
   310  	})
   311  }
   312  
   313  func TestMemorySetFile(t *testing.T) {
   314  	setupConfigMemory(t)
   315  
   316  	ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{
   317  		InitialConfig: minimalConfig,
   318  	})
   319  	require.NoError(t, err)
   320  	defer ms.Close()
   321  
   322  	t.Run("set new file", func(t *testing.T) {
   323  		err := ms.SetFile("new", []byte("new file"))
   324  		require.NoError(t, err)
   325  
   326  		data, err := ms.GetFile("new")
   327  		require.NoError(t, err)
   328  		require.Equal(t, []byte("new file"), data)
   329  	})
   330  
   331  	t.Run("overwrite existing file", func(t *testing.T) {
   332  		err := ms.SetFile("existing", []byte("existing file"))
   333  		require.NoError(t, err)
   334  
   335  		err = ms.SetFile("existing", []byte("overwritten file"))
   336  		require.NoError(t, err)
   337  
   338  		data, err := ms.GetFile("existing")
   339  		require.NoError(t, err)
   340  		require.Equal(t, []byte("overwritten file"), data)
   341  	})
   342  }
   343  
   344  func TestMemoryHasFile(t *testing.T) {
   345  	t.Run("has non-existent", func(t *testing.T) {
   346  		setupConfigMemory(t)
   347  
   348  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{
   349  			InitialConfig: minimalConfig,
   350  		})
   351  		require.NoError(t, err)
   352  		defer ms.Close()
   353  
   354  		has, err := ms.HasFile("non-existent")
   355  		require.NoError(t, err)
   356  		require.False(t, has)
   357  	})
   358  
   359  	t.Run("has existing", func(t *testing.T) {
   360  		setupConfigMemory(t)
   361  
   362  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{
   363  			InitialConfig: minimalConfig,
   364  		})
   365  		require.NoError(t, err)
   366  		defer ms.Close()
   367  
   368  		err = ms.SetFile("existing", []byte("existing file"))
   369  		require.NoError(t, err)
   370  
   371  		has, err := ms.HasFile("existing")
   372  		require.NoError(t, err)
   373  		require.True(t, has)
   374  	})
   375  
   376  	t.Run("has manually created file", func(t *testing.T) {
   377  		setupConfigMemory(t)
   378  
   379  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{
   380  			InitialConfig: minimalConfig,
   381  			InitialFiles: map[string][]byte{
   382  				"manual": []byte("manual file"),
   383  			},
   384  		})
   385  		require.NoError(t, err)
   386  		defer ms.Close()
   387  
   388  		has, err := ms.HasFile("manual")
   389  		require.NoError(t, err)
   390  		require.True(t, has)
   391  	})
   392  }
   393  
   394  func TestMemoryRemoveFile(t *testing.T) {
   395  	t.Run("remove non-existent", func(t *testing.T) {
   396  		setupConfigMemory(t)
   397  
   398  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{
   399  			InitialConfig: minimalConfig,
   400  		})
   401  		require.NoError(t, err)
   402  		defer ms.Close()
   403  
   404  		err = ms.RemoveFile("non-existent")
   405  		require.NoError(t, err)
   406  	})
   407  
   408  	t.Run("remove existing", func(t *testing.T) {
   409  		setupConfigMemory(t)
   410  
   411  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{
   412  			InitialConfig: minimalConfig,
   413  		})
   414  		require.NoError(t, err)
   415  		defer ms.Close()
   416  
   417  		err = ms.SetFile("existing", []byte("existing file"))
   418  		require.NoError(t, err)
   419  
   420  		err = ms.RemoveFile("existing")
   421  		require.NoError(t, err)
   422  
   423  		has, err := ms.HasFile("existing")
   424  		require.NoError(t, err)
   425  		require.False(t, has)
   426  
   427  		_, err = ms.GetFile("existing")
   428  		require.Error(t, err)
   429  	})
   430  
   431  	t.Run("remove manually created file", func(t *testing.T) {
   432  		setupConfigMemory(t)
   433  
   434  		ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{
   435  			InitialConfig: minimalConfig,
   436  			InitialFiles: map[string][]byte{
   437  				"manual": []byte("manual file"),
   438  			},
   439  		})
   440  		require.NoError(t, err)
   441  		defer ms.Close()
   442  
   443  		err = ms.RemoveFile("manual")
   444  		require.NoError(t, err)
   445  
   446  		has, err := ms.HasFile("manual")
   447  		require.NoError(t, err)
   448  		require.False(t, has)
   449  
   450  		_, err = ms.GetFile("manual")
   451  		require.Error(t, err)
   452  	})
   453  }
   454  
   455  func TestMemoryStoreString(t *testing.T) {
   456  	setupConfigMemory(t)
   457  
   458  	ms, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{InitialConfig: emptyConfig})
   459  	require.NoError(t, err)
   460  	defer ms.Close()
   461  
   462  	assert.Equal(t, "memory://", ms.String())
   463  }