github.com/mad-app/mattermost-server@v5.11.1+incompatible/store/storetest/settings.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package storetest 5 6 import ( 7 "flag" 8 "fmt" 9 "net/url" 10 "os" 11 "path" 12 13 "database/sql" 14 15 "github.com/go-sql-driver/mysql" 16 _ "github.com/go-sql-driver/mysql" 17 _ "github.com/lib/pq" 18 "github.com/pkg/errors" 19 20 "github.com/mattermost/mattermost-server/model" 21 ) 22 23 const ( 24 defaultMysqlDSN = "mmuser:mostest@tcp(dockerhost:3306)/mattermost_test?charset=utf8mb4,utf8\u0026readTimeout=30s\u0026writeTimeout=30s" 25 defaultPostgresqlDSN = "postgres://mmuser:mostest@dockerhost:5432/mattermost_test?sslmode=disable&connect_timeout=10" 26 defaultMysqlRootPWD = "mostest" 27 ) 28 29 func getEnv(name, defaultValue string) string { 30 if value := os.Getenv(name); value != "" { 31 return value 32 } else { 33 return defaultValue 34 } 35 } 36 37 func log(message string) { 38 verbose := false 39 if verboseFlag := flag.Lookup("test.v"); verboseFlag != nil { 40 verbose = verboseFlag.Value.String() != "" 41 } 42 if verboseFlag := flag.Lookup("v"); verboseFlag != nil { 43 verbose = verboseFlag.Value.String() != "" 44 } 45 46 if verbose { 47 fmt.Println(message) 48 } 49 } 50 51 // MySQLSettings returns the database settings to connect to the MySQL unittesting database. 52 // The database name is generated randomly and must be created before use. 53 func MySQLSettings() *model.SqlSettings { 54 dsn := getEnv("TEST_DATABASE_MYSQL_DSN", defaultMysqlDSN) 55 cfg, err := mysql.ParseDSN(dsn) 56 if err != nil { 57 panic("failed to parse dsn " + dsn + ": " + err.Error()) 58 } 59 60 cfg.DBName = "db" + model.NewId() 61 62 return databaseSettings("mysql", cfg.FormatDSN()) 63 } 64 65 // PostgresSQLSettings returns the database settings to connect to the PostgreSQL unittesting database. 66 // The database name is generated randomly and must be created before use. 67 func PostgreSQLSettings() *model.SqlSettings { 68 dsn := getEnv("TEST_DATABASE_POSTGRESQL_DSN", defaultPostgresqlDSN) 69 dsnUrl, err := url.Parse(dsn) 70 if err != nil { 71 panic("failed to parse dsn " + dsn + ": " + err.Error()) 72 } 73 74 // Generate a random database name 75 dsnUrl.Path = "db" + model.NewId() 76 77 return databaseSettings("postgres", dsnUrl.String()) 78 } 79 80 func mySQLRootDSN(dsn string) string { 81 rootPwd := getEnv("TEST_DATABASE_MYSQL_ROOT_PASSWD", defaultMysqlRootPWD) 82 cfg, err := mysql.ParseDSN(dsn) 83 if err != nil { 84 panic("failed to parse dsn " + dsn + ": " + err.Error()) 85 } 86 87 cfg.User = "root" 88 cfg.Passwd = rootPwd 89 cfg.DBName = "mysql" 90 91 return cfg.FormatDSN() 92 } 93 94 func postgreSQLRootDSN(dsn string) string { 95 dsnUrl, err := url.Parse(dsn) 96 if err != nil { 97 panic("failed to parse dsn " + dsn + ": " + err.Error()) 98 } 99 100 // // Assume the unittesting database has the same password. 101 // password := "" 102 // if dsnUrl.User != nil { 103 // password, _ = dsnUrl.User.Password() 104 // } 105 106 // dsnUrl.User = url.UserPassword("", password) 107 dsnUrl.Path = "postgres" 108 109 return dsnUrl.String() 110 } 111 112 func mySQLDSNDatabase(dsn string) string { 113 cfg, err := mysql.ParseDSN(dsn) 114 if err != nil { 115 panic("failed to parse dsn " + dsn + ": " + err.Error()) 116 } 117 118 return cfg.DBName 119 } 120 121 func postgreSQLDSNDatabase(dsn string) string { 122 dsnUrl, err := url.Parse(dsn) 123 if err != nil { 124 panic("failed to parse dsn " + dsn + ": " + err.Error()) 125 } 126 127 return path.Base(dsnUrl.Path) 128 } 129 130 func databaseSettings(driver, dataSource string) *model.SqlSettings { 131 settings := &model.SqlSettings{ 132 DriverName: &driver, 133 DataSource: &dataSource, 134 DataSourceReplicas: []string{}, 135 DataSourceSearchReplicas: []string{}, 136 MaxIdleConns: new(int), 137 ConnMaxLifetimeMilliseconds: new(int), 138 MaxOpenConns: new(int), 139 Trace: model.NewBool(false), 140 AtRestEncryptKey: model.NewString(model.NewRandomString(32)), 141 QueryTimeout: new(int), 142 } 143 *settings.MaxIdleConns = 10 144 *settings.ConnMaxLifetimeMilliseconds = 3600000 145 *settings.MaxOpenConns = 100 146 *settings.QueryTimeout = 60 147 148 return settings 149 } 150 151 // execAsRoot executes the given sql as root against the testing database 152 func execAsRoot(settings *model.SqlSettings, sqlCommand string) error { 153 var dsn string 154 var driver = *settings.DriverName 155 156 switch driver { 157 case model.DATABASE_DRIVER_MYSQL: 158 dsn = mySQLRootDSN(*settings.DataSource) 159 case model.DATABASE_DRIVER_POSTGRES: 160 dsn = postgreSQLRootDSN(*settings.DataSource) 161 default: 162 return fmt.Errorf("unsupported driver %s", driver) 163 } 164 165 db, err := sql.Open(driver, dsn) 166 if err != nil { 167 return errors.Wrapf(err, "failed to connect to %s database as root", driver) 168 } 169 defer db.Close() 170 if _, err = db.Exec(sqlCommand); err != nil { 171 return errors.Wrapf(err, "failed to execute `%s` against %s database as root", sqlCommand, driver) 172 } 173 174 return nil 175 } 176 177 // MakeSqlSettings creates a randomly named database and returns the corresponding sql settings 178 func MakeSqlSettings(driver string) *model.SqlSettings { 179 var settings *model.SqlSettings 180 var dbName string 181 182 switch driver { 183 case model.DATABASE_DRIVER_MYSQL: 184 settings = MySQLSettings() 185 dbName = mySQLDSNDatabase(*settings.DataSource) 186 case model.DATABASE_DRIVER_POSTGRES: 187 settings = PostgreSQLSettings() 188 dbName = postgreSQLDSNDatabase(*settings.DataSource) 189 default: 190 panic("unsupported driver " + driver) 191 } 192 193 if err := execAsRoot(settings, "CREATE DATABASE "+dbName); err != nil { 194 panic("failed to create temporary database " + dbName + ": " + err.Error()) 195 } 196 197 switch driver { 198 case model.DATABASE_DRIVER_MYSQL: 199 if err := execAsRoot(settings, "GRANT ALL PRIVILEGES ON "+dbName+".* TO 'mmuser'"); err != nil { 200 panic("failed to grant mmuser permission to " + dbName + ":" + err.Error()) 201 } 202 case model.DATABASE_DRIVER_POSTGRES: 203 if err := execAsRoot(settings, "GRANT ALL PRIVILEGES ON DATABASE \""+dbName+"\" TO mmuser"); err != nil { 204 panic("failed to grant mmuser permission to " + dbName + ":" + err.Error()) 205 } 206 default: 207 panic("unsupported driver " + driver) 208 } 209 210 log("Created temporary " + driver + " database " + dbName) 211 212 return settings 213 } 214 215 func CleanupSqlSettings(settings *model.SqlSettings) { 216 var driver = *settings.DriverName 217 var dbName string 218 219 switch driver { 220 case model.DATABASE_DRIVER_MYSQL: 221 dbName = mySQLDSNDatabase(*settings.DataSource) 222 case model.DATABASE_DRIVER_POSTGRES: 223 dbName = postgreSQLDSNDatabase(*settings.DataSource) 224 default: 225 panic("unsupported driver " + driver) 226 } 227 228 if err := execAsRoot(settings, "DROP DATABASE "+dbName); err != nil { 229 panic("failed to drop temporary database " + dbName + ": " + err.Error()) 230 } 231 232 log("Dropped temporary database " + dbName) 233 }