github.com/ilgooz/mattermost-server@v5.11.1+incompatible/config/file_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 "io/ioutil" 8 "os" 9 "path/filepath" 10 "strings" 11 "testing" 12 "time" 13 14 "github.com/pkg/errors" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 18 "github.com/mattermost/mattermost-server/config" 19 "github.com/mattermost/mattermost-server/model" 20 "github.com/mattermost/mattermost-server/utils" 21 ) 22 23 func setupConfigFile(t *testing.T, cfg *model.Config) (string, func()) { 24 os.Clearenv() 25 t.Helper() 26 27 tempDir, err := ioutil.TempDir("", "setupConfigFile") 28 require.NoError(t, err) 29 30 err = os.Chdir(tempDir) 31 require.NoError(t, err) 32 33 var name string 34 if cfg != nil { 35 f, err := ioutil.TempFile(tempDir, "setupConfigFile") 36 require.NoError(t, err) 37 38 cfgData, err := config.MarshalConfig(cfg) 39 require.NoError(t, err) 40 41 ioutil.WriteFile(f.Name(), cfgData, 0644) 42 43 name = f.Name() 44 } 45 46 return name, func() { 47 os.RemoveAll(tempDir) 48 } 49 } 50 51 // getActualFileConfig returns the configuration present in the given file without relying a config store. 52 func getActualFileConfig(t *testing.T, path string) *model.Config { 53 t.Helper() 54 55 f, err := os.Open(path) 56 require.Nil(t, err) 57 defer f.Close() 58 59 actualCfg, _, err := config.UnmarshalConfig(f, false) 60 require.Nil(t, err) 61 62 return actualCfg 63 } 64 65 // assertFileEqualsConfig verifies the on disk contents of the given path equal the given config. 66 func assertFileEqualsConfig(t *testing.T, expectedCfg *model.Config, path string) { 67 t.Helper() 68 69 expectedCfg = prepareExpectedConfig(t, expectedCfg) 70 actualCfg := getActualFileConfig(t, path) 71 72 assert.Equal(t, expectedCfg, actualCfg) 73 } 74 75 // assertFileNotEqualsConfig verifies the on disk contents of the given path does not equal the given config. 76 func assertFileNotEqualsConfig(t *testing.T, expectedCfg *model.Config, path string) { 77 t.Helper() 78 79 expectedCfg = prepareExpectedConfig(t, expectedCfg) 80 actualCfg := getActualFileConfig(t, path) 81 82 assert.NotEqual(t, expectedCfg, actualCfg) 83 } 84 85 func TestFileStoreNew(t *testing.T) { 86 utils.TranslationsPreInit() 87 88 t.Run("absolute path, initialization required", func(t *testing.T) { 89 path, tearDown := setupConfigFile(t, testConfig) 90 defer tearDown() 91 92 fs, err := config.NewFileStore(path, false) 93 require.NoError(t, err) 94 defer fs.Close() 95 96 assert.Equal(t, "http://TestStoreNew", *fs.Get().ServiceSettings.SiteURL) 97 assertFileNotEqualsConfig(t, testConfig, path) 98 }) 99 100 t.Run("absolute path, already minimally configured", func(t *testing.T) { 101 path, tearDown := setupConfigFile(t, minimalConfig) 102 defer tearDown() 103 104 fs, err := config.NewFileStore(path, false) 105 require.NoError(t, err) 106 defer fs.Close() 107 108 assert.Equal(t, "http://minimal", *fs.Get().ServiceSettings.SiteURL) 109 assertFileEqualsConfig(t, minimalConfig, path) 110 }) 111 112 t.Run("absolute path, file does not exist", func(t *testing.T) { 113 _, tearDown := setupConfigFile(t, nil) 114 defer tearDown() 115 116 tempDir, err := ioutil.TempDir("", "TestFileStoreNew") 117 require.NoError(t, err) 118 defer os.RemoveAll(tempDir) 119 120 path := filepath.Join(tempDir, "does_not_exist") 121 fs, err := config.NewFileStore(path, false) 122 require.NoError(t, err) 123 defer fs.Close() 124 125 assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *fs.Get().ServiceSettings.SiteURL) 126 assertFileNotEqualsConfig(t, testConfig, path) 127 }) 128 129 t.Run("absolute path, path to file does not exist", func(t *testing.T) { 130 _, tearDown := setupConfigFile(t, nil) 131 defer tearDown() 132 133 tempDir, err := ioutil.TempDir("", "TestFileStoreNew") 134 require.NoError(t, err) 135 defer os.RemoveAll(tempDir) 136 137 path := filepath.Join(tempDir, "does/not/exist") 138 _, err = config.NewFileStore(path, false) 139 require.Error(t, err) 140 }) 141 142 t.Run("relative path, file exists", func(t *testing.T) { 143 _, tearDown := setupConfigFile(t, nil) 144 defer tearDown() 145 146 err := os.MkdirAll("TestFileStoreNew/a/b/c", 0700) 147 require.NoError(t, err) 148 defer os.RemoveAll("TestFileStoreNew") 149 150 path := "TestFileStoreNew/a/b/c/config.json" 151 152 cfgData, err := config.MarshalConfig(testConfig) 153 require.NoError(t, err) 154 155 ioutil.WriteFile(path, cfgData, 0644) 156 157 fs, err := config.NewFileStore(path, false) 158 require.NoError(t, err) 159 defer fs.Close() 160 161 assert.Equal(t, "http://TestStoreNew", *fs.Get().ServiceSettings.SiteURL) 162 assertFileNotEqualsConfig(t, testConfig, path) 163 }) 164 165 t.Run("relative path, file does not exist", func(t *testing.T) { 166 _, tearDown := setupConfigFile(t, nil) 167 defer tearDown() 168 169 err := os.MkdirAll("config/TestFileStoreNew/a/b/c", 0700) 170 require.NoError(t, err) 171 defer os.RemoveAll("config/TestFileStoreNew") 172 173 path := "TestFileStoreNew/a/b/c/config.json" 174 fs, err := config.NewFileStore(path, false) 175 require.NoError(t, err) 176 defer fs.Close() 177 178 assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *fs.Get().ServiceSettings.SiteURL) 179 assertFileNotEqualsConfig(t, testConfig, filepath.Join("config", path)) 180 }) 181 } 182 183 func TestFileStoreGet(t *testing.T) { 184 path, tearDown := setupConfigFile(t, testConfig) 185 defer tearDown() 186 187 fs, err := config.NewFileStore(path, false) 188 require.NoError(t, err) 189 defer fs.Close() 190 191 cfg := fs.Get() 192 assert.Equal(t, "http://TestStoreNew", *cfg.ServiceSettings.SiteURL) 193 194 cfg2 := fs.Get() 195 assert.Equal(t, "http://TestStoreNew", *cfg.ServiceSettings.SiteURL) 196 197 assert.True(t, cfg == cfg2, "Get() returned different configuration instances") 198 199 newCfg := &model.Config{} 200 oldCfg, err := fs.Set(newCfg) 201 202 assert.True(t, oldCfg == cfg, "returned config after set() changed original") 203 assert.False(t, newCfg == cfg, "returned config should have been different from original") 204 } 205 206 func TestFileStoreGetEnivironmentOverrides(t *testing.T) { 207 path, tearDown := setupConfigFile(t, testConfig) 208 defer tearDown() 209 210 fs, err := config.NewFileStore(path, false) 211 require.NoError(t, err) 212 defer fs.Close() 213 214 assert.Equal(t, "http://TestStoreNew", *fs.Get().ServiceSettings.SiteURL) 215 assert.Empty(t, fs.GetEnvironmentOverrides()) 216 217 os.Setenv("MM_SERVICESETTINGS_SITEURL", "http://override") 218 219 fs, err = config.NewFileStore(path, false) 220 require.NoError(t, err) 221 defer fs.Close() 222 223 assert.Equal(t, "http://override", *fs.Get().ServiceSettings.SiteURL) 224 assert.Equal(t, map[string]interface{}{"ServiceSettings": map[string]interface{}{"SiteURL": true}}, fs.GetEnvironmentOverrides()) 225 } 226 227 func TestFileStoreSet(t *testing.T) { 228 t.Run("set same pointer value", func(t *testing.T) { 229 t.Skip("not yet implemented") 230 231 path, tearDown := setupConfigFile(t, emptyConfig) 232 defer tearDown() 233 234 fs, err := config.NewFileStore(path, false) 235 require.NoError(t, err) 236 defer fs.Close() 237 238 _, err = fs.Set(fs.Get()) 239 if assert.Error(t, err) { 240 assert.EqualError(t, err, "old configuration modified instead of cloning") 241 } 242 }) 243 244 t.Run("defaults required", func(t *testing.T) { 245 path, tearDown := setupConfigFile(t, minimalConfig) 246 defer tearDown() 247 248 fs, err := config.NewFileStore(path, false) 249 require.NoError(t, err) 250 defer fs.Close() 251 252 oldCfg := fs.Get() 253 254 newCfg := &model.Config{} 255 256 retCfg, err := fs.Set(newCfg) 257 require.NoError(t, err) 258 assert.Equal(t, oldCfg, retCfg) 259 260 assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *fs.Get().ServiceSettings.SiteURL) 261 }) 262 263 t.Run("desanitization required", func(t *testing.T) { 264 path, tearDown := setupConfigFile(t, ldapConfig) 265 defer tearDown() 266 267 fs, err := config.NewFileStore(path, false) 268 require.NoError(t, err) 269 defer fs.Close() 270 271 oldCfg := fs.Get() 272 273 newCfg := &model.Config{} 274 newCfg.LdapSettings.BindPassword = sToP(model.FAKE_SETTING) 275 276 retCfg, err := fs.Set(newCfg) 277 require.NoError(t, err) 278 assert.Equal(t, oldCfg, retCfg) 279 280 assert.Equal(t, "password", *fs.Get().LdapSettings.BindPassword) 281 }) 282 283 t.Run("invalid", func(t *testing.T) { 284 path, tearDown := setupConfigFile(t, emptyConfig) 285 defer tearDown() 286 287 fs, err := config.NewFileStore(path, false) 288 require.NoError(t, err) 289 defer fs.Close() 290 291 newCfg := &model.Config{} 292 newCfg.ServiceSettings.SiteURL = sToP("invalid") 293 294 _, err = fs.Set(newCfg) 295 if assert.Error(t, err) { 296 assert.EqualError(t, err, "new configuration is invalid: Config.IsValid: model.config.is_valid.site_url.app_error, ") 297 } 298 299 assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *fs.Get().ServiceSettings.SiteURL) 300 }) 301 302 t.Run("read-only", func(t *testing.T) { 303 path, tearDown := setupConfigFile(t, readOnlyConfig) 304 defer tearDown() 305 306 fs, err := config.NewFileStore(path, false) 307 require.NoError(t, err) 308 defer fs.Close() 309 310 newCfg := &model.Config{} 311 312 _, err = fs.Set(newCfg) 313 if assert.Error(t, err) { 314 assert.Equal(t, config.ErrReadOnlyConfiguration, errors.Cause(err)) 315 } 316 317 assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *fs.Get().ServiceSettings.SiteURL) 318 }) 319 320 t.Run("persist failed", func(t *testing.T) { 321 t.Skip("skipping persistence test inside Set") 322 path, tearDown := setupConfigFile(t, emptyConfig) 323 defer tearDown() 324 325 fs, err := config.NewFileStore(path, false) 326 require.NoError(t, err) 327 defer fs.Close() 328 329 os.Chmod(path, 0500) 330 331 newCfg := &model.Config{} 332 333 _, err = fs.Set(newCfg) 334 if assert.Error(t, err) { 335 assert.True(t, strings.HasPrefix(err.Error(), "failed to persist: failed to write file")) 336 } 337 338 assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *fs.Get().ServiceSettings.SiteURL) 339 }) 340 341 t.Run("listeners notified", func(t *testing.T) { 342 path, tearDown := setupConfigFile(t, emptyConfig) 343 defer tearDown() 344 345 fs, err := config.NewFileStore(path, false) 346 require.NoError(t, err) 347 defer fs.Close() 348 349 oldCfg := fs.Get() 350 351 called := make(chan bool, 1) 352 callback := func(oldfg, newCfg *model.Config) { 353 called <- true 354 } 355 fs.AddListener(callback) 356 357 newCfg := &model.Config{} 358 359 retCfg, err := fs.Set(newCfg) 360 require.NoError(t, err) 361 assert.Equal(t, oldCfg, retCfg) 362 363 select { 364 case <-called: 365 case <-time.After(5 * time.Second): 366 t.Fatal("callback should have been called when config written") 367 } 368 }) 369 370 t.Run("watcher restarted", func(t *testing.T) { 371 if testing.Short() { 372 t.Skip("skipping watcher test in short mode") 373 } 374 375 path, tearDown := setupConfigFile(t, emptyConfig) 376 defer tearDown() 377 378 fs, err := config.NewFileStore(path, true) 379 require.NoError(t, err) 380 defer fs.Close() 381 382 _, err = fs.Set(&model.Config{}) 383 require.NoError(t, err) 384 385 // Let the initial call to invokeConfigListeners finish. 386 time.Sleep(1 * time.Second) 387 388 called := make(chan bool, 1) 389 callback := func(oldfg, newCfg *model.Config) { 390 called <- true 391 } 392 fs.AddListener(callback) 393 394 // Rewrite the config to the file on disk 395 cfgData, err := config.MarshalConfig(emptyConfig) 396 require.NoError(t, err) 397 398 ioutil.WriteFile(path, cfgData, 0644) 399 select { 400 case <-called: 401 case <-time.After(5 * time.Second): 402 t.Fatal("callback should have been called when config written") 403 } 404 }) 405 } 406 407 func TestFileStoreLoad(t *testing.T) { 408 t.Run("file no longer exists", func(t *testing.T) { 409 path, tearDown := setupConfigFile(t, emptyConfig) 410 defer tearDown() 411 412 fs, err := config.NewFileStore(path, false) 413 require.NoError(t, err) 414 defer fs.Close() 415 416 os.Remove(path) 417 418 err = fs.Load() 419 require.NoError(t, err) 420 assertFileNotEqualsConfig(t, emptyConfig, path) 421 }) 422 423 t.Run("honour environment", func(t *testing.T) { 424 path, tearDown := setupConfigFile(t, minimalConfig) 425 defer tearDown() 426 427 fs, err := config.NewFileStore(path, false) 428 require.NoError(t, err) 429 defer fs.Close() 430 431 os.Setenv("MM_SERVICESETTINGS_SITEURL", "http://override") 432 433 err = fs.Load() 434 require.NoError(t, err) 435 assert.Equal(t, "http://override", *fs.Get().ServiceSettings.SiteURL) 436 assert.Equal(t, map[string]interface{}{"ServiceSettings": map[string]interface{}{"SiteURL": true}}, fs.GetEnvironmentOverrides()) 437 }) 438 439 t.Run("invalid", func(t *testing.T) { 440 path, tearDown := setupConfigFile(t, emptyConfig) 441 defer tearDown() 442 443 fs, err := config.NewFileStore(path, false) 444 require.NoError(t, err) 445 defer fs.Close() 446 447 cfgData, err := config.MarshalConfig(invalidConfig) 448 require.NoError(t, err) 449 450 ioutil.WriteFile(path, cfgData, 0644) 451 452 err = fs.Load() 453 if assert.Error(t, err) { 454 assert.EqualError(t, err, "invalid config: Config.IsValid: model.config.is_valid.site_url.app_error, ") 455 } 456 }) 457 458 t.Run("fixes required", func(t *testing.T) { 459 path, tearDown := setupConfigFile(t, fixesRequiredConfig) 460 defer tearDown() 461 462 fs, err := config.NewFileStore(path, false) 463 require.NoError(t, err) 464 defer fs.Close() 465 466 err = fs.Load() 467 require.NoError(t, err) 468 assertFileNotEqualsConfig(t, fixesRequiredConfig, path) 469 assert.Equal(t, "http://trailingslash", *fs.Get().ServiceSettings.SiteURL) 470 assert.Equal(t, "/path/to/directory/", *fs.Get().FileSettings.Directory) 471 assert.Equal(t, "en", *fs.Get().LocalizationSettings.DefaultServerLocale) 472 assert.Equal(t, "en", *fs.Get().LocalizationSettings.DefaultClientLocale) 473 }) 474 475 t.Run("listeners notifed", func(t *testing.T) { 476 path, tearDown := setupConfigFile(t, emptyConfig) 477 defer tearDown() 478 479 fs, err := config.NewFileStore(path, false) 480 require.NoError(t, err) 481 defer fs.Close() 482 483 called := make(chan bool, 1) 484 callback := func(oldfg, newCfg *model.Config) { 485 called <- true 486 } 487 fs.AddListener(callback) 488 489 err = fs.Load() 490 require.NoError(t, err) 491 492 select { 493 case <-called: 494 case <-time.After(5 * time.Second): 495 t.Fatal("callback should have been called when config loaded") 496 } 497 }) 498 } 499 500 func TestFileStoreWatcherEmitter(t *testing.T) { 501 if testing.Short() { 502 t.Skip("skipping watcher test in short mode") 503 } 504 505 t.Parallel() 506 507 path, tearDown := setupConfigFile(t, emptyConfig) 508 defer tearDown() 509 510 t.Run("disabled", func(t *testing.T) { 511 fs, err := config.NewFileStore(path, false) 512 require.NoError(t, err) 513 defer fs.Close() 514 515 // Let the initial call to invokeConfigListeners finish. 516 time.Sleep(1 * time.Second) 517 518 called := make(chan bool, 1) 519 callback := func(oldfg, newCfg *model.Config) { 520 called <- true 521 } 522 fs.AddListener(callback) 523 524 // Rewrite the config to the file on disk 525 cfgData, err := config.MarshalConfig(emptyConfig) 526 require.NoError(t, err) 527 528 ioutil.WriteFile(path, cfgData, 0644) 529 select { 530 case <-called: 531 t.Fatal("callback should not have been called since watching disabled") 532 case <-time.After(1 * time.Second): 533 } 534 }) 535 536 t.Run("enabled", func(t *testing.T) { 537 fs, err := config.NewFileStore(path, true) 538 require.NoError(t, err) 539 defer fs.Close() 540 541 called := make(chan bool, 1) 542 callback := func(oldfg, newCfg *model.Config) { 543 called <- true 544 } 545 fs.AddListener(callback) 546 547 // Rewrite the config to the file on disk 548 cfgData, err := config.MarshalConfig(emptyConfig) 549 require.NoError(t, err) 550 551 ioutil.WriteFile(path, cfgData, 0644) 552 select { 553 case <-called: 554 case <-time.After(5 * time.Second): 555 t.Fatal("callback should have been called when config written") 556 } 557 }) 558 } 559 560 func TestFileStoreSave(t *testing.T) { 561 path, tearDown := setupConfigFile(t, minimalConfig) 562 defer tearDown() 563 564 fs, err := config.NewFileStore(path, true) 565 require.NoError(t, err) 566 defer fs.Close() 567 568 newCfg := &model.Config{ 569 ServiceSettings: model.ServiceSettings{ 570 SiteURL: sToP("http://new"), 571 }, 572 } 573 574 t.Run("set with automatic save", func(t *testing.T) { 575 _, err = fs.Set(newCfg) 576 require.NoError(t, err) 577 578 err = fs.Load() 579 require.NoError(t, err) 580 581 assert.Equal(t, "http://new", *fs.Get().ServiceSettings.SiteURL) 582 }) 583 } 584 585 func TestFileGetFile(t *testing.T) { 586 path, tearDown := setupConfigFile(t, minimalConfig) 587 defer tearDown() 588 589 fs, err := config.NewFileStore(path, true) 590 require.NoError(t, err) 591 defer fs.Close() 592 593 t.Run("get empty filename", func(t *testing.T) { 594 _, err := fs.GetFile("") 595 require.Error(t, err) 596 }) 597 598 t.Run("get non-existent file", func(t *testing.T) { 599 _, err := fs.GetFile("unknown") 600 require.Error(t, err) 601 }) 602 603 t.Run("get empty file", func(t *testing.T) { 604 err := os.MkdirAll("config", 0700) 605 require.NoError(t, err) 606 607 f, err := ioutil.TempFile("config", "empty-file") 608 require.NoError(t, err) 609 defer os.Remove(f.Name()) 610 611 err = ioutil.WriteFile(f.Name(), nil, 0777) 612 require.NoError(t, err) 613 614 data, err := fs.GetFile(f.Name()) 615 require.NoError(t, err) 616 require.Empty(t, data) 617 }) 618 619 t.Run("get non-empty file", func(t *testing.T) { 620 err := os.MkdirAll("config", 0700) 621 require.NoError(t, err) 622 623 f, err := ioutil.TempFile("config", "test-file") 624 require.NoError(t, err) 625 defer os.Remove(f.Name()) 626 627 err = ioutil.WriteFile(f.Name(), []byte("test"), 0777) 628 require.NoError(t, err) 629 630 data, err := fs.GetFile(f.Name()) 631 require.NoError(t, err) 632 require.Equal(t, []byte("test"), data) 633 }) 634 } 635 636 func TestFileSetFile(t *testing.T) { 637 path, tearDown := setupConfigFile(t, minimalConfig) 638 defer tearDown() 639 640 fs, err := config.NewFileStore(path, true) 641 require.NoError(t, err) 642 defer fs.Close() 643 644 t.Run("set new file", func(t *testing.T) { 645 err := fs.SetFile("new", []byte("new file")) 646 require.NoError(t, err) 647 648 data, err := fs.GetFile("new") 649 require.NoError(t, err) 650 require.Equal(t, []byte("new file"), data) 651 }) 652 653 t.Run("overwrite existing file", func(t *testing.T) { 654 err := fs.SetFile("existing", []byte("existing file")) 655 require.NoError(t, err) 656 657 err = fs.SetFile("existing", []byte("overwritten file")) 658 require.NoError(t, err) 659 660 data, err := fs.GetFile("existing") 661 require.NoError(t, err) 662 require.Equal(t, []byte("overwritten file"), data) 663 }) 664 } 665 666 func TestFileHasFile(t *testing.T) { 667 668 t.Run("has non-existent", func(t *testing.T) { 669 path, tearDown := setupConfigFile(t, minimalConfig) 670 defer tearDown() 671 672 fs, err := config.NewFileStore(path, true) 673 require.NoError(t, err) 674 defer fs.Close() 675 676 has, err := fs.HasFile("non-existent") 677 require.NoError(t, err) 678 require.False(t, has) 679 }) 680 681 t.Run("has existing", func(t *testing.T) { 682 path, tearDown := setupConfigFile(t, minimalConfig) 683 defer tearDown() 684 685 fs, err := config.NewFileStore(path, true) 686 require.NoError(t, err) 687 defer fs.Close() 688 689 err = fs.SetFile("existing", []byte("existing file")) 690 require.NoError(t, err) 691 692 has, err := fs.HasFile("existing") 693 require.NoError(t, err) 694 require.True(t, has) 695 }) 696 697 t.Run("has manually created file", func(t *testing.T) { 698 path, tearDown := setupConfigFile(t, minimalConfig) 699 defer tearDown() 700 701 fs, err := config.NewFileStore(path, true) 702 require.NoError(t, err) 703 defer fs.Close() 704 705 err = os.MkdirAll("config", 0700) 706 require.NoError(t, err) 707 708 f, err := ioutil.TempFile("config", "test-file") 709 require.NoError(t, err) 710 defer os.Remove(f.Name()) 711 712 err = ioutil.WriteFile(f.Name(), []byte("test"), 0777) 713 require.NoError(t, err) 714 715 has, err := fs.HasFile(f.Name()) 716 require.NoError(t, err) 717 require.True(t, has) 718 }) 719 } 720 721 func TestFileRemoveFile(t *testing.T) { 722 t.Run("remove non-existent", func(t *testing.T) { 723 path, tearDown := setupConfigFile(t, minimalConfig) 724 defer tearDown() 725 726 fs, err := config.NewFileStore(path, true) 727 require.NoError(t, err) 728 defer fs.Close() 729 730 err = fs.RemoveFile("non-existent") 731 require.NoError(t, err) 732 }) 733 734 t.Run("remove existing", func(t *testing.T) { 735 path, tearDown := setupConfigFile(t, minimalConfig) 736 defer tearDown() 737 738 fs, err := config.NewFileStore(path, true) 739 require.NoError(t, err) 740 defer fs.Close() 741 742 err = fs.SetFile("existing", []byte("existing file")) 743 require.NoError(t, err) 744 745 err = fs.RemoveFile("existing") 746 require.NoError(t, err) 747 748 has, err := fs.HasFile("existing") 749 require.NoError(t, err) 750 require.False(t, has) 751 752 _, err = fs.GetFile("existing") 753 require.Error(t, err) 754 }) 755 756 t.Run("remove manually created file", func(t *testing.T) { 757 path, tearDown := setupConfigFile(t, minimalConfig) 758 defer tearDown() 759 760 fs, err := config.NewFileStore(path, true) 761 require.NoError(t, err) 762 defer fs.Close() 763 764 err = os.MkdirAll("config", 0700) 765 require.NoError(t, err) 766 767 f, err := ioutil.TempFile("config", "test-file") 768 require.NoError(t, err) 769 defer os.Remove(f.Name()) 770 771 err = ioutil.WriteFile(f.Name(), []byte("test"), 0777) 772 require.NoError(t, err) 773 774 err = fs.RemoveFile(f.Name()) 775 require.NoError(t, err) 776 777 has, err := fs.HasFile("existing") 778 require.NoError(t, err) 779 require.False(t, has) 780 781 _, err = fs.GetFile("existing") 782 require.Error(t, err) 783 }) 784 } 785 786 func TestFileStoreString(t *testing.T) { 787 path, tearDown := setupConfigFile(t, emptyConfig) 788 defer tearDown() 789 790 fs, err := config.NewFileStore(path, false) 791 require.NoError(t, err) 792 defer fs.Close() 793 794 assert.Equal(t, "file://"+path, fs.String()) 795 }