Skip to content
This repository has been archived by the owner on Mar 12, 2024. It is now read-only.

Commit

Permalink
e2e: move db container helpers to internal/testdb (pressly#371)
Browse files Browse the repository at this point in the history
  • Loading branch information
mfridman authored Jun 21, 2022
1 parent bfd4286 commit d04c088
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 170 deletions.
4 changes: 4 additions & 0 deletions internal/testdb/clickhouse.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ func newClickHouse(opts ...OptionsFunc) (*sql.DB, func(), error) {
return nil, nil, err
}
cleanup := func() {
if option.debug {
// User must manually delete the Docker container.
return
}
if err := pool.Purge(container); err != nil {
log.Printf("failed to purge resource: %v", err)
}
Expand Down
97 changes: 97 additions & 0 deletions internal/testdb/mariadb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package testdb

import (
"database/sql"
"fmt"
"log"
"strconv"
"time"

"github.com/ory/dockertest/v3"
"github.com/ory/dockertest/v3/docker"
)

const (
// https://hub.docker.com/_/mariadb
MARIADB_IMAGE = "mariadb"
MARIADB_VERSION = "10"

MARIADB_DB = "testdb"
MARIADB_USER = "tester"
MARIADB_PASSWORD = "password1"
)

func newMariaDB(opts ...OptionsFunc) (*sql.DB, func(), error) {
option := &options{}
for _, f := range opts {
f(option)
}
// Uses a sensible default on windows (tcp/http) and linux/osx (socket).
pool, err := dockertest.NewPool("")
if err != nil {
return nil, nil, fmt.Errorf("failed to connect to docker: %v", err)
}
options := &dockertest.RunOptions{
Repository: MARIADB_IMAGE,
Tag: MARIADB_VERSION,
Env: []string{
"MARIADB_USER=" + MARIADB_USER,
"MARIADB_PASSWORD=" + MARIADB_PASSWORD,
"MARIADB_ROOT_PASSWORD=" + MARIADB_PASSWORD,
"MARIADB_DATABASE=" + MARIADB_DB,
},
Labels: map[string]string{"goose_test": "1"},
PortBindings: make(map[docker.Port][]docker.PortBinding),
}
if option.bindPort > 0 {
options.PortBindings[docker.Port("3306/tcp")] = []docker.PortBinding{
{HostPort: strconv.Itoa(option.bindPort)},
}
}
container, err := pool.RunWithOptions(
options,
func(config *docker.HostConfig) {
// Set AutoRemove to true so that stopped container goes away by itself.
config.AutoRemove = true
// config.PortBindings = options.PortBindings
config.RestartPolicy = docker.RestartPolicy{Name: "no"}
},
)
if err != nil {
return nil, nil, fmt.Errorf("failed to create docker container: %v", err)
}
cleanup := func() {
if option.debug {
// User must manually delete the Docker container.
return
}
if err := pool.Purge(container); err != nil {
log.Printf("failed to purge resource: %v", err)
}
}
// MySQL DSN: username:password@protocol(address)/dbname?param=value
dsn := fmt.Sprintf("%s:%s@(%s:%s)/%s?parseTime=true&multiStatements=true",
MARIADB_USER,
MARIADB_PASSWORD,
"localhost",
container.GetPort("3306/tcp"), // Fetch port dynamically assigned to container
MARIADB_DB,
)
var db *sql.DB
// Exponential backoff-retry, because the application in the container
// might not be ready to accept connections yet. Add an extra sleep
// because mariadb containers take much longer to startup.
time.Sleep(5 * time.Second)
if err := pool.Retry(func() error {
var err error
db, err = sql.Open("mysql", dsn)
if err != nil {
return err
}
return db.Ping()
},
); err != nil {
return nil, cleanup, fmt.Errorf("could not connect to docker database: %v", err)
}
return db, cleanup, nil
}
93 changes: 93 additions & 0 deletions internal/testdb/postgres.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package testdb

import (
"database/sql"
"fmt"
"log"
"strconv"

"github.com/ory/dockertest/v3"
"github.com/ory/dockertest/v3/docker"
)

const (
// https://hub.docker.com/_/postgres
POSTGRES_IMAGE = "postgres"
POSTGRES_VERSION = "14-alpine"

POSTGRES_DB = "testdb"
POSTGRES_USER = "postgres"
POSTGRES_PASSWORD = "password1"
)

func newPostgres(opts ...OptionsFunc) (*sql.DB, func(), error) {
option := &options{}
for _, f := range opts {
f(option)
}
// Uses a sensible default on windows (tcp/http) and linux/osx (socket).
pool, err := dockertest.NewPool("")
if err != nil {
return nil, nil, fmt.Errorf("failed to connect to docker: %v", err)
}
options := &dockertest.RunOptions{
Repository: POSTGRES_IMAGE,
Tag: POSTGRES_VERSION,
Env: []string{
"POSTGRES_USER=" + POSTGRES_USER,
"POSTGRES_PASSWORD=" + POSTGRES_PASSWORD,
"POSTGRES_DB=" + POSTGRES_DB,
"listen_addresses = '*'",
},
Labels: map[string]string{"goose_test": "1"},
PortBindings: make(map[docker.Port][]docker.PortBinding),
}
if option.bindPort > 0 {
options.PortBindings[docker.Port("5432/tcp")] = []docker.PortBinding{
{HostPort: strconv.Itoa(option.bindPort)},
}
}
container, err := pool.RunWithOptions(
options,
func(config *docker.HostConfig) {
// Set AutoRemove to true so that stopped container goes away by itself.
config.AutoRemove = true
config.RestartPolicy = docker.RestartPolicy{Name: "no"}
},
)
if err != nil {
return nil, nil, fmt.Errorf("failed to create docker container: %v", err)
}
cleanup := func() {
if option.debug {
// User must manually delete the Docker container.
return
}
if err := pool.Purge(container); err != nil {
log.Printf("failed to purge resource: %v", err)
}
}
psqlInfo := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
"localhost",
container.GetPort("5432/tcp"), // Fetch port dynamically assigned to container
POSTGRES_USER,
POSTGRES_PASSWORD,
POSTGRES_DB,
)
var db *sql.DB
// Exponential backoff-retry, because the application in the container
// might not be ready to accept connections yet.
if err := pool.Retry(
func() error {
var err error
db, err = sql.Open("postgres", psqlInfo)
if err != nil {
return err
}
return db.Ping()
},
); err != nil {
return nil, cleanup, fmt.Errorf("could not connect to docker database: %v", err)
}
return db, cleanup, nil
}
16 changes: 12 additions & 4 deletions internal/testdb/testdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@ package testdb

import "database/sql"

// NewClickHouse starts a ClickHouse docker container, and returns
// a connection and a cleanup function.
// If bindPort is 0,b a random port will be used.
func NewClickHouse(options ...OptionsFunc) (_ *sql.DB, cleanup func(), _ error) {
// NewClickHouse starts a ClickHouse docker container. Returns db connection and a docker cleanup function.
func NewClickHouse(options ...OptionsFunc) (db *sql.DB, cleanup func(), err error) {
return newClickHouse(options...)
}

// NewPostgres starts a PostgreSQL docker container. Returns db connection and a docker cleanup function.
func NewPostgres(options ...OptionsFunc) (db *sql.DB, cleanup func(), err error) {
return newPostgres(options...)
}

// NewMariaDB starts a MariaDB docker container. Returns a db connection and a docker cleanup function.
func NewMariaDB(options ...OptionsFunc) (db *sql.DB, cleanup func(), err error) {
return newMariaDB(options...)
}
Loading

0 comments on commit d04c088

Please sign in to comment.