github.com/crspeller/mattermost-server@v0.0.0-20190328001957-a200beb3d111/config/database_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 "bytes" 8 "fmt" 9 "net/url" 10 "os" 11 "strings" 12 "testing" 13 "time" 14 15 "github.com/jmoiron/sqlx" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 19 "github.com/crspeller/mattermost-server/config" 20 "github.com/crspeller/mattermost-server/model" 21 ) 22 23 func setupConfigDatabase(t *testing.T, cfg *model.Config, files map[string][]byte) (string, func()) { 24 t.Helper() 25 os.Clearenv() 26 truncateTables(t) 27 28 cfgData, err := config.MarshalConfig(cfg) 29 require.NoError(t, err) 30 31 db := sqlx.NewDb(mainHelper.GetSqlSupplier().GetMaster().Db, *mainHelper.GetSqlSettings().DriverName) 32 err = config.InitializeConfigurationsTable(db) 33 require.NoError(t, err) 34 35 id := model.NewId() 36 _, err = db.NamedExec("INSERT INTO Configurations (Id, Value, CreateAt, Active) VALUES(:Id, :Value, :CreateAt, TRUE)", map[string]interface{}{ 37 "Id": id, 38 "Value": cfgData, 39 "CreateAt": model.GetMillis(), 40 }) 41 require.NoError(t, err) 42 43 for name, data := range files { 44 params := map[string]interface{}{ 45 "name": name, 46 "data": data, 47 "create_at": model.GetMillis(), 48 "update_at": model.GetMillis(), 49 } 50 51 _, err = db.NamedExec("INSERT INTO ConfigurationFiles (Name, Data, CreateAt, UpdateAt) VALUES (:name, :data, :create_at, :update_at)", params) 52 require.NoError(t, err) 53 } 54 55 return id, func() { 56 truncateTables(t) 57 } 58 } 59 60 // getActualDatabaseConfig returns the active configuration in the database without relying on a config store. 61 func getActualDatabaseConfig(t *testing.T) (string, *model.Config) { 62 t.Helper() 63 64 var actual struct { 65 Id string `db:"Id"` 66 Value []byte `db:"Value"` 67 } 68 db := sqlx.NewDb(mainHelper.GetSqlSupplier().GetMaster().Db, *mainHelper.GetSqlSettings().DriverName) 69 err := db.Get(&actual, "SELECT Id, Value FROM Configurations WHERE Active") 70 require.NoError(t, err) 71 72 actualCfg, _, err := config.UnmarshalConfig(bytes.NewReader(actual.Value), false) 73 require.Nil(t, err) 74 75 return actual.Id, actualCfg 76 } 77 78 // assertDatabaseEqualsConfig verifies the active in-database configuration equals the given config. 79 func assertDatabaseEqualsConfig(t *testing.T, expectedCfg *model.Config) { 80 t.Helper() 81 82 expectedCfg = prepareExpectedConfig(t, expectedCfg) 83 _, actualCfg := getActualDatabaseConfig(t) 84 assert.Equal(t, expectedCfg, actualCfg) 85 } 86 87 // assertDatabaseNotEqualsConfig verifies the in-database configuration does not equal the given config. 88 func assertDatabaseNotEqualsConfig(t *testing.T, expectedCfg *model.Config) { 89 t.Helper() 90 91 expectedCfg = prepareExpectedConfig(t, expectedCfg) 92 _, actualCfg := getActualDatabaseConfig(t) 93 assert.NotEqual(t, expectedCfg, actualCfg) 94 } 95 96 func TestDatabaseStoreNew(t *testing.T) { 97 sqlSettings := mainHelper.GetSqlSettings() 98 99 t.Run("no existing configuration - initialization required", func(t *testing.T) { 100 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 101 require.NoError(t, err) 102 defer ds.Close() 103 104 assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ds.Get().ServiceSettings.SiteURL) 105 }) 106 107 t.Run("existing config, initialization required", func(t *testing.T) { 108 _, tearDown := setupConfigDatabase(t, testConfig, nil) 109 defer tearDown() 110 111 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 112 require.NoError(t, err) 113 defer ds.Close() 114 115 assert.Equal(t, "http://TestStoreNew", *ds.Get().ServiceSettings.SiteURL) 116 assertDatabaseNotEqualsConfig(t, testConfig) 117 }) 118 119 t.Run("already minimally configured", func(t *testing.T) { 120 _, tearDown := setupConfigDatabase(t, minimalConfig, nil) 121 defer tearDown() 122 123 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 124 require.NoError(t, err) 125 defer ds.Close() 126 127 assert.Equal(t, "http://minimal", *ds.Get().ServiceSettings.SiteURL) 128 assertDatabaseEqualsConfig(t, minimalConfig) 129 }) 130 131 t.Run("invalid url", func(t *testing.T) { 132 _, err := config.NewDatabaseStore("") 133 require.Error(t, err) 134 }) 135 136 t.Run("unsupported scheme", func(t *testing.T) { 137 _, err := config.NewDatabaseStore("invalid") 138 require.Error(t, err) 139 }) 140 } 141 142 func TestDatabaseStoreGet(t *testing.T) { 143 _, tearDown := setupConfigDatabase(t, testConfig, nil) 144 defer tearDown() 145 146 sqlSettings := mainHelper.GetSqlSettings() 147 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 148 require.NoError(t, err) 149 defer ds.Close() 150 151 cfg := ds.Get() 152 assert.Equal(t, "http://TestStoreNew", *cfg.ServiceSettings.SiteURL) 153 154 cfg2 := ds.Get() 155 assert.Equal(t, "http://TestStoreNew", *cfg.ServiceSettings.SiteURL) 156 157 assert.True(t, cfg == cfg2, "Get() returned different configuration instances") 158 159 newCfg := &model.Config{} 160 oldCfg, err := ds.Set(newCfg) 161 require.NoError(t, err) 162 163 assert.True(t, oldCfg == cfg, "returned config after set() changed original") 164 assert.False(t, newCfg == cfg, "returned config should have been different from original") 165 } 166 167 func TestDatabaseStoreGetEnivironmentOverrides(t *testing.T) { 168 _, tearDown := setupConfigDatabase(t, testConfig, nil) 169 defer tearDown() 170 171 sqlSettings := mainHelper.GetSqlSettings() 172 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 173 require.NoError(t, err) 174 defer ds.Close() 175 176 assert.Equal(t, "http://TestStoreNew", *ds.Get().ServiceSettings.SiteURL) 177 assert.Empty(t, ds.GetEnvironmentOverrides()) 178 179 os.Setenv("MM_SERVICESETTINGS_SITEURL", "http://override") 180 181 ds, err = config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 182 require.NoError(t, err) 183 defer ds.Close() 184 185 assert.Equal(t, "http://override", *ds.Get().ServiceSettings.SiteURL) 186 assert.Equal(t, map[string]interface{}{"ServiceSettings": map[string]interface{}{"SiteURL": true}}, ds.GetEnvironmentOverrides()) 187 } 188 189 func TestDatabaseStoreSet(t *testing.T) { 190 sqlSettings := mainHelper.GetSqlSettings() 191 192 t.Run("set same pointer value", func(t *testing.T) { 193 t.Skip("not yet implemented") 194 195 _, tearDown := setupConfigDatabase(t, emptyConfig, nil) 196 defer tearDown() 197 198 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 199 require.NoError(t, err) 200 defer ds.Close() 201 202 _, err = ds.Set(ds.Get()) 203 if assert.Error(t, err) { 204 assert.EqualError(t, err, "old configuration modified instead of cloning") 205 } 206 }) 207 208 t.Run("defaults required", func(t *testing.T) { 209 _, tearDown := setupConfigDatabase(t, minimalConfig, nil) 210 defer tearDown() 211 212 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 213 require.NoError(t, err) 214 defer ds.Close() 215 216 oldCfg := ds.Get() 217 218 newCfg := &model.Config{} 219 220 retCfg, err := ds.Set(newCfg) 221 require.NoError(t, err) 222 assert.Equal(t, oldCfg, retCfg) 223 224 assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ds.Get().ServiceSettings.SiteURL) 225 }) 226 227 t.Run("desanitization required", func(t *testing.T) { 228 _, tearDown := setupConfigDatabase(t, ldapConfig, nil) 229 defer tearDown() 230 231 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 232 require.NoError(t, err) 233 defer ds.Close() 234 235 oldCfg := ds.Get() 236 237 newCfg := &model.Config{} 238 newCfg.LdapSettings.BindPassword = sToP(model.FAKE_SETTING) 239 240 retCfg, err := ds.Set(newCfg) 241 require.NoError(t, err) 242 assert.Equal(t, oldCfg, retCfg) 243 244 assert.Equal(t, "password", *ds.Get().LdapSettings.BindPassword) 245 }) 246 247 t.Run("invalid", func(t *testing.T) { 248 _, tearDown := setupConfigDatabase(t, emptyConfig, nil) 249 defer tearDown() 250 251 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 252 require.NoError(t, err) 253 defer ds.Close() 254 255 newCfg := &model.Config{} 256 newCfg.ServiceSettings.SiteURL = sToP("invalid") 257 258 _, err = ds.Set(newCfg) 259 if assert.Error(t, err) { 260 assert.EqualError(t, err, "new configuration is invalid: Config.IsValid: model.config.is_valid.site_url.app_error, ") 261 } 262 263 assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ds.Get().ServiceSettings.SiteURL) 264 }) 265 266 t.Run("duplicate ignored", func(t *testing.T) { 267 _, tearDown := setupConfigDatabase(t, minimalConfig, nil) 268 defer tearDown() 269 270 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 271 require.NoError(t, err) 272 defer ds.Close() 273 274 _, err = ds.Set(ds.Get()) 275 require.NoError(t, err) 276 277 beforeId, _ := getActualDatabaseConfig(t) 278 _, err = ds.Set(ds.Get()) 279 require.NoError(t, err) 280 281 afterId, _ := getActualDatabaseConfig(t) 282 assert.Equal(t, beforeId, afterId, "new record should not have been written") 283 }) 284 285 t.Run("read-only ignored", func(t *testing.T) { 286 _, tearDown := setupConfigDatabase(t, readOnlyConfig, nil) 287 defer tearDown() 288 289 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 290 require.NoError(t, err) 291 defer ds.Close() 292 293 newCfg := &model.Config{ 294 ServiceSettings: model.ServiceSettings{ 295 SiteURL: sToP("http://new"), 296 }, 297 } 298 299 _, err = ds.Set(newCfg) 300 require.NoError(t, err) 301 302 assert.Equal(t, "http://new", *ds.Get().ServiceSettings.SiteURL) 303 }) 304 305 t.Run("set with automatic save", func(t *testing.T) { 306 _, tearDown := setupConfigDatabase(t, minimalConfig, nil) 307 defer tearDown() 308 309 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 310 require.NoError(t, err) 311 defer ds.Close() 312 313 newCfg := &model.Config{ 314 ServiceSettings: model.ServiceSettings{ 315 SiteURL: sToP("http://new"), 316 }, 317 } 318 319 _, err = ds.Set(newCfg) 320 require.NoError(t, err) 321 322 err = ds.Load() 323 require.NoError(t, err) 324 325 assert.Equal(t, "http://new", *ds.Get().ServiceSettings.SiteURL) 326 }) 327 328 t.Run("persist failed", func(t *testing.T) { 329 t.Skip("skipping persistence test inside Set") 330 _, tearDown := setupConfigDatabase(t, emptyConfig, nil) 331 defer tearDown() 332 333 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 334 require.NoError(t, err) 335 defer ds.Close() 336 337 db := sqlx.NewDb(mainHelper.GetSqlSupplier().GetMaster().Db, *sqlSettings.DriverName) 338 _, err = db.Exec("DROP TABLE Configurations") 339 require.NoError(t, err) 340 341 newCfg := &model.Config{} 342 343 _, err = ds.Set(newCfg) 344 if assert.Error(t, err) { 345 assert.True(t, strings.HasPrefix(err.Error(), "failed to persist: failed to write to database")) 346 } 347 348 assert.Equal(t, model.SERVICE_SETTINGS_DEFAULT_SITE_URL, *ds.Get().ServiceSettings.SiteURL) 349 }) 350 351 t.Run("listeners notified", func(t *testing.T) { 352 activeId, tearDown := setupConfigDatabase(t, emptyConfig, nil) 353 defer tearDown() 354 355 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 356 require.NoError(t, err) 357 defer ds.Close() 358 359 oldCfg := ds.Get() 360 361 called := make(chan bool, 1) 362 callback := func(oldfg, newCfg *model.Config) { 363 called <- true 364 } 365 ds.AddListener(callback) 366 367 newCfg := &model.Config{} 368 369 retCfg, err := ds.Set(newCfg) 370 require.NoError(t, err) 371 assert.Equal(t, oldCfg, retCfg) 372 373 id, _ := getActualDatabaseConfig(t) 374 assert.NotEqual(t, activeId, id, "new record should have been written") 375 376 select { 377 case <-called: 378 case <-time.After(5 * time.Second): 379 t.Fatal("callback should have been called when config written") 380 } 381 }) 382 } 383 384 func TestDatabaseStoreLoad(t *testing.T) { 385 sqlSettings := mainHelper.GetSqlSettings() 386 387 t.Run("active configuration no longer exists", func(t *testing.T) { 388 _, tearDown := setupConfigDatabase(t, emptyConfig, nil) 389 defer tearDown() 390 391 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 392 require.NoError(t, err) 393 defer ds.Close() 394 395 truncateTables(t) 396 397 err = ds.Load() 398 require.NoError(t, err) 399 assertDatabaseNotEqualsConfig(t, emptyConfig) 400 }) 401 402 t.Run("honour environment", func(t *testing.T) { 403 _, tearDown := setupConfigDatabase(t, minimalConfig, nil) 404 defer tearDown() 405 406 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 407 require.NoError(t, err) 408 defer ds.Close() 409 410 assert.Equal(t, "http://minimal", *ds.Get().ServiceSettings.SiteURL) 411 412 os.Setenv("MM_SERVICESETTINGS_SITEURL", "http://override") 413 414 err = ds.Load() 415 require.NoError(t, err) 416 assert.Equal(t, "http://override", *ds.Get().ServiceSettings.SiteURL) 417 assert.Equal(t, map[string]interface{}{"ServiceSettings": map[string]interface{}{"SiteURL": true}}, ds.GetEnvironmentOverrides()) 418 }) 419 420 t.Run("do not persist environment variables", func(t *testing.T) { 421 _, tearDown := setupConfigDatabase(t, minimalConfig, nil) 422 defer tearDown() 423 424 os.Setenv("MM_SERVICESETTINGS_SITEURL", "http://overridePersistEnvVariables") 425 426 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 427 require.NoError(t, err) 428 defer ds.Close() 429 430 _, err = ds.Set(ds.Get()) 431 require.NoError(t, err) 432 433 assert.Equal(t, "http://overridePersistEnvVariables", *ds.Get().ServiceSettings.SiteURL) 434 assert.Equal(t, map[string]interface{}{"ServiceSettings": map[string]interface{}{"SiteURL": true}}, ds.GetEnvironmentOverrides()) 435 // check that in DB config does not include overwritten variable 436 _, actualConfig := getActualDatabaseConfig(t) 437 assert.Equal(t, "http://minimal", *actualConfig.ServiceSettings.SiteURL) 438 }) 439 440 t.Run("invalid", func(t *testing.T) { 441 _, tearDown := setupConfigDatabase(t, emptyConfig, nil) 442 defer tearDown() 443 444 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 445 require.NoError(t, err) 446 defer ds.Close() 447 448 cfgData, err := config.MarshalConfig(invalidConfig) 449 require.NoError(t, err) 450 451 db := sqlx.NewDb(mainHelper.GetSqlSupplier().GetMaster().Db, *sqlSettings.DriverName) 452 truncateTables(t) 453 id := model.NewId() 454 _, err = db.NamedExec("INSERT INTO Configurations (Id, Value, CreateAt, Active) VALUES(:Id, :Value, :CreateAt, TRUE)", map[string]interface{}{ 455 "Id": id, 456 "Value": cfgData, 457 "CreateAt": model.GetMillis(), 458 }) 459 require.NoError(t, err) 460 461 err = ds.Load() 462 if assert.Error(t, err) { 463 assert.EqualError(t, err, "invalid config: Config.IsValid: model.config.is_valid.site_url.app_error, ") 464 } 465 }) 466 467 t.Run("fixes required", func(t *testing.T) { 468 _, tearDown := setupConfigDatabase(t, fixesRequiredConfig, nil) 469 defer tearDown() 470 471 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 472 require.NoError(t, err) 473 defer ds.Close() 474 475 err = ds.Load() 476 require.NoError(t, err) 477 assertDatabaseNotEqualsConfig(t, fixesRequiredConfig) 478 assert.Equal(t, "http://trailingslash", *ds.Get().ServiceSettings.SiteURL) 479 }) 480 481 t.Run("listeners notifed", func(t *testing.T) { 482 _, tearDown := setupConfigDatabase(t, emptyConfig, nil) 483 defer tearDown() 484 485 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 486 require.NoError(t, err) 487 defer ds.Close() 488 489 called := make(chan bool, 1) 490 callback := func(oldfg, newCfg *model.Config) { 491 called <- true 492 } 493 ds.AddListener(callback) 494 495 err = ds.Load() 496 require.NoError(t, err) 497 498 select { 499 case <-called: 500 case <-time.After(5 * time.Second): 501 t.Fatal("callback should have been called when config loaded") 502 } 503 }) 504 } 505 506 func TestDatabaseGetFile(t *testing.T) { 507 _, tearDown := setupConfigDatabase(t, minimalConfig, map[string][]byte{ 508 "empty-file": []byte{}, 509 "test-file": []byte("test"), 510 }) 511 defer tearDown() 512 513 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *mainHelper.Settings.DriverName, *mainHelper.Settings.DataSource)) 514 require.NoError(t, err) 515 defer ds.Close() 516 517 t.Run("get empty filename", func(t *testing.T) { 518 _, err := ds.GetFile("") 519 require.Error(t, err) 520 }) 521 522 t.Run("get non-existent file", func(t *testing.T) { 523 _, err := ds.GetFile("unknown") 524 require.Error(t, err) 525 }) 526 527 t.Run("get empty file", func(t *testing.T) { 528 data, err := ds.GetFile("empty-file") 529 require.NoError(t, err) 530 require.Empty(t, data) 531 }) 532 533 t.Run("get non-empty file", func(t *testing.T) { 534 data, err := ds.GetFile("test-file") 535 require.NoError(t, err) 536 require.Equal(t, []byte("test"), data) 537 }) 538 } 539 540 func TestDatabaseSetFile(t *testing.T) { 541 _, tearDown := setupConfigDatabase(t, minimalConfig, nil) 542 defer tearDown() 543 544 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *mainHelper.Settings.DriverName, *mainHelper.Settings.DataSource)) 545 require.NoError(t, err) 546 defer ds.Close() 547 548 t.Run("set new file", func(t *testing.T) { 549 err := ds.SetFile("new", []byte("new file")) 550 require.NoError(t, err) 551 552 data, err := ds.GetFile("new") 553 require.NoError(t, err) 554 require.Equal(t, []byte("new file"), data) 555 }) 556 557 t.Run("overwrite existing file", func(t *testing.T) { 558 err := ds.SetFile("existing", []byte("existing file")) 559 require.NoError(t, err) 560 561 err = ds.SetFile("existing", []byte("overwritten file")) 562 require.NoError(t, err) 563 564 data, err := ds.GetFile("existing") 565 require.NoError(t, err) 566 require.Equal(t, []byte("overwritten file"), data) 567 }) 568 } 569 570 func TestDatabaseHasFile(t *testing.T) { 571 t.Run("has non-existent", func(t *testing.T) { 572 _, tearDown := setupConfigDatabase(t, minimalConfig, nil) 573 defer tearDown() 574 575 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *mainHelper.Settings.DriverName, *mainHelper.Settings.DataSource)) 576 require.NoError(t, err) 577 defer ds.Close() 578 579 has, err := ds.HasFile("non-existent") 580 require.NoError(t, err) 581 require.False(t, has) 582 }) 583 584 t.Run("has existing", func(t *testing.T) { 585 _, tearDown := setupConfigDatabase(t, minimalConfig, nil) 586 defer tearDown() 587 588 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *mainHelper.Settings.DriverName, *mainHelper.Settings.DataSource)) 589 require.NoError(t, err) 590 defer ds.Close() 591 592 err = ds.SetFile("existing", []byte("existing file")) 593 require.NoError(t, err) 594 595 has, err := ds.HasFile("existing") 596 require.NoError(t, err) 597 require.True(t, has) 598 }) 599 600 t.Run("has manually created file", func(t *testing.T) { 601 _, tearDown := setupConfigDatabase(t, minimalConfig, map[string][]byte{ 602 "manual": []byte("manual file"), 603 }) 604 defer tearDown() 605 606 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *mainHelper.Settings.DriverName, *mainHelper.Settings.DataSource)) 607 require.NoError(t, err) 608 defer ds.Close() 609 610 has, err := ds.HasFile("manual") 611 require.NoError(t, err) 612 require.True(t, has) 613 }) 614 } 615 616 func TestDatabaseRemoveFile(t *testing.T) { 617 t.Run("remove non-existent", func(t *testing.T) { 618 _, tearDown := setupConfigDatabase(t, minimalConfig, nil) 619 defer tearDown() 620 621 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *mainHelper.Settings.DriverName, *mainHelper.Settings.DataSource)) 622 require.NoError(t, err) 623 defer ds.Close() 624 625 err = ds.RemoveFile("non-existent") 626 require.NoError(t, err) 627 }) 628 629 t.Run("remove existing", func(t *testing.T) { 630 _, tearDown := setupConfigDatabase(t, minimalConfig, nil) 631 defer tearDown() 632 633 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *mainHelper.Settings.DriverName, *mainHelper.Settings.DataSource)) 634 require.NoError(t, err) 635 defer ds.Close() 636 637 err = ds.SetFile("existing", []byte("existing file")) 638 require.NoError(t, err) 639 640 err = ds.RemoveFile("existing") 641 require.NoError(t, err) 642 643 has, err := ds.HasFile("existing") 644 require.NoError(t, err) 645 require.False(t, has) 646 647 _, err = ds.GetFile("existing") 648 require.Error(t, err) 649 }) 650 651 t.Run("remove manually created file", func(t *testing.T) { 652 _, tearDown := setupConfigDatabase(t, minimalConfig, map[string][]byte{ 653 "manual": []byte("manual file"), 654 }) 655 defer tearDown() 656 657 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *mainHelper.Settings.DriverName, *mainHelper.Settings.DataSource)) 658 require.NoError(t, err) 659 defer ds.Close() 660 661 err = ds.RemoveFile("manual") 662 require.NoError(t, err) 663 664 has, err := ds.HasFile("manual") 665 require.NoError(t, err) 666 require.False(t, has) 667 668 _, err = ds.GetFile("manual") 669 require.Error(t, err) 670 }) 671 } 672 673 func TestDatabaseStoreString(t *testing.T) { 674 _, tearDown := setupConfigDatabase(t, emptyConfig, nil) 675 defer tearDown() 676 677 sqlSettings := mainHelper.GetSqlSettings() 678 ds, err := config.NewDatabaseStore(fmt.Sprintf("%s://%s", *sqlSettings.DriverName, *sqlSettings.DataSource)) 679 require.NoError(t, err) 680 defer ds.Close() 681 682 actualStringURL, err := url.Parse(ds.String()) 683 require.NoError(t, err) 684 685 assert.Equal(t, *sqlSettings.DriverName, actualStringURL.Scheme) 686 actualUsername := actualStringURL.User.Username() 687 actualPassword, _ := actualStringURL.User.Password() 688 assert.NotEmpty(t, actualUsername) 689 assert.Empty(t, actualPassword, "should mask password") 690 }