forked from ebhomengo/niki
1
0
Fork 0
niki/delivery/http_server/end2end/setup/docker.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)
}
}