github.com/levb/mattermost-server@v5.3.1+incompatible/model/config_test.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package model 5 6 import ( 7 "fmt" 8 "reflect" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 ) 14 15 func TestConfigDefaults(t *testing.T) { 16 t.Parallel() 17 18 t.Run("somewhere nil when uninitialized", func(t *testing.T) { 19 c := Config{} 20 require.False(t, checkNowhereNil(t, "config", c)) 21 }) 22 23 t.Run("nowhere nil when initialized", func(t *testing.T) { 24 c := Config{} 25 c.SetDefaults() 26 require.True(t, checkNowhereNil(t, "config", c)) 27 }) 28 29 t.Run("nowhere nil when partially initialized", func(t *testing.T) { 30 var recursivelyUninitialize func(*Config, string, reflect.Value) 31 recursivelyUninitialize = func(config *Config, name string, v reflect.Value) { 32 if v.Type().Kind() == reflect.Ptr { 33 // Set every pointer we find in the tree to nil 34 v.Set(reflect.Zero(v.Type())) 35 require.True(t, v.IsNil()) 36 37 // SetDefaults on the root config should make it non-nil, otherwise 38 // it means that SetDefaults isn't being called recursively in 39 // all cases. 40 config.SetDefaults() 41 if assert.False(t, v.IsNil(), "%s should be non-nil after SetDefaults()", name) { 42 recursivelyUninitialize(config, fmt.Sprintf("(*%s)", name), v.Elem()) 43 } 44 45 } else if v.Type().Kind() == reflect.Struct { 46 for i := 0; i < v.NumField(); i++ { 47 recursivelyUninitialize(config, fmt.Sprintf("%s.%s", name, v.Type().Field(i).Name), v.Field(i)) 48 } 49 } 50 } 51 52 c := Config{} 53 c.SetDefaults() 54 recursivelyUninitialize(&c, "config", reflect.ValueOf(&c).Elem()) 55 }) 56 } 57 58 func TestConfigDefaultFileSettingsDirectory(t *testing.T) { 59 c1 := Config{} 60 c1.SetDefaults() 61 62 if c1.FileSettings.Directory != "./data/" { 63 t.Fatal("FileSettings.Directory should default to './data/'") 64 } 65 } 66 67 func TestConfigDefaultEmailNotificationContentsType(t *testing.T) { 68 c1 := Config{} 69 c1.SetDefaults() 70 71 if *c1.EmailSettings.EmailNotificationContentsType != EMAIL_NOTIFICATION_CONTENTS_FULL { 72 t.Fatal("EmailSettings.EmailNotificationContentsType should default to 'full'") 73 } 74 } 75 76 func TestConfigDefaultFileSettingsS3SSE(t *testing.T) { 77 c1 := Config{} 78 c1.SetDefaults() 79 80 if *c1.FileSettings.AmazonS3SSE { 81 t.Fatal("FileSettings.AmazonS3SSE should default to false") 82 } 83 } 84 85 func TestConfigDefaultServiceSettingsExperimentalGroupUnreadChannels(t *testing.T) { 86 c1 := Config{} 87 c1.SetDefaults() 88 89 if *c1.ServiceSettings.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DISABLED { 90 t.Fatal("ServiceSettings.ExperimentalGroupUnreadChannels should default to 'disabled'") 91 } 92 93 // This setting was briefly a boolean, so ensure that those values still work as expected 94 c1 = Config{ 95 ServiceSettings: ServiceSettings{ 96 ExperimentalGroupUnreadChannels: NewString("1"), 97 }, 98 } 99 c1.SetDefaults() 100 101 if *c1.ServiceSettings.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DEFAULT_ON { 102 t.Fatal("ServiceSettings.ExperimentalGroupUnreadChannels should set true to 'default on'") 103 } 104 105 c1 = Config{ 106 ServiceSettings: ServiceSettings{ 107 ExperimentalGroupUnreadChannels: NewString("0"), 108 }, 109 } 110 c1.SetDefaults() 111 112 if *c1.ServiceSettings.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DISABLED { 113 t.Fatal("ServiceSettings.ExperimentalGroupUnreadChannels should set false to 'disabled'") 114 } 115 } 116 117 func TestMessageExportSettingsIsValidEnableExportNotSet(t *testing.T) { 118 fs := &FileSettings{} 119 mes := &MessageExportSettings{} 120 121 // should fail fast because mes.EnableExport is not set 122 require.Error(t, mes.isValid(*fs)) 123 } 124 125 func TestMessageExportSettingsIsValidEnableExportFalse(t *testing.T) { 126 fs := &FileSettings{} 127 mes := &MessageExportSettings{ 128 EnableExport: NewBool(false), 129 } 130 131 // should fail fast because message export isn't enabled 132 require.Nil(t, mes.isValid(*fs)) 133 } 134 135 func TestMessageExportSettingsIsValidExportFromTimestampInvalid(t *testing.T) { 136 fs := &FileSettings{} 137 mes := &MessageExportSettings{ 138 EnableExport: NewBool(true), 139 } 140 141 // should fail fast because export from timestamp isn't set 142 require.Error(t, mes.isValid(*fs)) 143 144 mes.ExportFromTimestamp = NewInt64(-1) 145 146 // should fail fast because export from timestamp isn't valid 147 require.Error(t, mes.isValid(*fs)) 148 149 mes.ExportFromTimestamp = NewInt64(GetMillis() + 10000) 150 151 // should fail fast because export from timestamp is greater than current time 152 require.Error(t, mes.isValid(*fs)) 153 } 154 155 func TestMessageExportSettingsIsValidDailyRunTimeInvalid(t *testing.T) { 156 fs := &FileSettings{} 157 mes := &MessageExportSettings{ 158 EnableExport: NewBool(true), 159 ExportFromTimestamp: NewInt64(0), 160 } 161 162 // should fail fast because daily runtime isn't set 163 require.Error(t, mes.isValid(*fs)) 164 165 mes.DailyRunTime = NewString("33:33:33") 166 167 // should fail fast because daily runtime is invalid format 168 require.Error(t, mes.isValid(*fs)) 169 } 170 171 func TestMessageExportSettingsIsValidBatchSizeInvalid(t *testing.T) { 172 fs := &FileSettings{ 173 DriverName: NewString("foo"), // bypass file location check 174 } 175 mes := &MessageExportSettings{ 176 EnableExport: NewBool(true), 177 ExportFromTimestamp: NewInt64(0), 178 DailyRunTime: NewString("15:04"), 179 } 180 181 // should fail fast because batch size isn't set 182 require.Error(t, mes.isValid(*fs)) 183 } 184 185 func TestMessageExportSettingsIsValidExportFormatInvalid(t *testing.T) { 186 fs := &FileSettings{ 187 DriverName: NewString("foo"), // bypass file location check 188 } 189 mes := &MessageExportSettings{ 190 EnableExport: NewBool(true), 191 ExportFromTimestamp: NewInt64(0), 192 DailyRunTime: NewString("15:04"), 193 BatchSize: NewInt(100), 194 } 195 196 // should fail fast because export format isn't set 197 require.Error(t, mes.isValid(*fs)) 198 } 199 200 func TestMessageExportSettingsIsValidGlobalRelayEmailAddressInvalid(t *testing.T) { 201 fs := &FileSettings{ 202 DriverName: NewString("foo"), // bypass file location check 203 } 204 mes := &MessageExportSettings{ 205 EnableExport: NewBool(true), 206 ExportFormat: NewString(COMPLIANCE_EXPORT_TYPE_GLOBALRELAY), 207 ExportFromTimestamp: NewInt64(0), 208 DailyRunTime: NewString("15:04"), 209 BatchSize: NewInt(100), 210 } 211 212 // should fail fast because global relay email address isn't set 213 require.Error(t, mes.isValid(*fs)) 214 } 215 216 func TestMessageExportSettingsIsValidActiance(t *testing.T) { 217 fs := &FileSettings{ 218 DriverName: NewString("foo"), // bypass file location check 219 } 220 mes := &MessageExportSettings{ 221 EnableExport: NewBool(true), 222 ExportFormat: NewString(COMPLIANCE_EXPORT_TYPE_ACTIANCE), 223 ExportFromTimestamp: NewInt64(0), 224 DailyRunTime: NewString("15:04"), 225 BatchSize: NewInt(100), 226 } 227 228 // should pass because everything is valid 229 require.Nil(t, mes.isValid(*fs)) 230 } 231 232 func TestMessageExportSettingsIsValidGlobalRelaySettingsMissing(t *testing.T) { 233 fs := &FileSettings{ 234 DriverName: NewString("foo"), // bypass file location check 235 } 236 mes := &MessageExportSettings{ 237 EnableExport: NewBool(true), 238 ExportFormat: NewString(COMPLIANCE_EXPORT_TYPE_GLOBALRELAY), 239 ExportFromTimestamp: NewInt64(0), 240 DailyRunTime: NewString("15:04"), 241 BatchSize: NewInt(100), 242 } 243 244 // should fail because globalrelay settings are missing 245 require.Error(t, mes.isValid(*fs)) 246 } 247 248 func TestMessageExportSettingsIsValidGlobalRelaySettingsInvalidCustomerType(t *testing.T) { 249 fs := &FileSettings{ 250 DriverName: NewString("foo"), // bypass file location check 251 } 252 mes := &MessageExportSettings{ 253 EnableExport: NewBool(true), 254 ExportFormat: NewString(COMPLIANCE_EXPORT_TYPE_GLOBALRELAY), 255 ExportFromTimestamp: NewInt64(0), 256 DailyRunTime: NewString("15:04"), 257 BatchSize: NewInt(100), 258 GlobalRelaySettings: &GlobalRelayMessageExportSettings{ 259 CustomerType: NewString("Invalid"), 260 EmailAddress: NewString("valid@mattermost.com"), 261 SmtpUsername: NewString("SomeUsername"), 262 SmtpPassword: NewString("SomePassword"), 263 }, 264 } 265 266 // should fail because customer type is invalid 267 require.Error(t, mes.isValid(*fs)) 268 } 269 270 // func TestMessageExportSettingsIsValidGlobalRelaySettingsInvalidEmailAddress(t *testing.T) { 271 func TestMessageExportSettingsGlobalRelaySettings(t *testing.T) { 272 fs := &FileSettings{ 273 DriverName: NewString("foo"), // bypass file location check 274 } 275 tests := []struct { 276 name string 277 value *GlobalRelayMessageExportSettings 278 success bool 279 }{ 280 { 281 "Invalid email address", 282 &GlobalRelayMessageExportSettings{ 283 CustomerType: NewString(GLOBALRELAY_CUSTOMER_TYPE_A9), 284 EmailAddress: NewString("invalidEmailAddress"), 285 SmtpUsername: NewString("SomeUsername"), 286 SmtpPassword: NewString("SomePassword"), 287 }, 288 false, 289 }, 290 { 291 "Missing smtp username", 292 &GlobalRelayMessageExportSettings{ 293 CustomerType: NewString(GLOBALRELAY_CUSTOMER_TYPE_A10), 294 EmailAddress: NewString("valid@mattermost.com"), 295 SmtpPassword: NewString("SomePassword"), 296 }, 297 false, 298 }, 299 { 300 "Invalid smtp username", 301 &GlobalRelayMessageExportSettings{ 302 CustomerType: NewString(GLOBALRELAY_CUSTOMER_TYPE_A10), 303 EmailAddress: NewString("valid@mattermost.com"), 304 SmtpUsername: NewString(""), 305 SmtpPassword: NewString("SomePassword"), 306 }, 307 false, 308 }, 309 { 310 "Invalid smtp password", 311 &GlobalRelayMessageExportSettings{ 312 CustomerType: NewString(GLOBALRELAY_CUSTOMER_TYPE_A10), 313 EmailAddress: NewString("valid@mattermost.com"), 314 SmtpUsername: NewString("SomeUsername"), 315 SmtpPassword: NewString(""), 316 }, 317 false, 318 }, 319 { 320 "Valid data", 321 &GlobalRelayMessageExportSettings{ 322 CustomerType: NewString(GLOBALRELAY_CUSTOMER_TYPE_A9), 323 EmailAddress: NewString("valid@mattermost.com"), 324 SmtpUsername: NewString("SomeUsername"), 325 SmtpPassword: NewString("SomePassword"), 326 }, 327 true, 328 }, 329 } 330 331 for _, tt := range tests { 332 t.Run(tt.name, func(t *testing.T) { 333 mes := &MessageExportSettings{ 334 EnableExport: NewBool(true), 335 ExportFormat: NewString(COMPLIANCE_EXPORT_TYPE_GLOBALRELAY), 336 ExportFromTimestamp: NewInt64(0), 337 DailyRunTime: NewString("15:04"), 338 BatchSize: NewInt(100), 339 GlobalRelaySettings: tt.value, 340 } 341 342 if tt.success { 343 require.Nil(t, mes.isValid(*fs)) 344 } else { 345 require.Error(t, mes.isValid(*fs)) 346 } 347 }) 348 } 349 } 350 351 func TestMessageExportSetDefaults(t *testing.T) { 352 mes := &MessageExportSettings{} 353 mes.SetDefaults() 354 355 require.False(t, *mes.EnableExport) 356 require.Equal(t, "01:00", *mes.DailyRunTime) 357 require.Equal(t, int64(0), *mes.ExportFromTimestamp) 358 require.Equal(t, 10000, *mes.BatchSize) 359 require.Equal(t, COMPLIANCE_EXPORT_TYPE_ACTIANCE, *mes.ExportFormat) 360 } 361 362 func TestMessageExportSetDefaultsExportEnabledExportFromTimestampNil(t *testing.T) { 363 mes := &MessageExportSettings{ 364 EnableExport: NewBool(true), 365 } 366 mes.SetDefaults() 367 368 require.True(t, *mes.EnableExport) 369 require.Equal(t, "01:00", *mes.DailyRunTime) 370 require.NotEqual(t, int64(0), *mes.ExportFromTimestamp) 371 require.True(t, *mes.ExportFromTimestamp <= GetMillis()) 372 require.Equal(t, 10000, *mes.BatchSize) 373 } 374 375 func TestMessageExportSetDefaultsExportEnabledExportFromTimestampZero(t *testing.T) { 376 mes := &MessageExportSettings{ 377 EnableExport: NewBool(true), 378 ExportFromTimestamp: NewInt64(0), 379 } 380 mes.SetDefaults() 381 382 require.True(t, *mes.EnableExport) 383 require.Equal(t, "01:00", *mes.DailyRunTime) 384 require.NotEqual(t, int64(0), *mes.ExportFromTimestamp) 385 require.True(t, *mes.ExportFromTimestamp <= GetMillis()) 386 require.Equal(t, 10000, *mes.BatchSize) 387 } 388 389 func TestMessageExportSetDefaultsExportEnabledExportFromTimestampNonZero(t *testing.T) { 390 mes := &MessageExportSettings{ 391 EnableExport: NewBool(true), 392 ExportFromTimestamp: NewInt64(12345), 393 } 394 mes.SetDefaults() 395 396 require.True(t, *mes.EnableExport) 397 require.Equal(t, "01:00", *mes.DailyRunTime) 398 require.Equal(t, int64(12345), *mes.ExportFromTimestamp) 399 require.Equal(t, 10000, *mes.BatchSize) 400 } 401 402 func TestMessageExportSetDefaultsExportDisabledExportFromTimestampNil(t *testing.T) { 403 mes := &MessageExportSettings{ 404 EnableExport: NewBool(false), 405 } 406 mes.SetDefaults() 407 408 require.False(t, *mes.EnableExport) 409 require.Equal(t, "01:00", *mes.DailyRunTime) 410 require.Equal(t, int64(0), *mes.ExportFromTimestamp) 411 require.Equal(t, 10000, *mes.BatchSize) 412 } 413 414 func TestMessageExportSetDefaultsExportDisabledExportFromTimestampZero(t *testing.T) { 415 mes := &MessageExportSettings{ 416 EnableExport: NewBool(false), 417 ExportFromTimestamp: NewInt64(0), 418 } 419 mes.SetDefaults() 420 421 require.False(t, *mes.EnableExport) 422 require.Equal(t, "01:00", *mes.DailyRunTime) 423 require.Equal(t, int64(0), *mes.ExportFromTimestamp) 424 require.Equal(t, 10000, *mes.BatchSize) 425 } 426 427 func TestMessageExportSetDefaultsExportDisabledExportFromTimestampNonZero(t *testing.T) { 428 mes := &MessageExportSettings{ 429 EnableExport: NewBool(false), 430 ExportFromTimestamp: NewInt64(12345), 431 } 432 mes.SetDefaults() 433 434 require.False(t, *mes.EnableExport) 435 require.Equal(t, "01:00", *mes.DailyRunTime) 436 require.Equal(t, int64(0), *mes.ExportFromTimestamp) 437 require.Equal(t, 10000, *mes.BatchSize) 438 } 439 440 func TestDisplaySettingsIsValidCustomUrlSchemes(t *testing.T) { 441 tests := []struct { 442 name string 443 value []string 444 valid bool 445 }{ 446 { 447 name: "empty", 448 value: []string{}, 449 valid: true, 450 }, 451 { 452 name: "custom protocol", 453 value: []string{"steam"}, 454 valid: true, 455 }, 456 { 457 name: "multiple custom protocols", 458 value: []string{"bitcoin", "rss", "redis"}, 459 valid: true, 460 }, 461 { 462 name: "containing numbers", 463 value: []string{"ut2004", "ts3server", "h323"}, 464 valid: true, 465 }, 466 { 467 name: "containing period", 468 value: []string{"iris.beep"}, 469 valid: false, // should technically be true, but client doesn't support it 470 }, 471 { 472 name: "containing hyphen", 473 value: []string{"ms-excel"}, 474 valid: true, 475 }, 476 { 477 name: "containing plus", 478 value: []string{"coap+tcp", "coap+ws"}, 479 valid: false, // should technically be true, but client doesn't support it 480 }, 481 { 482 name: "starting with number", 483 value: []string{"4four"}, 484 valid: false, 485 }, 486 { 487 name: "starting with period", 488 value: []string{"data", ".dot"}, 489 valid: false, 490 }, 491 { 492 name: "starting with hyphen", 493 value: []string{"-hyphen", "dns"}, 494 valid: false, 495 }, 496 { 497 name: "invalid symbols", 498 value: []string{"!!fun!!"}, 499 valid: false, 500 }, 501 { 502 name: "invalid letters", 503 value: []string{"école"}, 504 valid: false, 505 }, 506 } 507 for _, test := range tests { 508 t.Run(test.name, func(t *testing.T) { 509 ds := &DisplaySettings{} 510 ds.SetDefaults() 511 512 ds.CustomUrlSchemes = &test.value 513 514 if err := ds.isValid(); err != nil && test.valid { 515 t.Error("Expected CustomUrlSchemes to be valid but got error:", err) 516 } else if err == nil && !test.valid { 517 t.Error("Expected CustomUrlSchemes to be invalid but got no error") 518 } 519 }) 520 } 521 } 522 523 func TestListenAddressIsValidated(t *testing.T) { 524 525 testValues := map[string]bool{ 526 ":8065": true, 527 ":9917": true, 528 "0.0.0.0:9917": true, 529 "[2001:db8::68]:9918": true, 530 "[::1]:8065": true, 531 "localhost:8065": true, 532 "test.com:8065": true, 533 ":0": true, 534 ":33147": true, 535 "123:8065": false, 536 "[::1]:99999": false, 537 "[::1]:-1": false, 538 "[::1]:8065a": false, 539 "0.0.0:9917": false, 540 "0.0.0.0:9917/": false, 541 "0..0.0:9917/": false, 542 "0.0.0222.0:9917/": false, 543 "http://0.0.0.0:9917/": false, 544 "http://0.0.0.0:9917": false, 545 "8065": false, 546 "[2001:db8::68]": false, 547 } 548 549 for key, expected := range testValues { 550 ss := &ServiceSettings{ 551 ListenAddress: NewString(key), 552 } 553 ss.SetDefaults() 554 if expected { 555 require.Nil(t, ss.isValid(), fmt.Sprintf("Got an error from '%v'.", key)) 556 } else { 557 err := ss.isValid() 558 require.NotNil(t, err, fmt.Sprintf("Expected '%v' to throw an error.", key)) 559 require.Equal(t, "model.config.is_valid.listen_address.app_error", err.Message) 560 } 561 } 562 563 }