/* * Minio Cloud Storage, (C) 2016, 2017 Minio, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package cmd import ( "io/ioutil" "os" "path/filepath" "reflect" "testing" "github.com/tidwall/gjson" ) func TestServerConfig(t *testing.T) { rootPath, err := newTestConfig(globalMinioDefaultRegion) if err != nil { t.Fatalf("Init Test config failed") } // remove the root directory after the test ends. defer os.RemoveAll(rootPath) if serverConfig.GetRegion() != globalMinioDefaultRegion { t.Errorf("Expecting region `us-east-1` found %s", serverConfig.GetRegion()) } // Set new region and verify. serverConfig.SetRegion("us-west-1") if serverConfig.GetRegion() != "us-west-1" { t.Errorf("Expecting region `us-west-1` found %s", serverConfig.GetRegion()) } // Set new amqp notification id. serverConfig.Notify.SetAMQPByID("2", amqpNotify{}) savedNotifyCfg1 := serverConfig.Notify.GetAMQPByID("2") if !reflect.DeepEqual(savedNotifyCfg1, amqpNotify{}) { t.Errorf("Expecting AMQP config %#v found %#v", amqpNotify{}, savedNotifyCfg1) } // Set new elastic search notification id. serverConfig.Notify.SetElasticSearchByID("2", elasticSearchNotify{}) savedNotifyCfg2 := serverConfig.Notify.GetElasticSearchByID("2") if !reflect.DeepEqual(savedNotifyCfg2, elasticSearchNotify{}) { t.Errorf("Expecting Elasticsearch config %#v found %#v", elasticSearchNotify{}, savedNotifyCfg2) } // Set new redis notification id. serverConfig.Notify.SetRedisByID("2", redisNotify{}) savedNotifyCfg3 := serverConfig.Notify.GetRedisByID("2") if !reflect.DeepEqual(savedNotifyCfg3, redisNotify{}) { t.Errorf("Expecting Redis config %#v found %#v", redisNotify{}, savedNotifyCfg3) } // Set new kafka notification id. serverConfig.Notify.SetKafkaByID("2", kafkaNotify{}) savedNotifyCfg4 := serverConfig.Notify.GetKafkaByID("2") if !reflect.DeepEqual(savedNotifyCfg4, kafkaNotify{}) { t.Errorf("Expecting Kafka config %#v found %#v", kafkaNotify{}, savedNotifyCfg4) } // Set new Webhook notification id. serverConfig.Notify.SetWebhookByID("2", webhookNotify{}) savedNotifyCfg5 := serverConfig.Notify.GetWebhookByID("2") if !reflect.DeepEqual(savedNotifyCfg5, webhookNotify{}) { t.Errorf("Expecting Webhook config %#v found %#v", webhookNotify{}, savedNotifyCfg5) } // Set new console logger. // Set new MySQL notification id. serverConfig.Notify.SetMySQLByID("2", mySQLNotify{}) savedNotifyCfg6 := serverConfig.Notify.GetMySQLByID("2") if !reflect.DeepEqual(savedNotifyCfg6, mySQLNotify{}) { t.Errorf("Expecting Webhook config %#v found %#v", mySQLNotify{}, savedNotifyCfg6) } // Set new console logger. // Set new MQTT notification id. serverConfig.Notify.SetMQTTByID("2", mqttNotify{}) savedNotifyCfg7 := serverConfig.Notify.GetMQTTByID("2") if !reflect.DeepEqual(savedNotifyCfg7, mqttNotify{}) { t.Errorf("Expecting Webhook config %#v found %#v", mqttNotify{}, savedNotifyCfg7) } consoleLogger := NewConsoleLogger() serverConfig.Logger.SetConsole(consoleLogger) consoleCfg := serverConfig.Logger.GetConsole() if !reflect.DeepEqual(consoleCfg, consoleLogger) { t.Errorf("Expecting console logger config %#v found %#v", consoleLogger, consoleCfg) } // Set new console logger. consoleLogger.Enable = false serverConfig.Logger.SetConsole(consoleLogger) // Set new file logger. fileLogger := NewFileLogger("test-log-file") serverConfig.Logger.SetFile(fileLogger) fileCfg := serverConfig.Logger.GetFile() if !reflect.DeepEqual(fileCfg, fileLogger) { t.Errorf("Expecting file logger config %#v found %#v", fileLogger, fileCfg) } // Set new file logger. fileLogger.Enable = false serverConfig.Logger.SetFile(fileLogger) // Match version. if serverConfig.GetVersion() != v20 { t.Errorf("Expecting version %s found %s", serverConfig.GetVersion(), v20) } // Attempt to save. if err := serverConfig.Save(); err != nil { t.Fatalf("Unable to save updated config file %s", err) } // Do this only once here. setConfigDir(rootPath) // Initialize server config. if err := loadConfig(); err != nil { t.Fatalf("Unable to initialize from updated config file %s", err) } } func TestServerConfigWithEnvs(t *testing.T) { os.Setenv("MINIO_BROWSER", "off") defer os.Unsetenv("MINIO_BROWSER") os.Setenv("MINIO_ACCESS_KEY", "minio") defer os.Unsetenv("MINIO_ACCESS_KEY") os.Setenv("MINIO_SECRET_KEY", "minio123") defer os.Unsetenv("MINIO_SECRET_KEY") os.Setenv("MINIO_REGION", "us-west-1") defer os.Unsetenv("MINIO_REGION") os.Setenv("MINIO_DOMAIN", "domain.com") defer os.Unsetenv("MINIO_DOMAIN") defer resetGlobalIsEnvs() // Get test root. rootPath, err := getTestRoot() if err != nil { t.Error(err) } serverHandleEnvVars() // Do this only once here. setConfigDir(rootPath) // Init config initConfig() // remove the root directory after the test ends. defer os.RemoveAll(rootPath) // Check if serverConfig has if serverConfig.GetBrowser() { t.Errorf("Expecting browser is set to false found %v", serverConfig.GetBrowser()) } // Check if serverConfig has if serverConfig.GetRegion() != "us-west-1" { t.Errorf("Expecting region to be \"us-west-1\" found %v", serverConfig.GetRegion()) } // Check if serverConfig has cred := serverConfig.GetCredential() if cred.AccessKey != "minio" { t.Errorf("Expecting access key to be `minio` found %s", cred.AccessKey) } if cred.SecretKey != "minio123" { t.Errorf("Expecting access key to be `minio123` found %s", cred.SecretKey) } if serverConfig.Domain != "domain.com" { t.Errorf("Expecting Domain to be `domain.com` found " + serverConfig.Domain) } } func TestCheckDupJSONKeys(t *testing.T) { testCases := []struct { json string shouldPass bool }{ {`{}`, true}, {`{"version" : "13"}`, true}, {`{"version" : "13", "version": "14"}`, false}, {`{"version" : "13", "credential": {"accessKey": "12345"}}`, true}, {`{"version" : "13", "credential": {"accessKey": "12345", "accessKey":"12345"}}`, false}, {`{"version" : "13", "notify": {"amqp": {"1"}, "webhook":{"3"}}}`, true}, {`{"version" : "13", "notify": {"amqp": {"1"}, "amqp":{"3"}}}`, false}, {`{"version" : "13", "notify": {"amqp": {"1":{}, "2":{}}}}`, true}, {`{"version" : "13", "notify": {"amqp": {"1":{}, "1":{}}}}`, false}, } for i, testCase := range testCases { err := doCheckDupJSONKeys(gjson.Result{}, gjson.Parse(testCase.json)) if testCase.shouldPass && err != nil { t.Errorf("Test %d, should pass but it failed with err = %v", i+1, err) } if !testCase.shouldPass && err == nil { t.Errorf("Test %d, should fail but it succeed.", i+1) } } } // Tests config validator.. func TestValidateConfig(t *testing.T) { rootPath, err := newTestConfig(globalMinioDefaultRegion) if err != nil { t.Fatalf("Init Test config failed") } // remove the root directory after the test ends. defer os.RemoveAll(rootPath) configPath := filepath.Join(rootPath, minioConfigFile) v := v20 testCases := []struct { configData string shouldPass bool }{ // Test 1 - wrong json {`{`, false}, // Test 2 - empty json {`{}`, false}, // Test 3 - wrong config version {`{"version": "10"}`, false}, // Test 4 - wrong browser parameter {`{"version": "` + v + `", "browser": "foo"}`, false}, // Test 5 - missing credential {`{"version": "` + v + `", "browser": "on"}`, false}, // Test 6 - missing secret key {`{"version": "` + v + `", "browser": "on", "credential" : {"accessKey":"minio", "secretKey":""}}`, false}, // Test 7 - missing region should pass, defaults to 'us-east-1'. {`{"version": "` + v + `", "browser": "on", "credential" : {"accessKey":"minio", "secretKey":"minio123"}}`, true}, // Test 8 - missing browser should pass, defaults to 'on'. {`{"version": "` + v + `", "region": "us-east-1", "credential" : {"accessKey":"minio", "secretKey":"minio123"}}`, true}, // Test 9 - success {`{"version": "` + v + `", "browser": "on", "region":"us-east-1", "credential" : {"accessKey":"minio", "secretKey":"minio123"}}`, true}, // Test 10 - duplicated json keys {`{"version": "` + v + `", "browser": "on", "browser": "on", "region":"us-east-1", "credential" : {"accessKey":"minio", "secretKey":"minio123"}}`, false}, // Test 11 - empty filename field in File {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "logger": { "file": { "enable": true, "filename": "" } }}`, false}, // Test 12 - Test AMQP {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "amqp": { "1": { "enable": true, "url": "", "exchange": "", "routingKey": "", "exchangeType": "", "mandatory": false, "immediate": false, "durable": false, "internal": false, "noWait": false, "autoDeleted": false }}}}`, false}, // Test 13 - Test NATS {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "nats": { "1": { "enable": true, "address": "", "subject": "", "username": "", "password": "", "token": "", "secure": false, "pingInterval": 0, "streaming": { "enable": false, "clusterID": "", "clientID": "", "async": false, "maxPubAcksInflight": 0 } } }}}`, false}, // Test 14 - Test ElasticSearch {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "elasticsearch": { "1": { "enable": true, "url": "", "index": "" } }}}`, false}, // Test 15 - Test Redis {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "redis": { "1": { "enable": true, "address": "", "password": "", "key": "" } }}}`, false}, // Test 16 - Test PostgreSQL {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "postgresql": { "1": { "enable": true, "connectionString": "", "table": "", "host": "", "port": "", "user": "", "password": "", "database": "" }}}}`, false}, // Test 17 - Test Kafka {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "kafka": { "1": { "enable": true, "brokers": null, "topic": "" } }}}`, false}, // Test 18 - Test Webhook {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "webhook": { "1": { "enable": true, "endpoint": "" } }}}`, false}, // Test 20 - Test MySQL {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "mysql": { "1": { "enable": true, "dsnString": "", "table": "", "host": "", "port": "", "user": "", "password": "", "database": "" }}}}`, false}, // Test 21 - Test Format for MySQL {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "mysql": { "1": { "enable": true, "dsnString": "", "format": "invalid", "table": "xxx", "host": "10.0.0.1", "port": "3306", "user": "abc", "password": "pqr", "database": "test1" }}}}`, false}, // Test 22 - Test valid Format for MySQL {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "mysql": { "1": { "enable": true, "dsnString": "", "format": "namespace", "table": "xxx", "host": "10.0.0.1", "port": "3306", "user": "abc", "password": "pqr", "database": "test1" }}}}`, true}, // Test 23 - Test Format for PostgreSQL {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "postgresql": { "1": { "enable": true, "connectionString": "", "format": "invalid", "table": "xxx", "host": "myhost", "port": "5432", "user": "abc", "password": "pqr", "database": "test1" }}}}`, false}, // Test 24 - Test valid Format for PostgreSQL {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "postgresql": { "1": { "enable": true, "connectionString": "", "format": "namespace", "table": "xxx", "host": "myhost", "port": "5432", "user": "abc", "password": "pqr", "database": "test1" }}}}`, true}, // Test 25 - Test Format for ElasticSearch {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "elasticsearch": { "1": { "enable": true, "format": "invalid", "url": "example.com", "index": "myindex" } }}}`, false}, // Test 26 - Test valid Format for ElasticSearch {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "elasticsearch": { "1": { "enable": true, "format": "namespace", "url": "example.com", "index": "myindex" } }}}`, true}, // Test 27 - Test Format for Redis {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "redis": { "1": { "enable": true, "format": "invalid", "address": "example.com:80", "password": "xxx", "key": "key1" } }}}`, false}, // Test 28 - Test valid Format for Redis {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "redis": { "1": { "enable": true, "format": "namespace", "address": "example.com:80", "password": "xxx", "key": "key1" } }}}`, true}, // Test 29 - Test MQTT {`{"version": "` + v + `", "credential": { "accessKey": "minio", "secretKey": "minio123" }, "region": "us-east-1", "browser": "on", "notify": { "mqtt": { "1": { "enable": true, "broker": "", "topic": "", "qos": 0, "clientId": "", "username": "", "password": ""}}}}`, false}, } for i, testCase := range testCases { if werr := ioutil.WriteFile(configPath, []byte(testCase.configData), 0700); werr != nil { t.Fatal(werr) } _, verr := getValidConfig() if testCase.shouldPass && verr != nil { t.Errorf("Test %d, should pass but it failed with err = %v", i+1, verr) } if !testCase.shouldPass && verr == nil { t.Errorf("Test %d, should fail but it succeed.", i+1) } } }