github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/servercfg/yaml_config_test.go (about) 1 // Copyright 2020 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package servercfg 16 17 import ( 18 "testing" 19 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/require" 22 "gopkg.in/yaml.v2" 23 ) 24 25 var trueValue = true 26 27 func TestUnmarshall(t *testing.T) { 28 testStr := ` 29 log_level: info 30 31 behavior: 32 read_only: false 33 autocommit: true 34 dolt_transaction_commit: true 35 persistence_behavior: load 36 disable_client_multi_statements: false 37 event_scheduler: ON 38 39 user: 40 name: "" 41 password: "" 42 43 listener: 44 host: localhost 45 port: 3306 46 max_connections: 100 47 read_timeout_millis: 28800000 48 write_timeout_millis: 28800000 49 50 data_dir: some nonsense 51 52 metrics: 53 host: 123.45.67.89 54 port: 9091 55 labels: 56 label1: value1 57 label2: 2 58 label3: true 59 60 user_session_vars: 61 - name: user0 62 vars: 63 var1: val0_1 64 var2: val0_2 65 var3: val0_3 66 - name: user1 67 vars: 68 var1: val1_1 69 var2: val1_2 70 var4: val1_4 71 72 privilege_file: some other nonsense 73 74 branch_control_file: third nonsense 75 76 jwks: 77 - name: jwks_name 78 location_url: https://website.com 79 claims: 80 field1: a 81 field2: b 82 fields_to_log: [field1, field2] 83 - name: jwks_name2 84 location_url: https://website.com 85 claims: 86 field1: a 87 fields_to_log: 88 ` 89 expected := ServerConfigAsYAMLConfig(DefaultServerConfig()) 90 91 expected.BehaviorConfig.DoltTransactionCommit = &trueValue 92 expected.CfgDirStr = nillableStrPtr("") 93 expected.PrivilegeFile = ptr("some other nonsense") 94 expected.BranchControlFile = ptr("third nonsense") 95 96 expected.MetricsConfig = MetricsYAMLConfig{ 97 Host: ptr("123.45.67.89"), 98 Port: ptr(9091), 99 Labels: map[string]string{ 100 "label1": "value1", 101 "label2": "2", 102 "label3": "true", 103 }, 104 } 105 expected.DataDirStr = ptr("some nonsense") 106 expected.SystemVars_ = nil 107 expected.Vars = []UserSessionVars{ 108 { 109 Name: "user0", 110 Vars: map[string]string{ 111 "var1": "val0_1", 112 "var2": "val0_2", 113 "var3": "val0_3", 114 }, 115 }, 116 { 117 Name: "user1", 118 Vars: map[string]string{ 119 "var1": "val1_1", 120 "var2": "val1_2", 121 "var4": "val1_4", 122 }, 123 }, 124 } 125 expected.Jwks = []JwksConfig{ 126 { 127 Name: "jwks_name", 128 LocationUrl: "https://website.com", 129 Claims: map[string]string{ 130 "field1": "a", 131 "field2": "b", 132 }, 133 FieldsToLog: []string{"field1", "field2"}, 134 }, 135 { 136 Name: "jwks_name2", 137 LocationUrl: "https://website.com", 138 Claims: map[string]string{ 139 "field1": "a", 140 }, 141 FieldsToLog: nil, 142 }, 143 } 144 145 config, err := NewYamlConfig([]byte(testStr)) 146 require.NoError(t, err) 147 assert.Equal(t, expected, config, "Expected:\n%v\nActual:\n%v", expected, config) 148 } 149 150 func TestUnmarshallRemotesapiPort(t *testing.T) { 151 testStr := ` 152 remotesapi: 153 port: 8000 154 ` 155 config, err := NewYamlConfig([]byte(testStr)) 156 require.NoError(t, err) 157 require.NotNil(t, config.RemotesapiPort()) 158 require.Equal(t, 8000, *config.RemotesapiPort()) 159 } 160 161 func TestUnmarshallCluster(t *testing.T) { 162 testStr := ` 163 cluster: 164 standby_remotes: 165 - name: standby 166 remote_url_template: http://doltdb-1.doltdb:50051/{database} 167 bootstrap_role: primary 168 bootstrap_epoch: 0 169 remotesapi: 170 port: 50051 171 ` 172 config, err := NewYamlConfig([]byte(testStr)) 173 require.NoError(t, err) 174 require.NotNil(t, config.ClusterConfig()) 175 require.NotNil(t, config.ClusterConfig().RemotesAPIConfig()) 176 require.Equal(t, 50051, config.ClusterConfig().RemotesAPIConfig().Port()) 177 require.Len(t, config.ClusterConfig().StandbyRemotes(), 1) 178 require.Equal(t, "primary", config.ClusterConfig().BootstrapRole()) 179 require.Equal(t, 0, config.ClusterConfig().BootstrapEpoch()) 180 require.Equal(t, "standby", config.ClusterConfig().StandbyRemotes()[0].Name()) 181 require.Equal(t, "http://doltdb-1.doltdb:50051/{database}", config.ClusterConfig().StandbyRemotes()[0].RemoteURLTemplate()) 182 } 183 184 func TestValidateClusterConfig(t *testing.T) { 185 cases := []struct { 186 Name string 187 Config string 188 Error bool 189 }{ 190 { 191 Name: "no cluster: config", 192 Config: "", 193 Error: false, 194 }, 195 { 196 Name: "all fields valid", 197 Config: ` 198 cluster: 199 standby_remotes: 200 - name: standby 201 remote_url_template: http://localhost:50051/{database} 202 bootstrap_role: primary 203 bootstrap_epoch: 0 204 remotesapi: 205 port: 50051 206 `, 207 Error: false, 208 }, 209 { 210 Name: "bad bootstrap_role", 211 Config: ` 212 cluster: 213 standby_remotes: 214 - name: standby 215 remote_url_template: http://localhost:50051/{database} 216 bootstrap_role: backup 217 bootstrap_epoch: 0 218 remotesapi: 219 port: 50051 220 `, 221 Error: true, 222 }, 223 { 224 Name: "negative bootstrap_epoch", 225 Config: ` 226 cluster: 227 standby_remotes: 228 - name: standby 229 remote_url_template: http://localhost:50051/{database} 230 bootstrap_role: primary 231 bootstrap_epoch: -1 232 remotesapi: 233 port: 50051 234 `, 235 Error: true, 236 }, 237 { 238 Name: "negative remotesapi port", 239 Config: ` 240 cluster: 241 standby_remotes: 242 - name: standby 243 remote_url_template: http://localhost:50051/{database} 244 bootstrap_role: primary 245 bootstrap_epoch: 0 246 remotesapi: 247 port: -5 248 `, 249 Error: true, 250 }, 251 { 252 Name: "bad remote_url_template", 253 Config: ` 254 cluster: 255 standby_remotes: 256 - name: standby 257 remote_url_template: http://localhost:50051/{database 258 bootstrap_role: primary 259 bootstrap_epoch: 0 260 remotesapi: 261 port: 50051 262 `, 263 Error: true, 264 }, 265 { 266 Name: "no standby remotes", 267 Config: ` 268 cluster: 269 standby_remotes: 270 bootstrap_role: primary 271 bootstrap_epoch: 0 272 remotesapi: 273 port: 50051 274 `, 275 Error: true, 276 }, 277 } 278 for _, c := range cases { 279 t.Run(c.Name, func(t *testing.T) { 280 cfg, err := NewYamlConfig([]byte(c.Config)) 281 require.NoError(t, err) 282 if c.Error { 283 require.Error(t, ValidateClusterConfig(cfg.ClusterConfig())) 284 } else { 285 require.NoError(t, ValidateClusterConfig(cfg.ClusterConfig())) 286 } 287 }) 288 } 289 } 290 291 // Tests that a common YAML error (incorrect indentation) throws an error 292 func TestUnmarshallError(t *testing.T) { 293 testStr := ` 294 log_level: info 295 296 behavior: 297 read_only: false 298 autocommit: true 299 300 user: 301 name: root 302 password: "" 303 304 listener: 305 host: localhost 306 port: 3306 307 max_connections: 1 308 read_timeout_millis: 28800000 309 write_timeout_millis: 28800000 310 311 databases: 312 - name: irs_soi 313 path: ./datasets/irs-soi 314 - name: noaa 315 path: /Users/brian/datasets/noaa 316 ` 317 _, err := NewYamlConfig([]byte(testStr)) 318 assert.Error(t, err) 319 } 320 321 func TestYAMLConfigDefaults(t *testing.T) { 322 var cfg YAMLConfig 323 err := yaml.Unmarshal([]byte{}, &cfg) 324 require.NoError(t, err) 325 326 assert.Equal(t, DefaultHost, cfg.Host()) 327 assert.Equal(t, DefaultPort, cfg.Port()) 328 assert.Equal(t, DefaultUser, cfg.User()) 329 assert.Equal(t, DefaultPass, cfg.Password()) 330 assert.Equal(t, uint64(DefaultTimeout), cfg.WriteTimeout()) 331 assert.Equal(t, uint64(DefaultTimeout), cfg.ReadTimeout()) 332 assert.Equal(t, DefaultReadOnly, cfg.ReadOnly()) 333 assert.Equal(t, DefaultLogLevel, cfg.LogLevel()) 334 assert.Equal(t, DefaultAutoCommit, cfg.AutoCommit()) 335 assert.Equal(t, DefaultDoltTransactionCommit, cfg.DoltTransactionCommit()) 336 assert.Equal(t, uint64(DefaultMaxConnections), cfg.MaxConnections()) 337 assert.Equal(t, "", cfg.TLSKey()) 338 assert.Equal(t, "", cfg.TLSCert()) 339 assert.Equal(t, false, cfg.RequireSecureTransport()) 340 assert.Equal(t, false, cfg.AllowCleartextPasswords()) 341 assert.Equal(t, false, cfg.DisableClientMultiStatements()) 342 assert.Equal(t, DefaultMetricsHost, cfg.MetricsHost()) 343 assert.Equal(t, DefaultMetricsPort, cfg.MetricsPort()) 344 assert.Nil(t, cfg.MetricsConfig.Labels) 345 assert.Equal(t, DefaultAllowCleartextPasswords, cfg.AllowCleartextPasswords()) 346 assert.Nil(t, cfg.RemotesapiPort()) 347 348 c, err := LoadTLSConfig(cfg) 349 assert.NoError(t, err) 350 assert.Nil(t, c) 351 } 352 353 func TestYAMLConfigTLS(t *testing.T) { 354 var cfg YAMLConfig 355 err := yaml.Unmarshal([]byte(` 356 listener: 357 tls_key: testdata/selfsigned_key.pem 358 tls_cert: testdata/selfsigned_cert.pem 359 `), &cfg) 360 require.NoError(t, err) 361 362 c, err := LoadTLSConfig(cfg) 363 assert.NoError(t, err) 364 assert.NotNil(t, c) 365 assert.Len(t, c.Certificates, 1) 366 assert.Len(t, c.Certificates[0].Certificate, 1) 367 368 err = yaml.Unmarshal([]byte(` 369 listener: 370 tls_key: testdata/chain_key.pem 371 tls_cert: testdata/chain_cert.pem 372 `), &cfg) 373 require.NoError(t, err) 374 375 c, err = LoadTLSConfig(cfg) 376 assert.NoError(t, err) 377 assert.NotNil(t, c) 378 assert.Len(t, c.Certificates, 1) 379 assert.Len(t, c.Certificates[0].Certificate, 1) 380 381 cfg = YAMLConfig{} 382 err = yaml.Unmarshal([]byte(` 383 listener: 384 tls_key: testdata/chain_key.pem 385 `), &cfg) 386 require.NoError(t, err) 387 c, err = LoadTLSConfig(cfg) 388 assert.Error(t, err) 389 390 cfg = YAMLConfig{} 391 err = yaml.Unmarshal([]byte(` 392 listener: 393 tls_cert: testdata/chain_cert.pem 394 `), &cfg) 395 require.NoError(t, err) 396 c, err = LoadTLSConfig(cfg) 397 assert.Error(t, err) 398 399 cfg = YAMLConfig{} 400 err = yaml.Unmarshal([]byte(` 401 listener: 402 tls_cert: testdata/doesnotexist_cert.pem 403 tls_key: testdata/doesnotexist_key.pem 404 `), &cfg) 405 require.NoError(t, err) 406 c, err = LoadTLSConfig(cfg) 407 assert.Error(t, err) 408 409 cfg = YAMLConfig{} 410 err = yaml.Unmarshal([]byte(` 411 listener: 412 require_secure_transport: true 413 `), &cfg) 414 require.NoError(t, err) 415 err = ValidateConfig(cfg) 416 assert.Error(t, err) 417 }