github.com/cryptomisa/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 }