forked from ebhomengo/niki
184 lines
5.2 KiB
Go
184 lines
5.2 KiB
Go
package setup
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"strconv"
|
|
|
|
redisadapter "git.gocasts.ir/ebhomengo/niki/adapter/redis"
|
|
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
|
// nolint
|
|
_ "github.com/go-sql-driver/mysql"
|
|
"github.com/ory/dockertest/v3"
|
|
"github.com/ory/dockertest/v3/docker"
|
|
)
|
|
|
|
// TestContainer holds the state of docker test.
|
|
type TestContainer struct {
|
|
dockerPool *dockertest.Pool // the connection pool to Docker.
|
|
mariaResource *dockertest.Resource // MariaDB Docker container resource.
|
|
redisResource *dockertest.Resource // Redis Docker container resource.
|
|
mariaDBConn *mysql.DB // Connection to the MariaDB database.
|
|
redisDBConn *redisadapter.Adapter // Connection to the Redis database.
|
|
containerExpiryInSeconds uint
|
|
}
|
|
|
|
func NewTestContainer() *TestContainer {
|
|
return &TestContainer{
|
|
// nolint
|
|
containerExpiryInSeconds: 120,
|
|
}
|
|
}
|
|
|
|
func (t *TestContainer) GetMariaDBConnection() *mysql.DB {
|
|
if t.mariaDBConn == nil {
|
|
log.Fatal("did you forgot to start the test container?")
|
|
}
|
|
|
|
return t.mariaDBConn
|
|
}
|
|
|
|
func (t *TestContainer) GetRedisDBConnection() *redisadapter.Adapter {
|
|
if t.redisDBConn == nil {
|
|
log.Fatal("did you forgot to start the test container?")
|
|
}
|
|
|
|
return t.redisDBConn
|
|
}
|
|
|
|
func (t *TestContainer) GetMariaDBConfig() mysql.Config {
|
|
if t.mariaResource == nil {
|
|
log.Fatal("did you forgot to start the test container?")
|
|
}
|
|
|
|
port, err := strconv.Atoi(t.mariaResource.GetPort("3306/tcp"))
|
|
if err != nil {
|
|
log.Fatalf("couldn't convert port to integer: %s", err)
|
|
}
|
|
|
|
return mysql.Config{
|
|
Username: "root",
|
|
Password: "secret",
|
|
Port: port,
|
|
Host: "localhost",
|
|
DBName: "mysql",
|
|
}
|
|
}
|
|
|
|
func (t *TestContainer) GetRedisConfig() redisadapter.Config {
|
|
if t.mariaResource == nil {
|
|
log.Fatal("did you forgot to start the test container?")
|
|
}
|
|
|
|
port, err := strconv.Atoi(t.redisResource.GetPort("6379/tcp"))
|
|
if err != nil {
|
|
log.Fatalf("couldn't convert port to integer: %s", err)
|
|
}
|
|
|
|
return redisadapter.Config{
|
|
Host: "localhost",
|
|
Port: port,
|
|
Password: "",
|
|
DB: 0,
|
|
}
|
|
}
|
|
|
|
// Start initializes and starts the MariaDB and Redis Docker container for testing.
|
|
func (t *TestContainer) Start() {
|
|
// uses a sensible default on windows (tcp/http) and linux/osx (socket)
|
|
var err error
|
|
t.dockerPool, err = dockertest.NewPool("")
|
|
if err != nil {
|
|
log.Fatalf("Could not construct pool: %s", err)
|
|
}
|
|
|
|
// uses pool to try to connect to Docker
|
|
err = t.dockerPool.Client.Ping()
|
|
if err != nil {
|
|
log.Fatalf("Could not connect to Docker: %s", err)
|
|
}
|
|
|
|
// pulls mariaDB image, creates a container based on it and runs it
|
|
t.mariaResource, err = t.dockerPool.RunWithOptions(
|
|
&dockertest.RunOptions{
|
|
Repository: "bitnami/mariadb",
|
|
Tag: "11.1",
|
|
Env: []string{"MARIADB_ROOT_PASSWORD=secret"},
|
|
}, func(config *docker.HostConfig) {
|
|
config.AutoRemove = true // Ensure the container is removed after the test.
|
|
config.RestartPolicy = docker.RestartPolicy{
|
|
Name: "no", // Do not automatically restart the container.
|
|
}
|
|
},
|
|
)
|
|
if err != nil {
|
|
log.Fatalf("Could not start maria resource: %s", err)
|
|
}
|
|
|
|
// Set container to expire after two minutes to avoid dangling resources in case of test interruption.
|
|
if err = t.mariaResource.Expire(t.containerExpiryInSeconds); err != nil {
|
|
log.Fatalf("Couldn't set MariaDB container expiration: %s", err)
|
|
}
|
|
|
|
t.redisResource, err = t.dockerPool.RunWithOptions(
|
|
&dockertest.RunOptions{
|
|
Repository: "bitnami/redis",
|
|
Tag: "6.2",
|
|
Env: []string{"ALLOW_EMPTY_PASSWORD=yes"},
|
|
}, func(config *docker.HostConfig) {
|
|
config.AutoRemove = true // Ensure the container is removed after the test.
|
|
config.RestartPolicy = docker.RestartPolicy{
|
|
Name: "no", // Do not automatically restart the container.
|
|
}
|
|
},
|
|
)
|
|
if err != nil {
|
|
log.Fatalf("Could not start redis resource: %s", err)
|
|
}
|
|
|
|
// Set container to expire after two minutes to avoid dangling resources in case of test interruption.
|
|
if err = t.redisResource.Expire(t.containerExpiryInSeconds); err != nil {
|
|
log.Fatalf("Couldn't set RedisDB container expiration: %s", err)
|
|
}
|
|
|
|
// exponential backoff-retry, because the application in the container might not be ready to accept connections yet
|
|
if err = t.dockerPool.Retry(func() error {
|
|
var err error
|
|
t.mariaDBConn = mysql.New(t.GetMariaDBConfig())
|
|
err = t.mariaDBConn.Conn().Ping()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
t.redisDBConn = redisadapter.New(t.GetRedisConfig())
|
|
err = t.redisDBConn.Client().Ping(context.Background()).Err()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}); err != nil {
|
|
log.Fatalf("Could not connect to database: %s", err)
|
|
}
|
|
}
|
|
|
|
// Stop cleans up the Docker containers.
|
|
func (t *TestContainer) Stop() {
|
|
err := t.mariaDBConn.CloseStatements()
|
|
if err != nil {
|
|
log.Fatalf("Could not close statements on maria db connection: %s", err)
|
|
}
|
|
err = t.mariaDBConn.Conn().Close()
|
|
if err != nil {
|
|
log.Fatalf("Could not close maria db connection: %s", err)
|
|
}
|
|
|
|
if err = t.dockerPool.Purge(t.mariaResource); err != nil {
|
|
log.Fatalf("Could not purge maria resource: %s", err)
|
|
}
|
|
|
|
if err = t.dockerPool.Purge(t.redisResource); err != nil {
|
|
log.Fatalf("Could not purge redis resource: %s", err)
|
|
}
|
|
}
|