About this project
# go-docker-testsuite
A Go library to run third-party dependencies in Docker containers for integration testing. It lets you spin up any Docker image—databases, queues, caches, or object storage—and connect to them from your Go tests.
## Features
- **Container** — low-level wrapper to create, run, await output, and clean up any Docker image
- **Group** — run multiple containers in an isolated Docker network with IP-level connectivity
- **Applications** — ready-to-use wrappers for popular services (MySQL, PostgreSQL, Redis, Kafka, etc.)
- **Hooks** — lifecycle callbacks (BeforeRun, AfterRun, BeforeClose, AfterClose) per container
- **Exec** — run commands inside a running container and capture stdout, stderr, and exit code
- **Lifecycle commands** — run startup / after-ready commands via exec
- **Copy files into containers** — seed files before start with `WithFiles`
- **Copy files out of containers** — read files back out of a running container as a tar stream
- **Resource limits** — cap CPU/memory/pids to protect the host and CI
- **Matchers** — await container logs with substring, exact, or regexp matchers
- **Wait strategies** — composable readiness probes (ForLog, ForHTTPGet, ForCommand, ForTCPConnection)
- **Environment builder** — fluent DSL for typed environment variables
- **Port bindings** — DNAT port mapping with random or one-to-one allocation
- **Network mode** — host or custom network support
- **IMAGE_PREFIX** — route images through a proxy/mirror
- **`*testing.T` binding** — automatic teardown and logging with safe `t.Parallel()`
## Requirements
- Go 1.26+
- A running Docker daemon (works with remote hosts via `DOCKER_HOST`)
## Installation
Multi-module workspace: the root is the core module, and each application under `applications/<name>` is its own Go module. Pull only what you need:
```sh
go get github.com/teran/go-docker-testsuite
# Specific application wrapper:
go get github.com/teran/go-docker-testsuite/applications/redis
go get github.com/teran/go-docker-testsuite/applications/postgres
```
## Applications
Ready-to-use wrappers (each returns a typed client interface and handles startup, health checks, and cleanup):
- Ceph (RGW) with AWS SDK v2
- ClickHouse with clickhouse-go
- Forgejo with SQLite
- FRR routing suite with vtysh
- K3s with client-go
- Kafka with Sarama
- Memcache with gomemcache
- MinIO (S3-compatible)
- MongoDB with mongo-driver
- MySQL / MariaDB / Percona Server
- NetBox with PostgreSQL + Redis
- Nginx
- OpenSearch with opensearch-go
- Paperless-ngx with PostgreSQL + Valkey
- PostgreSQL with pgx
- Prometheus with prometheus/client_golang
- RabbitMQ (AMQP + Management API)
- Redis with go-redis
- ScyllaDB with gocql
- Vault
- Libvirtd (KVM/QEMU)
Many packages include testable examples on pkg.go.dev.
## Usage
### Quick start — 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)
}
}
```
### Multi-container group
```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)
}
```
### Wait strategies
```go
if err := wait.Wait(ctx, c, wait.ForHTTPGet(8080,
wait.WithPath("/health"),
wait.WithResponseStatuses(200),
)); err != nil {
panic(err)
}
```
Other strategies: `ForLog`, `ForCommand`, `ForTCPConnection`. Combine with `ForAll` / `ForAny` / `ForAtLeast`.
### `*testing.T` binding
```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; registers t.Cleanup
}
```
### Lifecycle hooks
```go
docker.HookTypeBeforeRun // before container starts
docker.HookTypeAfterRun // after container starts
docker.HookTypeBeforeClose // before container stops
docker.HookTypeAfterClose // after container stops
```
### Exec and lifecycle commands
```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)
```
### Copying files into/out of containers
Use `WithFiles` with `FileFromBytes` for small content or an `io.Reader` + `Size` for large files. Read files back with `docker.CopyFromContainer`.
### Image prefix / proxy
```sh
export IMAGE_PREFIX=registry-mirror.example.com
```
## Modules & releases
Multi-module workspace with a single version number, tagged separately (e.g., core `v1.6.0`, application `applications/redis/v1.6.0`). Release order: core first, then applications. Use the Makefile to tag.
## License
Apache License, Version 2.0
Comments
0 Rating appears after 10 ratings
Sign in to join the discussion.