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  }