Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor tests to work with testcontainers #59

Merged
merged 7 commits into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 3 additions & 30 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,40 +19,13 @@ jobs:
strategy:
matrix:
go: ["1.18.x", "1.19.x", "1.20.x", "1.21.x"]
services:
mysql8:
image: mysql:8
env:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: pass
ports:
- 3306:3306
options: >-
--health-cmd "mysqladmin ping -ppass"
--health-interval 10s
--health-start-period 10s
--health-timeout 5s
--health-retries 10
postgres15:
image: postgres:15
env:
POSTGRES_DB: test
POSTGRES_PASSWORD: pass
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}
- name: Create Table
run: |
make mysql
make psql
- name: Run integration tests
env:
MYSQL_DSN: AUTO
PSQL_DSN: AUTO
run: go test ./...
54 changes: 3 additions & 51 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,52 +1,4 @@
define MYSQL_SQL
CREATE TABLE users (
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL,
username VARCHAR(32) NOT NULL,
email VARCHAR(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uniq_email (email)
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
endef

define PSQL_SQL
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(32) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL
);
endef

export MYSQL_SQL
MYSQL := "$$MYSQL_SQL"

export PSQL_SQL
PSQL := "$$PSQL_SQL"

INSERTS := "INSERT INTO users (username, email) VALUES ('gopher', 'gopher@go.com'), ('john', 'john@doe.com'), ('jane', 'jane@doe.com');"

MYSQLCMD=mysql
ifndef CI
MYSQLCMD=docker compose exec mysql mysql
endif

PSQLCMD=psql
ifndef CI
PSQLCMD=docker compose exec postgres psql
endif

test: MYSQL_DSN=root:pass@/txdb_test
test: PSQL_DSN=postgres://postgres:pass@localhost/txdb_test
test: mysql psql
@go test -race -tags "mysql psql"

mysql:
@$(MYSQLCMD) -h 127.0.0.1 -u root -ppass -e 'DROP DATABASE IF EXISTS txdb_test'
@$(MYSQLCMD) -h 127.0.0.1 -u root -ppass -e 'CREATE DATABASE txdb_test'
@$(MYSQLCMD) -h 127.0.0.1 -u root -ppass txdb_test -e $(MYSQL)
@$(MYSQLCMD) -h 127.0.0.1 -u root -ppass txdb_test -e $(INSERTS)

psql:
@$(PSQLCMD) "postgresql://postgres:pass@127.0.0.1" -c 'DROP DATABASE IF EXISTS txdb_test'
@$(PSQLCMD) "postgresql://postgres:pass@127.0.0.1" -c 'CREATE DATABASE txdb_test'
@$(PSQLCMD) "postgresql://postgres:pass@127.0.0.1/txdb_test" -c $(PSQL)
@$(PSQLCMD) "postgresql://postgres:pass@127.0.0.1/txdb_test" -c $(INSERTS)

.PHONY: test mysql psql
@go test -race
17 changes: 11 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,19 @@ Every time you will run this application, it will remain in the same state as be

### Testing

Usage is mainly intended for testing purposes. See the **db_test.go** as
an example. In order to run tests, you will need docker and
docker compose:
Usage is mainly intended for testing purposes. Tests require database access, support using `postgres` and `mysql` databases. The easiest way to do this is by using [testcontainers](https://golang.testcontainers.org/), which is enabled by setting the respective database DSN values to `AUTO`. Example:

docker compose up
make test
```bash
MYSQL_DSN=AUTO PSQL_DSN=AUTO go test ./...
```

If you wish to use a running local database instance, you can also provide the DSN directly, and it will be used:

```bash
MYSQL_DSN=root:pass@/ PSQL_DSN=postgres://postgres:pass@localhost/ go test ./...
```

The tests are currently using `postgres` and `mysql` databases
To run tests only against MySQL or PostgreSQL, you may provide only the respective DSN values; any unset DSN is skipped for tests.

### Documentation

Expand Down
111 changes: 111 additions & 0 deletions bootstrap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package txdb_test

import (
"context"
"database/sql"
"strings"
"testing"
"time"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/mysql"
"github.com/testcontainers/testcontainers-go/modules/postgres"
"github.com/testcontainers/testcontainers-go/wait"
)

const (
mysql_sql = `CREATE TABLE users (
id BIGINT UNSIGNED AUTO_INCREMENT NOT NULL,
username VARCHAR(32) NOT NULL,
email VARCHAR(255) NOT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uniq_email (email)
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB`

psql_sql = `CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(32) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL
)`

inserts = `INSERT INTO users (username, email) VALUES ('gopher', 'gopher@go.com'), ('john', 'john@doe.com'), ('jane', 'jane@doe.com')`

testDB = "txdb_test"
)

// bootstrap bootstraps the database for tests.
func bootstrap(t *testing.T, driver, dsn string) {
db, err := sql.Open(driver, dsn)
if err != nil {
t.Fatal(err)
}
switch driver {
case "mysql":
if _, err := db.Exec(mysql_sql); err != nil {
t.Fatal(err)
}
case "postgres":
if _, err := db.Exec(psql_sql); err != nil {
t.Fatal(err)
}
default:
panic("unrecognized driver: " + driver)
}
if _, err := db.Exec(inserts); err != nil {
t.Fatal(err)
}
}

func createDB(t *testing.T, driver, dsn string) {
db, err := sql.Open(driver, dsn)
if err != nil {
t.Fatal(err)
}
if _, err := db.Exec("DROP DATABASE IF EXISTS " + testDB); err != nil {
t.Fatal(err)
}
if _, err := db.Exec("CREATE DATABASE " + testDB); err != nil {
t.Fatal(err)
}
}

func startPostgres(t *testing.T) string {
ctx := context.Background()

postgresContainer, err := postgres.RunContainer(ctx,
Yiling-J marked this conversation as resolved.
Show resolved Hide resolved
testcontainers.WithImage("docker.io/postgres:15.2-alpine"),
postgres.WithDatabase(testDB),
testcontainers.WithWaitStrategy(
wait.ForLog("database system is ready to accept connections").
WithOccurrence(2).
WithStartupTimeout(5*time.Second)),
)
if err != nil {
t.Fatal(err)
}

dsn, err := postgresContainer.ConnectionString(ctx)
if err != nil {
t.Fatal(err)
}
return strings.TrimSuffix(dsn, testDB+"?")
}

func startMySQL(t *testing.T) string {
ctx := context.Background()

mysqlContainer, err := mysql.RunContainer(ctx,
testcontainers.WithImage("mysql:8"),
mysql.WithUsername("root"),
mysql.WithPassword("password"),
mysql.WithDatabase(testDB),
)
if err != nil {
t.Fatal(err)
}
dsn, err := mysqlContainer.ConnectionString(ctx)
if err != nil {
t.Fatal(err)
}
return strings.TrimSuffix(dsn, testDB)
}
Loading