You've already forked focalboard
							
							
				mirror of
				https://github.com/mattermost/focalboard.git
				synced 2025-10-31 00:17:42 +02:00 
			
		
		
		
	Test all supported databases in CI (#2000)
* add mysql and postgres tests to CI
This commit is contained in:
		
							
								
								
									
										8
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -43,9 +43,15 @@ jobs: | ||||
|         name: focalboard-server-linux-amd64.tar.gz | ||||
|         path: ${{ github.workspace }}/dist/focalboard-server-linux-amd64.tar.gz | ||||
|  | ||||
|     - name: Test server | ||||
|     - name: "Test server: sqlite" | ||||
|       run: make server-test | ||||
|  | ||||
|     - name: "Test server: mysql" | ||||
|       run: make server-test-mysql | ||||
|  | ||||
|     - name: "Test server: postgres" | ||||
|       run: make server-test-postgres | ||||
|  | ||||
|     - name: "Test webapp: Jest" | ||||
|       run: cd webapp; npm run test | ||||
|  | ||||
|   | ||||
							
								
								
									
										22
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								Makefile
									
									
									
									
									
								
							| @@ -105,6 +105,28 @@ watch-server-test: modd-precheck ## Run server tests watching for changes | ||||
| server-test: ## Run server tests | ||||
| 	cd server; go test -race -v -count=1 ./... | ||||
|  | ||||
|  | ||||
|  | ||||
| server-test-mysql: export FB_UNIT_TESTING=1 | ||||
| server-test-mysql: export FB_STORE_TEST_DB_TYPE=mysql | ||||
| server-test-mysql: export FB_STORE_TEST_DOCKER_PORT=44445 | ||||
|  | ||||
| server-test-mysql: ## Run server tests using mysql | ||||
| 	@echo Starting docker container for mysql | ||||
| 	docker-compose -f ./docker-testing/docker-compose-mysql.yml run start_dependencies | ||||
| 	cd server; go test -race -v -count=1 ./... | ||||
| 	docker-compose -f ./docker-testing/docker-compose-mysql.yml down -v --remove-orphans  | ||||
|  | ||||
| server-test-postgres: export FB_UNIT_TESTING=1 | ||||
| server-test-postgres: export FB_STORE_TEST_DB_TYPE=postgres | ||||
| server-test-postgres: export FB_STORE_TEST_DOCKER_PORT=44446 | ||||
|  | ||||
| server-test-postgres: ## Run server tests using postgres | ||||
| 	@echo Starting docker container for postgres | ||||
| 	docker-compose -f ./docker-testing/docker-compose-postgres.yml run start_dependencies | ||||
| 	cd server; go test -race -v -count=1 ./... | ||||
| 	docker-compose -f ./docker-testing/docker-compose-postgres.yml down -v --remove-orphans  | ||||
|  | ||||
| webapp: ## Build webapp. | ||||
| 	cd webapp; npm run pack | ||||
|  | ||||
|   | ||||
							
								
								
									
										25
									
								
								docker-testing/docker-compose-mysql.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								docker-testing/docker-compose-mysql.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| version: '2.4' | ||||
| services: | ||||
|   mysql: | ||||
|     image: "mysql/mysql-server:5.7.12" | ||||
|     restart: always | ||||
|     environment: | ||||
|       MYSQL_ROOT_HOST: "%" | ||||
|       MYSQL_ROOT_PASSWORD: mostest | ||||
|       MYSQL_PASSWORD: mostest | ||||
|       MYSQL_USER: mmuser | ||||
|     healthcheck: | ||||
|       test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] | ||||
|       interval: 5s | ||||
|       timeout: 10s | ||||
|       retries: 3 | ||||
|     tmpfs: /var/lib/mysql | ||||
|     ports: | ||||
|       - 44445:3306 | ||||
|  | ||||
|   start_dependencies: | ||||
|     image: mattermost/mattermost-wait-for-dep:latest | ||||
|     depends_on: | ||||
|       - mysql | ||||
|     command: mysql | ||||
|  | ||||
							
								
								
									
										23
									
								
								docker-testing/docker-compose-postgres.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								docker-testing/docker-compose-postgres.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| version: '2.4' | ||||
| services: | ||||
|   postgres: | ||||
|     image: "postgres:10" | ||||
|     restart: always | ||||
|     environment: | ||||
|       POSTGRES_USER: mmuser | ||||
|       POSTGRES_PASSWORD: mostest | ||||
|     healthcheck: | ||||
|       test: [ "CMD", "pg_isready", "-h", "localhost" ] | ||||
|       interval: 5s | ||||
|       timeout: 10s | ||||
|       retries: 3 | ||||
|     tmpfs: /var/lib/postgresql/data | ||||
|     ports: | ||||
|       - 44446:5432 | ||||
|  | ||||
|   start_dependencies: | ||||
|     image: mattermost/mattermost-wait-for-dep:latest | ||||
|     depends_on: | ||||
|       - postgres | ||||
|     command: postgres:5432 | ||||
|  | ||||
| @@ -10,6 +10,7 @@ import ( | ||||
| 	"github.com/mattermost/focalboard/server/client" | ||||
| 	"github.com/mattermost/focalboard/server/server" | ||||
| 	"github.com/mattermost/focalboard/server/services/config" | ||||
| 	"github.com/mattermost/focalboard/server/services/store/sqlstore" | ||||
| 	"github.com/mattermost/focalboard/server/utils" | ||||
|  | ||||
| 	"github.com/mattermost/mattermost-server/v6/shared/mlog" | ||||
| @@ -21,15 +22,10 @@ type TestHelper struct { | ||||
| 	Client2 *client.Client | ||||
| } | ||||
|  | ||||
| func getTestConfig() *config.Configuration { | ||||
| 	dbType := os.Getenv("FB_STORE_TEST_DB_TYPE") | ||||
| 	if dbType == "" { | ||||
| 		dbType = "sqlite3" | ||||
| 	} | ||||
|  | ||||
| 	connectionString := os.Getenv("FB_STORE_TEST_CONN_STRING") | ||||
| 	if connectionString == "" { | ||||
| 		connectionString = ":memory:" | ||||
| func getTestConfig() (*config.Configuration, error) { | ||||
| 	dbType, connectionString, err := sqlstore.PrepareNewTestDatabase() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	logging := ` | ||||
| @@ -66,15 +62,19 @@ func getTestConfig() *config.Configuration { | ||||
| 		LoggingCfgJSON:    logging, | ||||
| 		SessionExpireTime: int64(30 * time.Second), | ||||
| 		AuthMode:          "native", | ||||
| 	} | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func newTestServer(singleUserToken string) *server.Server { | ||||
| 	logger, _ := mlog.NewLogger() | ||||
| 	if err := logger.Configure("", getTestConfig().LoggingCfgJSON, nil); err != nil { | ||||
| 	cfg, err := getTestConfig() | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	logger, _ := mlog.NewLogger() | ||||
| 	if err = logger.Configure("", cfg.LoggingCfgJSON, nil); err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	cfg := getTestConfig() | ||||
| 	db, err := server.NewStore(cfg, logger) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
|   | ||||
| @@ -182,7 +182,7 @@ func (s *SQLStore) getSubTree3(db sq.BaseRunner, c store.Container, blockID stri | ||||
| 		Join(s.tablePrefix + "blocks" + " as l3 on l3.parent_id = l2.id or l3.id = l2.id"). | ||||
| 		Where(sq.Eq{"l1.id": blockID}). | ||||
| 		Where(sq.Eq{"COALESCE(l3.workspace_id, '0')": c.WorkspaceID}). | ||||
| 		OrderBy("l3.insert_at") | ||||
| 		OrderBy("l3.id, l3.insert_at") | ||||
|  | ||||
| 	if opts.BeforeUpdateAt != 0 { | ||||
| 		query = query.Where(sq.LtOrEq{"update_at": opts.BeforeUpdateAt}) | ||||
|   | ||||
| @@ -2,7 +2,6 @@ package sqlstore | ||||
|  | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/mattermost/focalboard/server/services/store" | ||||
| @@ -12,15 +11,8 @@ import ( | ||||
| ) | ||||
|  | ||||
| func SetupTests(t *testing.T) (store.Store, func()) { | ||||
| 	dbType := os.Getenv("FB_STORE_TEST_DB_TYPE") | ||||
| 	if dbType == "" { | ||||
| 		dbType = sqliteDBType | ||||
| 	} | ||||
|  | ||||
| 	connectionString := os.Getenv("FB_STORE_TEST_CONN_STRING") | ||||
| 	if connectionString == "" { | ||||
| 		connectionString = ":memory:" | ||||
| 	} | ||||
| 	dbType, connectionString, err := PrepareNewTestDatabase() | ||||
| 	require.NoError(t, err) | ||||
|  | ||||
| 	logger := mlog.CreateConsoleTestLogger(false, mlog.LvlDebug) | ||||
|  | ||||
|   | ||||
| @@ -2,8 +2,12 @@ package sqlstore | ||||
|  | ||||
| import ( | ||||
| 	"database/sql" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/mattermost/focalboard/server/services/store" | ||||
| 	"github.com/mattermost/focalboard/server/utils" | ||||
|  | ||||
| 	"github.com/mattermost/mattermost-server/v6/shared/mlog" | ||||
| ) | ||||
| @@ -17,3 +21,78 @@ func (s *SQLStore) CloseRows(rows *sql.Rows) { | ||||
| func (s *SQLStore) IsErrNotFound(err error) bool { | ||||
| 	return store.IsErrNotFound(err) | ||||
| } | ||||
|  | ||||
| func PrepareNewTestDatabase() (dbType string, connectionString string, err error) { | ||||
| 	dbType = strings.TrimSpace(os.Getenv("FB_STORE_TEST_DB_TYPE")) | ||||
| 	if dbType == "" { | ||||
| 		dbType = sqliteDBType | ||||
| 	} | ||||
|  | ||||
| 	var dbName string | ||||
| 	var rootUser string | ||||
|  | ||||
| 	if dbType == sqliteDBType { | ||||
| 		connectionString = ":memory:" | ||||
| 	} else if port := strings.TrimSpace(os.Getenv("FB_STORE_TEST_DOCKER_PORT")); port != "" { | ||||
| 		// docker unit tests take priority over any DSN env vars | ||||
| 		var template string | ||||
| 		switch dbType { | ||||
| 		case mysqlDBType: | ||||
| 			template = "%s:mostest@tcp(localhost:%s)/%s?charset=utf8mb4,utf8&writeTimeout=30s" | ||||
| 			rootUser = "root" | ||||
| 		case postgresDBType: | ||||
| 			template = "postgres://%s:mostest@localhost:%s/%s?sslmode=disable\u0026connect_timeout=10" | ||||
| 			rootUser = "mmuser" | ||||
| 		default: | ||||
| 			return "", "", newErrInvalidDBType(dbType) | ||||
| 		} | ||||
|  | ||||
| 		connectionString = fmt.Sprintf(template, rootUser, port, "") | ||||
|  | ||||
| 		// create a new database each run | ||||
| 		sqlDB, err := sql.Open(dbType, connectionString) | ||||
| 		if err != nil { | ||||
| 			return "", "", fmt.Errorf("cannot connect to %s database: %w", dbType, err) | ||||
| 		} | ||||
| 		defer sqlDB.Close() | ||||
|  | ||||
| 		err = sqlDB.Ping() | ||||
| 		if err != nil { | ||||
| 			return "", "", fmt.Errorf("cannot ping %s database: %w", dbType, err) | ||||
| 		} | ||||
|  | ||||
| 		dbName = "testdb_" + utils.NewID(utils.IDTypeNone)[:8] | ||||
| 		_, err = sqlDB.Exec(fmt.Sprintf("CREATE DATABASE %s;", dbName)) | ||||
| 		if err != nil { | ||||
| 			return "", "", fmt.Errorf("cannot create %s database %s: %w", dbType, dbName, err) | ||||
| 		} | ||||
|  | ||||
| 		if dbType != postgresDBType { | ||||
| 			_, err = sqlDB.Exec(fmt.Sprintf("GRANT ALL PRIVILEGES ON %s.* TO mmuser;", dbName)) | ||||
| 			if err != nil { | ||||
| 				return "", "", fmt.Errorf("cannot grant permissions on %s database %s: %w", dbType, dbName, err) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		connectionString = fmt.Sprintf(template, "mmuser", port, dbName) | ||||
| 	} else { | ||||
| 		// mysql or postgres need a DSN (connection string) | ||||
| 		connectionString = strings.TrimSpace(os.Getenv("FB_STORE_TEST_CONN_STRING")) | ||||
| 	} | ||||
|  | ||||
| 	return dbType, connectionString, nil | ||||
| } | ||||
|  | ||||
| type ErrInvalidDBType struct { | ||||
| 	dbType string | ||||
| } | ||||
|  | ||||
| func newErrInvalidDBType(dbType string) error { | ||||
| 	return ErrInvalidDBType{ | ||||
| 		dbType: dbType, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (e ErrInvalidDBType) Error() string { | ||||
| 	return "unsupported database type: " + e.dbType | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user