Для запуска интеграционных тестов в Golang часто требуются внешние зависимости в виде базы данных, брокера сообщений либо еще каких-то сторонних компонентов.В итоге для поднятия внешних сервисов мы используем Docker и пишем docker-compose.yml файл который выглядит как-то так:
version: '3'
services:
db:
image: postgres:10.6-alpine
ports:
- '5432'
environment:
LC_ALL: C.UTF-8
POSTGRES_DB: test
POSTGRES_USER: test
POSTGRES_PASSWORD: pass
Далее до запуска go test мы делаем docker-compose up -d.
Все вроде здорово и все работает, но что если мы будем запускать нужные нам контейнеры прямо в наших тестах? А после завершения мы будем все очищать. И все это без yaml и утилиты docker-compose.
Это возможно при помощи библиотеки https://github.com/ory/dockertest
package main
import (
"fmt"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
"github.com/ory/dockertest"
"log"
)
func main() {
pool, err := dockertest.NewPool("")
if err != nil {
log.Fatalf("Could not connect to docker pool: %s", err)
}
// pulls an image, creates a container based on it and runs it
resource, err := pool.Run("postgres", "10.6-alpine", []string{"POSTGRES_DB=test", "POSTGRES_USER=test", "POSTGRES_PASSWORD=pass"})
if err != nil {
log.Fatalf("Could not start resource: %s", err)
}
if err := pool.Retry(func() error {
var err error
dsnString := "postgres://test:[email protected]:" + resource.GetPort("5432/tcp") + "/test?sslmode=disable"
db, err := sqlx.Connect("postgres", dsnString)
if err != nil {
return err
}
return db.Ping()
}); err != nil {
log.Printf("Could not connect to docker resource: %s", err)
}
fmt.Println(" Image port: " + resource.GetPort("5432/tcp"))
if err := pool.Purge(resource); err != nil {
log.Fatalf("Could not purge resource: %s", err)
}
}
Что делает наш код? В начале поднимает dockertest pool и запускает нужный нам контейнер при помощи pool.Run:
resource, err := pool.Run("postgres", "10.6-alpine", []string{"POSTGRES_DB=test", "POSTGRES_USER=test", "POSTGRES_PASSWORD=pass"})
Далее наша программа ждет пока контейнер не будет готов к работе при помощи метода pool.Retry и когда все готово просто показывает на каком порту работает наш Postgres:
resource.GetPort("5432/tcp")
Итого данный кусок кода можно поместить в начало и последнюю часть в конец работы наших тестов.