Sobre el proyecto

# go-docker-testsuite Una biblioteca Go para ejecutar dependencias de terceros en contenedores Docker para pruebas de integración. Permite levantar cualquier imagen Docker (bases de datos, colas, cachés o almacenamiento de objetos) y conectarse a ellas desde tus pruebas Go. ## Características - **Container** — envoltorio de bajo nivel para crear, ejecutar, esperar salida y limpiar cualquier imagen Docker - **Group** — ejecuta múltiples contenedores en una red Docker aislada con conectividad a nivel de IP - **Applications** — envoltorios listos para servicios populares (MySQL, PostgreSQL, Redis, Kafka, etc.) - **Hooks** — callbacks del ciclo de vida (BeforeRun, AfterRun, BeforeClose, AfterClose) por contenedor - **Exec** — ejecuta comandos dentro de un contenedor en ejecución y captura stdout, stderr y código de salida - **Comandos de ciclo de vida** — ejecuta comandos de inicio / post-listos mediante exec - **Copiar archivos a contenedores** — siembra archivos antes de iniciar con `WithFiles` - **Copiar archivos desde contenedores** — lee archivos de un contenedor en ejecución como flujo tar - **Límites de recursos** — limita CPU/memoria/pids para proteger el host y CI - **Matchers** — espera registros de contenedor con matchers de subcadena, exactos o regexp - **Estrategias de espera** — sondas de preparación componibles (ForLog, ForHTTPGet, ForCommand, ForTCPConnection) - **Constructor de entorno** — DSL fluido para variables de entorno tipadas - **Enlaces de puertos** — mapeo de puertos DNAT con asignación aleatoria o uno a uno - **Modo de red** — soporte de red host o personalizada - **IMAGE_PREFIX** — enruta imágenes a través de un proxy/mirror - **Enlace `*testing.T`** — limpieza automática y registro con `t.Parallel()` seguro ## Requisitos - Go 1.26+ - Un demonio Docker en ejecución (funciona con hosts remotos mediante `DOCKER_HOST`) ## Instalación Espacio de trabajo multimódulo: la raíz es el módulo central, y cada aplicación bajo `applications/<nombre>` es su propio módulo Go. Extrae solo lo que necesites: ```sh go get github.com/teran/go-docker-testsuite # Envoltorio de aplicación específico: go get github.com/teran/go-docker-testsuite/applications/redis go get github.com/teran/go-docker-testsuite/applications/postgres ``` ## Aplicaciones Envoltorios listos (cada uno devuelve una interfaz de cliente tipada y maneja inicio, verificaciones de salud y limpieza): - Ceph (RGW) con AWS SDK v2 - ClickHouse con clickhouse-go - Forgejo con SQLite - Suite de enrutamiento FRR con vtysh - K3s con client-go - Kafka con Sarama - Memcache con gomemcache - MinIO (compatible con S3) - MongoDB con mongo-driver - MySQL / MariaDB / Percona Server - NetBox con PostgreSQL + Redis - Nginx - OpenSearch con opensearch-go - Paperless-ngx con PostgreSQL + Valkey - PostgreSQL con pgx - Prometheus con prometheus/client_golang - RabbitMQ (AMQP + API de gestión) - Redis con go-redis - ScyllaDB con gocql - Vault - Libvirtd (KVM/QEMU) Muchos paquetes incluyen ejemplos comprobables en pkg.go.dev. ## Uso ### Inicio rápido — 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) } } ``` ### Grupo de múltiples contenedores ```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) } ``` ### Estrategias de espera ```go if err := wait.Wait(ctx, c, wait.ForHTTPGet(8080, wait.WithPath("/health"), wait.WithResponseStatuses(200), )); err != nil { panic(err) } ``` Otras estrategias: `ForLog`, `ForCommand`, `ForTCPConnection`. Combínalas con `ForAll` / `ForAny` / `ForAtLeast`. ### Enlace `*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; registra t.Cleanup } ``` ### Hooks del ciclo de vida ```go docker.HookTypeBeforeRun // antes de que el contenedor inicie docker.HookTypeAfterRun // después de que el contenedor inicie docker.HookTypeBeforeClose // antes de que el contenedor se detenga docker.HookTypeAfterClose // después de que el contenedor se detenga ``` ### Exec y comandos de ciclo de vida ```go res, err := c.Exec(ctx, []string{"echo", "hello"}) if err != nil { panic(err) } if err := res.Error(); err != nil { panic(err) } fmt.Printf("código de salida: %d\n", res.ExitCode) fmt.Printf("stdout: %s", res.Stdout) ``` ### Copiar archivos hacia/desde contenedores Usa `WithFiles` con `FileFromBytes` para contenido pequeño o un `io.Reader` + `Size` para archivos grandes. Lee archivos de vuelta con `docker.CopyFromContainer`. ### Prefijo de imagen / proxy ```sh export IMAGE_PREFIX=registry-mirror.example.com ``` ## Módulos y versiones Espacio de trabajo multimódulo con un solo número de versión, etiquetado por separado (por ejemplo, núcleo `v1.6.0`, aplicación `applications/redis/v1.6.0`). Orden de lanzamiento: primero el núcleo, luego las aplicaciones. Usa el Makefile para etiquetar. ## Licencia Apache License, Versión 2.0