Об этом проекте
# go-docker-testsuite
Библиотека Go для запуска сторонних зависимостей в контейнерах Docker при интеграционном тестировании. Она позволяет поднять любой образ Docker — базы данных, очереди, кэши или объектное хранилище — и подключиться к ним из ваших тестов на Go.
## Возможности
- **Container** — низкоуровневая обёртка для создания, запуска, ожидания вывода и очистки любого образа Docker
- **Group** — запуск нескольких контейнеров в изолированной сети Docker с IP-связностью
- **Applications** — готовые обёртки для популярных сервисов (MySQL, PostgreSQL, Redis, Kafka и др.)
- **Hooks** — колбэки жизненного цикла (BeforeRun, AfterRun, BeforeClose, AfterClose) для каждого контейнера
- **Exec** — выполнение команд внутри запущенного контейнера с захватом stdout, stderr и кода выхода
- **Команды жизненного цикла** — команды запуска / после готовности через exec
- **Копирование файлов в контейнеры** — предварительная загрузка файлов перед стартом с помощью `WithFiles`
- **Копирование файлов из контейнеров** — чтение файлов из запущенного контейнера в виде tar-потока
- **Ограничения ресурсов** — ограничение CPU/памяти/pids для защиты хоста и CI
- **Matchers** — ожидание логов контейнера с сопоставлением по подстроке, точному совпадению или regexp
- **Стратегии ожидания** — композируемые проверки готовности (ForLog, ForHTTPGet, ForCommand, ForTCPConnection)
- **Конструктор окружения** — fluent DSL для типизированных переменных окружения
- **Привязки портов** — DNAT-маппинг портов со случайным или взаимно-однозначным распределением
- **Сетевой режим** — поддержка host или пользовательской сети
- **IMAGE_PREFIX** — маршрутизация образов через прокси/зеркало
- **Привязка `*testing.T`** — автоматическая очистка и логирование с безопасным `t.Parallel()`
## Требования
- Go 1.26+
- Запущенный демон Docker (работает с удалёнными хостами через `DOCKER_HOST`)
## Установка
Многомодульное рабочее пространство: корень — это основной модуль, а каждое приложение в `applications/<name>` — отдельный модуль Go. Подключайте только необходимое:
```sh
go get github.com/teran/go-docker-testsuite
# Конкретная обёртка приложения:
go get github.com/teran/go-docker-testsuite/applications/redis
go get github.com/teran/go-docker-testsuite/applications/postgres
```
## Приложения
Готовые обёртки (каждая возвращает типизированный интерфейс клиента и обрабатывает запуск, проверки работоспособности и очистку):
- Ceph (RGW) с AWS SDK v2
- ClickHouse с clickhouse-go
- Forgejo с SQLite
- FRR routing suite с vtysh
- K3s с client-go
- Kafka с Sarama
- Memcache с gomemcache
- MinIO (S3-совместимый)
- MongoDB с mongo-driver
- MySQL / MariaDB / Percona Server
- NetBox с PostgreSQL + Redis
- Nginx
- OpenSearch с opensearch-go
- Paperless-ngx с PostgreSQL + Valkey
- PostgreSQL с pgx
- Prometheus с prometheus/client_golang
- RabbitMQ (AMQP + Management API)
- Redis с go-redis
- ScyllaDB с gocql
- Vault
- Libvirtd (KVM/QEMU)
Многие пакеты включают тестируемые примеры на pkg.go.dev.
## Использование
### Быстрый старт — MySQL
```go
package main
import (
"context"
"database/sql"
"time"
_ "github.com/go-sql-driver/mysql"
"github.com/teran/go-docker-testsuite/applications/mysql"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
app, err := mysql.New(ctx, "index.docker.io/library/mysql:8.0.4")
if err != nil {
panic(err)
}
defer app.Close(ctx)
if err := app.CreateDB(ctx, "important_database"); err != nil {
panic(err)
}
db, err := sql.Open("mysql", app.MustDSN("important_database"))
if err != nil {
panic(err)
}
defer db.Close()
if _, err := db.ExecContext(ctx, "SELECT 1"); err != nil {
panic(err)
}
}
```
### Группа из нескольких контейнеров
```go
package main
import (
"context"
"time"
"github.com/teran/go-docker-testsuite"
"github.com/teran/go-docker-testsuite/wait"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
app := docker.NewApplication(
c,
docker.HookFunc(func(ctx context.Context, ht docker.HookType, c docker.Container) error {
return wait.Wait(ctx, c, wait.ForLog(docker.NewSubstringMatcher("ready")))
}),
)
g, err := docker.NewGroup("my-services", app1, app2)
if err != nil {
panic(err)
}
if err := g.Run(ctx); err != nil {
panic(err)
}
defer g.Close(ctx)
}
```
### Стратегии ожидания
```go
if err := wait.Wait(ctx, c, wait.ForHTTPGet(8080,
wait.WithPath("/health"),
wait.WithResponseStatuses(200),
)); err != nil {
panic(err)
}
```
Другие стратегии: `ForLog`, `ForCommand`, `ForTCPConnection`. Комбинируйте с `ForAll` / `ForAny` / `ForAtLeast`.
### Привязка `*testing.T`
```go
func TestRedis(t *testing.T) {
t.Parallel()
c, err := docker.NewContainerWithT(
t,
"redis",
images.Redis,
nil,
docker.NewEnvironment(),
docker.NewPortBindings().PortDNAT(docker.ProtoTCP, 6379),
)
if err != nil {
t.Fatal(err)
}
c.RunT(ctx) // fail-fast; регистрирует t.Cleanup
}
```
### Хуки жизненного цикла
```go
docker.HookTypeBeforeRun // перед запуском контейнера
docker.HookTypeAfterRun // после запуска контейнера
docker.HookTypeBeforeClose // перед остановкой контейнера
docker.HookTypeAfterClose // после остановки контейнера
```
### Exec и команды жизненного цикла
```go
res, err := c.Exec(ctx, []string{"echo", "hello"})
if err != nil {
panic(err)
}
if err := res.Error(); err != nil {
panic(err)
}
fmt.Printf("exit code: %d\n", res.ExitCode)
fmt.Printf("stdout: %s", res.Stdout)
```
### Копирование файлов в контейнеры и из них
Используйте `WithFiles` с `FileFromBytes` для небольшого содержимого или `io.Reader` + `Size` для больших файлов. Читайте файлы обратно с помощью `docker.CopyFromContainer`.
### Префикс образа / прокси
```sh
export IMAGE_PREFIX=registry-mirror.example.com
```
## Модули и релизы
Многомодульное рабочее пространство с единым номером версии, тегируемое отдельно (например, ядро `v1.6.0`, приложение `applications/redis/v1.6.0`). Порядок релиза: сначала ядро, затем приложения. Используйте Makefile для тегирования.
## Лицензия
Apache License, Version 2.0
Comments
0 Rating appears after 10 ratings
Sign in to join the discussion.