Documentation
¶
Overview ¶
Example (Container) ¶
This example demonstrates using the low-level Container API: creating a container from a custom image, configuring environment variables and port bindings, waiting for a log line, and making gRPC calls.
package main
import (
"context"
"fmt"
"time"
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"github.com/teran/echo-grpc-server/presenter/proto"
docker "github.com/teran/go-docker-testsuite"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
defer cancel()
c, err := docker.NewContainer(
"echo-server",
"ghcr.io/teran/echo-grpc-server:latest",
nil,
docker.NewEnvironment().
StringVar("ADDR", ":5555").
LogLevelVar("LOG_LEVEL", logrus.TraceLevel),
docker.NewPortBindings().
PortDNAT(docker.ProtoTCP, 5555),
)
if err != nil {
fmt.Printf("error creating container: %v\n", err)
return
}
defer func() { _ = c.Close(ctx) }()
if err := c.Run(ctx); err != nil {
fmt.Printf("error running container: %v\n", err)
return
}
if err := c.AwaitOutput(ctx, docker.NewSubstringMatcher("running GRPC echo server")); err != nil {
fmt.Printf("error waiting for server: %v\n", err)
return
}
fmt.Println("server is ready")
hp, err := c.URL(docker.ProtoTCP, 5555)
if err != nil {
fmt.Printf("error getting URL: %v\n", err)
return
}
conn, err := grpc.NewClient(hp.String(), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
fmt.Printf("error dialing: %v\n", err)
return
}
defer func() { _ = conn.Close() }()
cli := proto.NewEchoServiceClient(conn)
resp, err := cli.Echo(ctx, &proto.EchoRequest{Message: "Hello!"})
if err != nil {
fmt.Printf("error calling Echo: %v\n", err)
return
}
fmt.Printf("echo response: %s\n", resp.GetMessage())
}
Output:
Example (Group) ¶
This example demonstrates the Group API: running two containers on the same internal Docker network so they can reach each other by container name.
package main
import (
"context"
"fmt"
"time"
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"github.com/teran/echo-grpc-server/presenter/proto"
docker "github.com/teran/go-docker-testsuite"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
awaitRunFn := func(ctx context.Context, ht docker.HookType, c docker.Container) error {
if ht == docker.HookTypeAfterRun {
return c.AwaitOutput(ctx, docker.NewSubstringMatcher("running GRPC echo server"))
}
return nil
}
svr, err := docker.NewContainer(
"my-server",
"ghcr.io/teran/echo-grpc-server:latest",
nil,
docker.NewEnvironment().
StringVar("ADDR", ":5555").
LogLevelVar("LOG_LEVEL", logrus.TraceLevel),
docker.NewPortBindings().
PortDNAT(docker.ProtoTCP, 5555),
)
if err != nil {
fmt.Printf("error creating server container: %v\n", err)
return
}
client, err := docker.NewContainer(
"my-client",
"ghcr.io/teran/echo-grpc-server:latest",
nil,
docker.NewEnvironment().
StringVar("ADDR", ":5555").
LogLevelVar("LOG_LEVEL", logrus.TraceLevel),
docker.NewPortBindings().
PortDNAT(docker.ProtoTCP, 5555),
)
if err != nil {
fmt.Printf("error creating client container: %v\n", err)
return
}
g, err := docker.NewGroup("my-group",
docker.NewApplication(svr, awaitRunFn),
docker.NewApplication(client, awaitRunFn),
)
if err != nil {
fmt.Printf("error creating group: %v\n", err)
return
}
defer func() { _ = g.Close(ctx) }()
if err := g.Run(ctx); err != nil {
fmt.Printf("error running group: %v\n", err)
return
}
fmt.Println("group started")
// Connect to client and call server by its DNS name.
hp, err := client.URL(docker.ProtoTCP, 5555)
if err != nil {
fmt.Printf("error getting client URL: %v\n", err)
return
}
conn, err := grpc.NewClient(hp.String(), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
fmt.Printf("error dialing: %v\n", err)
return
}
defer func() { _ = conn.Close() }()
cli := proto.NewRemoteEchoServiceClient(conn)
resp, err := cli.RemoteEcho(ctx, &proto.RemoteEchoRequest{
Remote: "my-server:5555",
Message: "Hello across containers!",
})
if err != nil {
fmt.Printf("error calling RemoteEcho: %v\n", err)
return
}
fmt.Printf("remote echo response: %s\n", resp.GetMessage())
}
Output:
Index ¶
- Variables
- func CopyFromContainer(ctx context.Context, c Container, srcPath string) (io.ReadCloser, error)
- func DockerIP() (string, error)
- func NewHostConfig(pb *PortBindings, opts ...ContainerOption) (*dockerContainer.HostConfig, error)
- func OneToOneRandomPort(proto Protocol, srcPort uint16) (string, uint16, []string, error)
- func ParseRAMSize(s string) (int64, error)
- func RandomPort(proto Protocol, dstPort uint16) (string, uint16, []string, error)
- type Application
- type Binding
- type Container
- func NewContainer(name, image string, cmd []string, environment Environment, ports *PortBindings, ...) (Container, error)
- func NewContainerWithClient(cli *client.Client, name, image string, cmd []string, env Environment, ...) (Container, error)
- func NewContainerWithLifecycle(name, image string, cmd []string, environment Environment, ports *PortBindings, ...) (Container, error)
- type ContainerFileCopier
- type ContainerID
- type ContainerInfo
- type ContainerOption
- func WithBinds(binds ...string) ContainerOption
- func WithCPUs(count float64) ContainerOption
- func WithCapAdd(caps ...string) ContainerOption
- func WithCapDrop(caps ...string) ContainerOption
- func WithCpusetCpus(cpus string) ContainerOption
- func WithDevices(devices ...string) ContainerOption
- func WithHostNetwork() ContainerOption
- func WithMemoryLimit(bytes int64) ContainerOption
- func WithMemoryReservation(bytes int64) ContainerOption
- func WithMemorySwap(bytes int64) ContainerOption
- func WithNetworkMode(mode NetworkMode) ContainerOption
- func WithPidsLimit(limit int64) ContainerOption
- func WithPrivileged() ContainerOption
- func WithSecurityOpt(opts ...string) ContainerOption
- func WithTmpfs(m map[string]string) ContainerOption
- func WithUlimit(name string, soft, hard int64) ContainerOption
- type Environment
- func (e Environment) BoolVar(name string, value bool) Environment
- func (e Environment) Eval(c ContainerInfo) (es []string)
- func (e Environment) Int8Var(name string, value int8) Environment
- func (e Environment) Int16Var(name string, value int16) Environment
- func (e Environment) Int32Var(name string, value int32) Environment
- func (e Environment) Int64Var(name string, value int64) Environment
- func (e Environment) IntVar(name string, value int) Environment
- func (e Environment) LogLevelVar(name string, l log.Level) Environment
- func (e Environment) StringVar(name, value string) Environment
- func (e Environment) Uint8Var(name string, value uint8) Environment
- func (e Environment) Uint16Var(name string, value uint16) Environment
- func (e Environment) Uint32Var(name string, value uint32) Environment
- func (e Environment) Uint64Var(name string, value uint64) Environment
- func (e Environment) UintVar(name string, value uint) Environment
- func (e Environment) Var(name string, vfn func(c ContainerInfo) string) Environment
- type ExecResult
- type File
- type Group
- type Hook
- type HookType
- type HostConfigSpec
- type HostPort
- type LifecycleOption
- type Matcher
- type NetworkID
- type NetworkMode
- type PortAllocator
- type PortBindings
- type Protocol
- type TestContainer
- func (tc *TestContainer) AwaitOutput(ctx context.Context, m Matcher) error
- func (tc *TestContainer) Close(ctx context.Context) error
- func (tc *TestContainer) CopyFromContainer(ctx context.Context, srcPath string) (io.ReadCloser, error)
- func (tc *TestContainer) Exec(ctx context.Context, cmd []string) (*ExecResult, error)
- func (tc *TestContainer) GetOutput(ctx context.Context, ms ...Matcher) ([]string, error)
- func (tc *TestContainer) ID() ContainerID
- func (tc *TestContainer) Name() string
- func (tc *TestContainer) NetworkAttach(networkID string) error
- func (tc *TestContainer) Ping(ctx context.Context) error
- func (tc *TestContainer) Run(ctx context.Context) error
- func (tc *TestContainer) RunT(ctx context.Context)
- func (tc *TestContainer) URL(proto Protocol, port uint16) (*HostPort, error)
- type TestGroup
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrPortNotMapped = errors.New("port not mapped") ErrDockerHostIPIsNotResolved = errors.New("docker host IP address cannot be resolved") )
Functions ¶
func CopyFromContainer ¶ added in v1.5.0
CopyFromContainer copies the file or directory at srcPath out of the running container c, returning a tar stream that the caller must close and unpack (e.g. with archive/tar) to obtain the content. It works on any Container that supports the operation (the concrete container and TestContainer do); a Container without this capability returns an error.
Example ¶
This example demonstrates copying a file out of a running container with docker.CopyFromContainer: the returned reader is a tar stream, which is unpacked to read the file's content back out for verification.
package main
import (
"archive/tar"
"context"
"fmt"
"io"
"time"
docker "github.com/teran/go-docker-testsuite"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
defer cancel()
c, err := docker.NewContainer(
"copy-example",
"busybox:latest",
[]string{"sleep", "300"},
nil,
nil,
)
if err != nil {
fmt.Printf("error creating container: %v\n", err)
return
}
defer func() { _ = c.Close(ctx) }()
if err := c.Run(ctx); err != nil {
fmt.Printf("error running container: %v\n", err)
return
}
if _, err := c.Exec(ctx, []string{"sh", "-c", "echo 'secrets' > /tmp/report.txt"}); err != nil {
fmt.Printf("error writing file: %v\n", err)
return
}
rc, err := docker.CopyFromContainer(ctx, c, "/tmp/report.txt")
if err != nil {
fmt.Printf("error copying from container: %v\n", err)
return
}
defer func() { _ = rc.Close() }()
tr := tar.NewReader(rc)
if _, err := tr.Next(); err != nil {
fmt.Printf("error reading tar header: %v\n", err)
return
}
content, err := io.ReadAll(tr)
if err != nil {
fmt.Printf("error reading content: %v\n", err)
return
}
fmt.Printf("content: %s", content)
}
Output:
func NewHostConfig ¶
func NewHostConfig(pb *PortBindings, opts ...ContainerOption) (*dockerContainer.HostConfig, error)
NewHostConfig creates new HostConfig instance
func OneToOneRandomPort ¶ added in v1.1.0
func ParseRAMSize ¶ added in v1.5.0
ParseRAMSize parses a human-readable size string (e.g. "512m", "1g", "1.5g") into bytes, wrapping github.com/docker/go-units.RAMInBytes via pkg/errors.
Types ¶
type Application ¶
type Application struct {
// contains filtered or unexported fields
}
func NewApplication ¶
func NewApplication(c Container, hooks ...Hook) *Application
type Container ¶
type Container interface {
AwaitOutput(ctx context.Context, m Matcher) error
Close(ctx context.Context) error
Exec(ctx context.Context, cmd []string) (*ExecResult, error)
GetOutput(ctx context.Context, m ...Matcher) ([]string, error)
ID() ContainerID
Name() string
NetworkAttach(networkID string) error
Ping(ctx context.Context) error
Run(ctx context.Context) error
URL(proto Protocol, port uint16) (*HostPort, error)
}
Container exposes interface to control the container runtime
func NewContainer ¶
func NewContainer(name, image string, cmd []string, environment Environment, ports *PortBindings, opts ...ContainerOption) (Container, error)
New creates new container instance from remote docker image
Example (ResourceLimits) ¶
This example demonstrates capping the resources of a test container so a runaway test cannot exhaust the host or CI runner: memory, CPU and process limits are set via the With* ContainerOptions.
package main
import (
"context"
"fmt"
"time"
docker "github.com/teran/go-docker-testsuite"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
defer cancel()
c, err := docker.NewContainer(
"limits-example",
"busybox:latest",
[]string{"sleep", "300"},
nil,
nil,
docker.WithMemoryLimit(128*1024*1024), // 128 MiB
docker.WithCPUs(0.5), // half a vCPU
docker.WithPidsLimit(256),
)
if err != nil {
fmt.Printf("error creating container: %v\n", err)
return
}
defer func() { _ = c.Close(ctx) }()
if err := c.Run(ctx); err != nil {
fmt.Printf("error running container: %v\n", err)
return
}
fmt.Println("container started with resource limits")
}
Output:
func NewContainerWithClient ¶
func NewContainerWithClient(cli *client.Client, name, image string, cmd []string, env Environment, ports *PortBindings, opts ...ContainerOption) (Container, error)
NewContainerWithClient creates new container from remote docker image and allows to pass custom docker.Client instance
func NewContainerWithLifecycle ¶ added in v1.5.0
func NewContainerWithLifecycle(name, image string, cmd []string, environment Environment, ports *PortBindings, opts ...LifecycleOption) (Container, error)
NewContainerWithLifecycle is NewContainer plus lifecycle options. Existing NewContainer is unchanged.
Example ¶
This example demonstrates NewContainerWithLifecycle: running a startup command right after the container starts and an after-ready command once a readiness log line is observed.
package main
import (
"context"
"fmt"
"time"
docker "github.com/teran/go-docker-testsuite"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
defer cancel()
c, err := docker.NewContainerWithLifecycle(
"lifecycle-example",
"busybox:latest",
[]string{"sh", "-c", "echo READY; sleep 300"},
nil,
nil,
docker.WithStartupCommand("sh", "-c", "echo startup > /tmp/startup.txt"),
docker.WithAfterReadyCommand(
docker.NewSubstringMatcher("READY"),
"sh", "-c", "echo seeded > /tmp/seeded.txt",
),
)
if err != nil {
fmt.Printf("error creating container: %v\n", err)
return
}
defer func() { _ = c.Close(ctx) }()
if err := c.Run(ctx); err != nil {
fmt.Printf("error running container: %v\n", err)
return
}
startup, err := c.Exec(ctx, []string{"cat", "/tmp/startup.txt"})
if err != nil {
fmt.Printf("error reading startup marker: %v\n", err)
return
}
seeded, err := c.Exec(ctx, []string{"cat", "/tmp/seeded.txt"})
if err != nil {
fmt.Printf("error reading seeded marker: %v\n", err)
return
}
fmt.Printf("startup: %s", startup.Stdout)
fmt.Printf("seeded: %s", seeded.Stdout)
}
Output:
Example (WithFiles) ¶
This example demonstrates seeding a small file into a container before it starts with WithFiles / FileFromBytes: the file is copied into the container filesystem during Run, before the entrypoint runs.
package main
import (
"context"
"fmt"
"time"
docker "github.com/teran/go-docker-testsuite"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
defer cancel()
c, err := docker.NewContainerWithLifecycle(
"withfiles-example",
"busybox:latest",
[]string{"sh", "-c", "cat /etc/app.conf; sleep 300"},
nil,
nil,
docker.WithFiles(
docker.FileFromBytes("/etc/app.conf", []byte("key=value\n"), 0600, 0, 0),
),
)
if err != nil {
fmt.Printf("error creating container: %v\n", err)
return
}
defer func() { _ = c.Close(ctx) }()
if err := c.Run(ctx); err != nil {
fmt.Printf("error running container: %v\n", err)
return
}
res, err := c.Exec(ctx, []string{"cat", "/etc/app.conf"})
if err != nil {
fmt.Printf("error reading file: %v\n", err)
return
}
fmt.Printf("content: %s", res.Stdout)
}
Output:
type ContainerFileCopier ¶ added in v1.5.0
type ContainerFileCopier interface {
CopyFromContainer(ctx context.Context, srcPath string) (io.ReadCloser, error)
}
ContainerFileCopier is implemented by containers that can copy a file or directory out of a running container as a tar stream. It is an optional capability (not part of the Container interface): the concrete container and TestContainer satisfy it, and docker.CopyFromContainer resolves it for callers holding only the Container interface.
type ContainerID ¶
type ContainerID = string
type ContainerInfo ¶ added in v1.1.0
type ContainerOption ¶ added in v1.3.0
type ContainerOption func(*dockerContainer.HostConfig)
ContainerOption modifies the docker HostConfig before container creation.
func WithBinds ¶ added in v1.3.0
func WithBinds(binds ...string) ContainerOption
WithBinds adds volume bind mounts (host:container[:mode]).
func WithCPUs ¶ added in v1.5.0
func WithCPUs(count float64) ContainerOption
WithCPUs sets the CPU limit as a fractional vCPU count via HostConfig.NanoCPUs (e.g. 0.5 → 500000000 nanos). Non-positive values are ignored (no-op).
func WithCapAdd ¶ added in v1.5.0
func WithCapAdd(caps ...string) ContainerOption
WithCapAdd grants additional Linux capabilities (e.g. "NET_ADMIN", "SYS_NICE") beyond the Docker default set. Values are capability names without the "CAP_" prefix, as accepted by Docker.
func WithCapDrop ¶ added in v1.5.0
func WithCapDrop(caps ...string) ContainerOption
WithCapDrop removes Linux capabilities from the container's default set for least-privilege hardening. Values are capability names without the "CAP_" prefix. Passing "ALL" drops every capability; combine with WithCapAdd to whitelist only what is needed.
func WithCpusetCpus ¶ added in v1.5.0
func WithCpusetCpus(cpus string) ContainerOption
WithCpusetCpus pins the container to specific host CPUs via HostConfig.CpusetCpus (e.g. "0-2,7").
func WithDevices ¶ added in v1.5.0
func WithDevices(devices ...string) ContainerOption
WithDevices maps host devices into the container (e.g. "/dev/kvm", "/dev/net/tun"). Each entry is "hostPath" or "hostPath:containerPath[:mode]". This is required for workloads that need direct access to host devices, such as KVM/QEMU virtualization (libvirtd) or TUN/TAP networking.
func WithHostNetwork ¶ added in v1.5.0
func WithHostNetwork() ContainerOption
WithHostNetwork runs the container on the host network namespace (HostConfig.NetworkMode "host"): 127.0.0.1 inside the container is the host's loopback, and Docker ignores port bindings.
func WithMemoryLimit ¶ added in v1.5.0
func WithMemoryLimit(bytes int64) ContainerOption
WithMemoryLimit caps the container's memory usage (bytes) via HostConfig.Memory.
func WithMemoryReservation ¶ added in v1.5.0
func WithMemoryReservation(bytes int64) ContainerOption
WithMemoryReservation sets a soft memory reservation (bytes) via HostConfig.MemoryReservation.
func WithMemorySwap ¶ added in v1.5.0
func WithMemorySwap(bytes int64) ContainerOption
WithMemorySwap sets the swap limit (bytes) via HostConfig.MemorySwap. -1 disables swap; a value equal to Memory effectively disables swap; typically callers pass 2*Memory to allow double the memory in swap.
func WithNetworkMode ¶ added in v1.5.0
func WithNetworkMode(mode NetworkMode) ContainerOption
WithNetworkMode sets the container's network mode (HostConfig.NetworkMode). Note that under NetworkModeHost (and NetworkModeNone) Docker ignores port bindings, so any configured PortDNAT mappings are effectively dropped.
func WithPidsLimit ¶ added in v1.5.0
func WithPidsLimit(limit int64) ContainerOption
WithPidsLimit caps the number of processes inside the container via HostConfig.PidsLimit.
func WithPrivileged ¶ added in v1.3.0
func WithPrivileged() ContainerOption
WithPrivileged grants the container elevated privileges.
func WithSecurityOpt ¶ added in v1.5.0
func WithSecurityOpt(opts ...string) ContainerOption
WithSecurityOpt sets Docker security options (e.g. "seccomp=unconfined", "apparmor=unconfined"). Needed by workloads such as QEMU/libvirtd whose syscalls may be blocked by Docker's default seccomp profile when running in a least-privilege (non-privileged) configuration.
func WithTmpfs ¶ added in v1.3.0
func WithTmpfs(m map[string]string) ContainerOption
WithTmpfs mounts tmpfs filesystems at the given paths.
func WithUlimit ¶ added in v1.4.0
func WithUlimit(name string, soft, hard int64) ContainerOption
WithUlimit sets an ulimit (e.g. nofile) on the container's HostConfig. Some images (e.g. Ceph) start much slower under Docker's default limits, so callers can raise the soft/hard limit.
type Environment ¶
type Environment map[string]func(c ContainerInfo) string
Environment represents the container environment passed into runtime
func NewEnvironment ¶
func NewEnvironment() Environment
NewEnvironment creates new Environment instance
func (Environment) BoolVar ¶
func (e Environment) BoolVar(name string, value bool) Environment
BoolVar sets bool var to the environment
func (Environment) Eval ¶ added in v1.1.0
func (e Environment) Eval(c ContainerInfo) (es []string)
func (Environment) Int8Var ¶
func (e Environment) Int8Var(name string, value int8) Environment
Int8Var sets int8 var to the environment
func (Environment) Int16Var ¶
func (e Environment) Int16Var(name string, value int16) Environment
Int16Var sets int16 var to the environment
func (Environment) Int32Var ¶
func (e Environment) Int32Var(name string, value int32) Environment
Int32Var sets int32 var to the environment
func (Environment) Int64Var ¶
func (e Environment) Int64Var(name string, value int64) Environment
Int64Var sets int64 var to the environment
func (Environment) IntVar ¶
func (e Environment) IntVar(name string, value int) Environment
IntVar sets int var to the environment
func (Environment) LogLevelVar ¶
func (e Environment) LogLevelVar(name string, l log.Level) Environment
LogLevelVar sets logrus.Level var to the environment
func (Environment) StringVar ¶
func (e Environment) StringVar(name, value string) Environment
StringVar sets string var to the environment
func (Environment) Uint8Var ¶
func (e Environment) Uint8Var(name string, value uint8) Environment
Uint8Var sets uint8 var to the environment
func (Environment) Uint16Var ¶
func (e Environment) Uint16Var(name string, value uint16) Environment
Uint16Var sets uint16 var to the environment
func (Environment) Uint32Var ¶
func (e Environment) Uint32Var(name string, value uint32) Environment
Uint32Var sets uint32 var to the environment
func (Environment) Uint64Var ¶
func (e Environment) Uint64Var(name string, value uint64) Environment
Uint64Var sets uint64 var to the environment
func (Environment) UintVar ¶
func (e Environment) UintVar(name string, value uint) Environment
UintVar sets uint var to the environment
func (Environment) Var ¶ added in v1.1.0
func (e Environment) Var(name string, vfn func(c ContainerInfo) string) Environment
Var allows to set custom function to generate environment variable
type ExecResult ¶ added in v1.5.0
ExecResult carries the captured output and exit status of an Exec call.
func (*ExecResult) Combined ¶ added in v1.5.0
func (r *ExecResult) Combined() []byte
Combined returns Stdout followed by Stderr concatenated.
func (*ExecResult) Error ¶ added in v1.5.0
func (r *ExecResult) Error() error
Error returns a non-nil error if the command exited non-zero (includes exit code + stderr for diagnostics); nil when ExitCode == 0.
type File ¶ added in v1.5.0
type File struct {
Content io.Reader // streamed file content; Size bytes must be available
Size int64 // exact byte length of Content (required)
Mode os.FileMode // permission bits; 0 defaults to 0644
Destination string // absolute path inside the container, e.g. "/etc/app.conf"
Uid int // numeric owner uid; 0 (default) = root
Gid int // numeric owner gid; 0 (default) = root
}
File describes a single file to copy into the container filesystem before the container starts. Content is streamed from an io.Reader and written into the tar verbatim, so files larger than available RAM can be copied without buffering them in memory. Size MUST equal the exact number of bytes Content will yield: it is written into the tar header and used to stream exactly Size bytes (Content is not buffered).
Mode is the Unix permission bits (0 defaults to 0644); Destination is the absolute path inside the container (parent directories are created automatically). Uid and Gid set the numeric owner of the file; both default to 0 (root:root) when omitted. Docker honours the numeric ids and only the file itself is chowned — auto-created parent directories stay root:root (0755).
func FileFromBytes ¶ added in v1.5.0
FileFromBytes builds a File from an in-memory byte slice. It wraps data in a bytes.Reader and sets Size to len(data). Use this for small configuration and seed content; use File directly with an io.Reader + Size for large files.
type Group ¶
func NewGroupWithClient ¶
type HostConfigSpec ¶
HostConfigSpec is just a wrapper structure to pass host configuration to the container
type LifecycleOption ¶ added in v1.5.0
type LifecycleOption func(*container)
LifecycleOption configures behavior that runs inside the container during Run(), in addition to HostConfig-based ContainerOptions. It does not modify the Docker HostConfig.
func WithAfterReadyCommand ¶ added in v1.5.0
func WithAfterReadyCommand(ready Matcher, cmd ...string) LifecycleOption
WithAfterReadyCommand runs cmd inside the container once the readiness matcher is satisfied by the container output. When ready is nil the command runs immediately after the startup command (or right after start if none).
func WithFiles ¶ added in v1.5.0
func WithFiles(files ...File) LifecycleOption
WithFiles copies the given files into the container filesystem during Run(), immediately after the container is created (and attached to the network) and before it starts — and therefore before WithStartupCommand runs.
Files are packed into a single tar and pushed via the Docker SDK CopyToContainer at the container root; parent directories are auto-created. An empty file list is a no-op.
func WithHostConfig ¶ added in v1.5.0
func WithHostConfig(opts ...ContainerOption) LifecycleOption
WithHostConfig adapts ordinary ContainerOption values so they can be supplied alongside lifecycle options. They modify the Docker HostConfig as usual.
func WithStartupCommand ¶ added in v1.5.0
func WithStartupCommand(cmd ...string) LifecycleOption
WithStartupCommand runs cmd inside the container immediately after it starts, failing Run() if the command errors or exits non-zero.
type Matcher ¶
Matcher allows to create any kind of matcher for container outputs
func NewExactMatcher ¶
NewExactMatcher represents exact matcher i.e. the output should be exactly matched (except space chars around the word)
func NewRegexpMatcher ¶
NewRegexpMatcher returns a matcher that succeeds when the line matches the compiled regular expression.
func NewSubstringMatcher ¶
NewSubstringMatcher represents partial matcher
type NetworkMode ¶ added in v1.5.0
type NetworkMode string
NetworkMode enumerates Docker container network modes (roadmap #19).
const ( // NetworkModeBridge is the default: the container sits on the Docker // bridge with explicit port mappings (HostConfig.NetworkMode "default"). NetworkModeBridge NetworkMode = "bridge" // NetworkModeHost shares the host network namespace: 127.0.0.1 inside the // container IS the host's loopback, and no port mappings apply. Under this // mode Docker ignores port bindings. NetworkModeHost NetworkMode = "host" // NetworkModeNone disables networking entirely. Under this mode Docker // ignores port bindings. NetworkModeNone NetworkMode = "none" )
type PortAllocator ¶ added in v1.1.0
type PortBindings ¶
type PortBindings struct {
// contains filtered or unexported fields
}
PortBindings is a full mapping of internal & external docker container ports
func NewDirectPortBinding ¶ added in v1.1.0
func NewDirectPortBinding() *PortBindings
func NewPortBindings ¶
func NewPortBindings() *PortBindings
NewPortBindings creates new PortBindings instance
func NewPortBindingsWithPortAllocator ¶ added in v1.1.0
func NewPortBindingsWithPortAllocator(allocator PortAllocator) *PortBindings
NewPortBindingsWithTCPPortAllocator creates new PortBinding instance and allows to pass custom port allocation function
func (*PortBindings) PortDNAT ¶
func (pb *PortBindings) PortDNAT(proto Protocol, port uint16) *PortBindings
PortDNAT adds new port to be exposed from the container
type TestContainer ¶ added in v1.5.0
type TestContainer struct {
// contains filtered or unexported fields
}
TestContainer binds a Container to a *testing.T so its lifecycle is tied to the test. It implements the full Container interface by delegating to the wrapped Container, while additionally:
- registering a t.Cleanup handler on the first Run so the container is always stopped and removed when the test finishes (including on success, t.Fatal, panic and t.Skip), and
- making Close idempotent, so overlapping cleanups (the t.Cleanup handler and an explicit wrapper Close) do not double-remove the container.
Each binding owns its own lifecycle, so TestContainer is safe to use with t.Parallel(): cleanups are registered against the correct per-test T and run in LIFO order within that test's context.
func BindToT ¶ added in v1.5.0
func BindToT(t *testing.T, c Container) *TestContainer
BindToT wraps an existing Container with a *testing.T, tying its lifecycle (run cleanup + idempotent close) to the test. Use this when the container was created with the base NewContainer/NewContainerWithLifecycle constructors but should be cleaned up automatically by the test.
func NewContainerWithLifecycleT ¶ added in v1.5.0
func NewContainerWithLifecycleT(t *testing.T, name, image string, cmd []string, env Environment, ports *PortBindings, opts ...LifecycleOption) (*TestContainer, error)
NewContainerWithLifecycleT is NewContainerWithLifecycle bound to a *testing.T. It behaves like NewContainerWithLifecycle but returns a TestContainer whose lifecycle is tied to the test.
func NewContainerWithT ¶ added in v1.5.0
func NewContainerWithT(t *testing.T, name, image string, cmd []string, env Environment, ports *PortBindings, opts ...ContainerOption) (*TestContainer, error)
NewContainerWithT is NewContainer bound to a *testing.T. It creates a container exactly like NewContainer but returns a TestContainer whose lifecycle is tied to the test.
func (*TestContainer) AwaitOutput ¶ added in v1.5.0
func (tc *TestContainer) AwaitOutput(ctx context.Context, m Matcher) error
AwaitOutput delegates to the wrapped container.
func (*TestContainer) Close ¶ added in v1.5.0
func (tc *TestContainer) Close(ctx context.Context) error
Close stops and removes the container. It is idempotent: only the first call performs the work; subsequent calls return nil.
func (*TestContainer) CopyFromContainer ¶ added in v1.5.0
func (tc *TestContainer) CopyFromContainer(ctx context.Context, srcPath string) (io.ReadCloser, error)
CopyFromContainer delegates to the wrapped container, returning a tar stream of the file or directory at srcPath. Works even when the wrapped Container holds the base interface, by resolving the optional capability.
func (*TestContainer) Exec ¶ added in v1.5.0
func (tc *TestContainer) Exec(ctx context.Context, cmd []string) (*ExecResult, error)
Exec delegates to the wrapped container, logging the outcome at a low-noise level.
func (*TestContainer) ID ¶ added in v1.5.0
func (tc *TestContainer) ID() ContainerID
ID returns the Docker container ID (empty until Run).
func (*TestContainer) Name ¶ added in v1.5.0
func (tc *TestContainer) Name() string
Name returns the container name.
func (*TestContainer) NetworkAttach ¶ added in v1.5.0
func (tc *TestContainer) NetworkAttach(networkID string) error
NetworkAttach delegates to the wrapped container.
func (*TestContainer) Ping ¶ added in v1.5.0
func (tc *TestContainer) Ping(ctx context.Context) error
Ping delegates to the wrapped container, logging the outcome at a low-noise level.
func (*TestContainer) Run ¶ added in v1.5.0
func (tc *TestContainer) Run(ctx context.Context) error
Run starts the container and registers the test cleanup on the first call. On error it returns the error (logging it via t.Logf) rather than failing the test, so it remains compatible with applications and groups.
func (*TestContainer) RunT ¶ added in v1.5.0
func (tc *TestContainer) RunT(ctx context.Context)
RunT starts the container, registers the test cleanup and fails the test immediately (t.Fatal) if the container fails to start.
type TestGroup ¶ added in v1.5.0
type TestGroup struct {
// contains filtered or unexported fields
}
TestGroup binds a Group to a *testing.T so its lifecycle is tied to the test. It delegates Run/Close to the wrapped Group while additionally registering a t.Cleanup handler on the first Run and making Close idempotent.
The group's Close removes the member containers and then the internal network. This is protected against double-removal both by the idempotent group Close and by the idempotent per-container Close (so a group whose members are individually bound to the test is still safe to clean up from both paths). Like TestContainer, TestGroup is safe to use with t.Parallel().
func BindGroupToT ¶ added in v1.5.0
BindGroupToT wraps an existing Group with a *testing.T, tying its lifecycle (run cleanup + idempotent close) to the test. Use this when the group was created with the base NewGroup constructor but should be cleaned up automatically by the test.
func NewGroupT ¶ added in v1.5.0
NewGroupT is NewGroup bound to a *testing.T. It creates a group exactly like NewGroup but returns a TestGroup whose lifecycle is tied to the test.
func (*TestGroup) Close ¶ added in v1.5.0
Close removes the group's member containers and internal network. It is idempotent: only the first call performs the work; subsequent calls return nil.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
applications
|
|
|
forgejo
module
|
|
|
netbox
module
|
|
|
internal
|
|
|
tools
|
|
|
cmd/split_test_groups
command
split_test_groups discovers every Go module in the repository and emits a CI matrix, one entry per module, so tests can be run in parallel GitHub Actions jobs.
|
split_test_groups discovers every Go module in the repository and emits a CI matrix, one entry per module, so tests can be run in parallel GitHub Actions jobs. |
|
Package wait provides composable readiness wait-strategies for Docker containers.
|
Package wait provides composable readiness wait-strategies for Docker containers. |