Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ formatters:
- standard
- default
- prefix(github.com/testcontainers)

linters:
enable:
- errorlint
Expand Down Expand Up @@ -115,4 +116,5 @@ output:
path: stdout
run:
relative-path-mode: gitroot

version: "2"
8 changes: 5 additions & 3 deletions cleanup.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"fmt"
"reflect"
"time"

"github.com/moby/moby/client"
)

// TerminateOptions is a type that holds the options for terminating a container.
Expand Down Expand Up @@ -48,15 +50,15 @@ func (o *TerminateOptions) Cleanup() error {
if len(o.volumes) == 0 {
return nil
}
client, err := NewDockerClientWithOpts(o.ctx)
apiClient, err := NewDockerClientWithOpts(o.ctx)
if err != nil {
return fmt.Errorf("docker client: %w", err)
}
defer client.Close()
defer apiClient.Close()
// Best effort to remove all volumes.
var errs []error
for _, volume := range o.volumes {
if errRemove := client.VolumeRemove(o.ctx, volume, true); errRemove != nil {
if _, errRemove := apiClient.VolumeRemove(o.ctx, volume, client.VolumeRemoveOptions{Force: true}); errRemove != nil {
errs = append(errs, fmt.Errorf("volume remove %q: %w", volume, errRemove))
}
}
Expand Down
6 changes: 5 additions & 1 deletion commons-test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ $(GOBIN)/gotestsum:
$(GOBIN)/mockery:
$(call go_install,github.com/vektra/mockery/v2@v2.53.4)

$(GOBIN)/gci:
$(call go_install,github.com/daixiang0/gci@v0.13.5)

.PHONY: install
install: $(GOBIN)/golangci-lint $(GOBIN)/gotestsum $(GOBIN)/mockery

Expand All @@ -30,9 +33,10 @@ dependencies-scan:

.PHONY: lint
lint: $(GOBIN)/golangci-lint
golangci-lint run --verbose -c $(ROOT_DIR)/.golangci.yml --fix
golangci-lint run -c $(ROOT_DIR)/.golangci.yml --fix

.PHONY: generate
generate: $(GOBIN)/gci
generate: $(GOBIN)/mockery
go generate ./...

Expand Down
67 changes: 33 additions & 34 deletions container.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ import (
"time"

"github.com/cpuguy83/dockercfg"
"github.com/docker/docker/api/types/build"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/registry"
"github.com/docker/go-connections/nat"
"github.com/google/uuid"
"github.com/moby/go-archive"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/api/types/registry"
"github.com/moby/moby/client"
"github.com/moby/patternmatcher/ignorefile"

tcexec "github.com/testcontainers/testcontainers-go/exec"
Expand All @@ -34,23 +33,23 @@ import (
type DeprecatedContainer interface {
GetHostEndpoint(ctx context.Context, port string) (string, string, error)
GetIPAddress(ctx context.Context) (string, error)
LivenessCheckPorts(ctx context.Context) (nat.PortSet, error)
LivenessCheckPorts(ctx context.Context) (network.PortSet, error)
Terminate(ctx context.Context) error
}

// Container allows getting info about and controlling a single container instance
type Container interface {
GetContainerID() string // get the container id from the provider
Endpoint(context.Context, string) (string, error) // get proto://ip:port string for the lowest exposed port
PortEndpoint(ctx context.Context, port nat.Port, proto string) (string, error) // get proto://ip:port string for the given exposed port
Host(context.Context) (string, error) // get host where the container port is exposed
Inspect(context.Context) (*container.InspectResponse, error) // get container info
MappedPort(context.Context, nat.Port) (nat.Port, error) // get externally mapped port for a container port
Ports(context.Context) (nat.PortMap, error) // Deprecated: Use c.Inspect(ctx).NetworkSettings.Ports instead
SessionID() string // get session id
IsRunning() bool // IsRunning returns true if the container is running, false otherwise.
Start(context.Context) error // start the container
Stop(context.Context, *time.Duration) error // stop the container
GetContainerID() string // get the container id from the provider
Endpoint(context.Context, string) (string, error) // get proto://ip:port string for the lowest exposed port
PortEndpoint(ctx context.Context, port string, proto string) (string, error) // get proto://ip:port string for the given exposed port
Host(context.Context) (string, error) // get host where the container port is exposed
Inspect(context.Context) (*container.InspectResponse, error) // get container info
MappedPort(context.Context, string) (network.Port, error) // get externally mapped port for a container port
Ports(context.Context) (network.PortMap, error) // Deprecated: Use c.Inspect(ctx).NetworkSettings.Ports instead
SessionID() string // get session id
IsRunning() bool // IsRunning returns true if the container is running, false otherwise.
Start(context.Context) error // start the container
Stop(context.Context, *time.Duration) error // stop the container

// Terminate stops and removes the container and its image if it was built and not flagged as kept.
Terminate(ctx context.Context, opts ...TerminateOption) error
Expand All @@ -75,15 +74,15 @@ type Container interface {

// ImageBuildInfo defines what is needed to build an image
type ImageBuildInfo interface {
BuildOptions() (build.ImageBuildOptions, error) // converts the ImageBuildInfo to a build.ImageBuildOptions
GetContext() (io.Reader, error) // the path to the build context
GetDockerfile() string // the relative path to the Dockerfile, including the file itself
GetRepo() string // get repo label for image
GetTag() string // get tag label for image
BuildLogWriter() io.Writer // for output of build log, use io.Discard to disable the output
ShouldBuildImage() bool // return true if the image needs to be built
GetBuildArgs() map[string]*string // return the environment args used to build the Dockerfile
GetAuthConfigs() map[string]registry.AuthConfig // Deprecated. Testcontainers will detect registry credentials automatically. Return the auth configs to be able to pull from an authenticated docker registry
BuildOptions() (client.ImageBuildOptions, error) // converts the ImageBuildInfo to a build.ImageBuildOptions
GetContext() (io.Reader, error) // the path to the build context
GetDockerfile() string // the relative path to the Dockerfile, including the file itself
GetRepo() string // get repo label for image
GetTag() string // get tag label for image
BuildLogWriter() io.Writer // for output of build log, use io.Discard to disable the output
ShouldBuildImage() bool // return true if the image needs to be built
GetBuildArgs() map[string]*string // return the environment args used to build the Dockerfile
GetAuthConfigs() map[string]registry.AuthConfig // Deprecated. Testcontainers will detect registry credentials automatically. Return the auth configs to be able to pull from an authenticated docker registry
}

// FromDockerfile represents the parameters needed to build an image from a Dockerfile
Expand All @@ -105,7 +104,7 @@ type FromDockerfile struct {
// BuildOptionsModifier Modifier for the build options before image build. Use it for
// advanced configurations while building the image. Please consider that the modifier
// is called after the default build options are set.
BuildOptionsModifier func(*build.ImageBuildOptions)
BuildOptionsModifier func(*client.ImageBuildOptions)
}

type ContainerFile struct {
Expand Down Expand Up @@ -435,8 +434,8 @@ func (c *ContainerRequest) BuildLogWriter() io.Writer {
// BuildOptions returns the image build options when building a Docker image from a Dockerfile.
// It will apply some defaults and finally call the BuildOptionsModifier from the FromDockerfile struct,
// if set.
func (c *ContainerRequest) BuildOptions() (build.ImageBuildOptions, error) {
buildOptions := build.ImageBuildOptions{
func (c *ContainerRequest) BuildOptions() (client.ImageBuildOptions, error) {
buildOptions := client.ImageBuildOptions{
Remove: true,
ForceRemove: true,
}
Expand All @@ -452,7 +451,7 @@ func (c *ContainerRequest) BuildOptions() (build.ImageBuildOptions, error) {
// Make sure the auth configs from the Dockerfile are set right after the user-defined build options.
authsFromDockerfile, err := getAuthConfigsFromDockerfile(c)
if err != nil {
return build.ImageBuildOptions{}, fmt.Errorf("auth configs from Dockerfile: %w", err)
return client.ImageBuildOptions{}, fmt.Errorf("auth configs from Dockerfile: %w", err)
}

if buildOptions.AuthConfigs == nil {
Expand All @@ -468,7 +467,7 @@ func (c *ContainerRequest) BuildOptions() (build.ImageBuildOptions, error) {
for _, is := range c.ImageSubstitutors {
modifiedTag, err := is.Substitute(tag)
if err != nil {
return build.ImageBuildOptions{}, fmt.Errorf("failed to substitute image %s with %s: %w", tag, is.Description(), err)
return client.ImageBuildOptions{}, fmt.Errorf("failed to substitute image %s with %s: %w", tag, is.Description(), err)
}

if modifiedTag != tag {
Expand All @@ -487,18 +486,18 @@ func (c *ContainerRequest) BuildOptions() (build.ImageBuildOptions, error) {
if !c.ShouldKeepBuiltImage() {
dst := GenericLabels()
if err = core.MergeCustomLabels(dst, c.Labels); err != nil {
return build.ImageBuildOptions{}, err
return client.ImageBuildOptions{}, err
}
if err = core.MergeCustomLabels(dst, buildOptions.Labels); err != nil {
return build.ImageBuildOptions{}, err
return client.ImageBuildOptions{}, err
}
buildOptions.Labels = dst
}

// Do this as late as possible to ensure we don't leak the context on error/panic.
buildContext, err := c.GetContext()
if err != nil {
return build.ImageBuildOptions{}, err
return client.ImageBuildOptions{}, err
}

buildOptions.Context = buildContext
Expand Down
12 changes: 6 additions & 6 deletions container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (
"testing"
"time"

"github.com/docker/docker/api/types/build"
"github.com/docker/docker/api/types/container"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/client"
"github.com/stretchr/testify/require"

"github.com/testcontainers/testcontainers-go"
Expand Down Expand Up @@ -342,7 +342,7 @@ func TestCustomLabelsBuildOptionsModifier(t *testing.T) {
testcontainers.WithDockerfile(testcontainers.FromDockerfile{
Context: "./testdata",
Dockerfile: "Dockerfile",
BuildOptionsModifier: func(opts *build.ImageBuildOptions) {
BuildOptionsModifier: func(opts *client.ImageBuildOptions) {
opts.Labels = map[string]string{
myBuildOptionLabel: myBuildOptionValue,
}
Expand Down Expand Up @@ -377,8 +377,8 @@ func Test_GetLogsFromFailedContainer(t *testing.T) {
b, err := io.ReadAll(logs)
require.NoError(t, err)

log := string(b)
require.Contains(t, log, "I was not expecting this")
out := string(b)
require.Contains(t, out, "I was not expecting this")
}

// dockerImageSubstitutor {
Expand Down Expand Up @@ -497,7 +497,7 @@ func TestShouldStartContainersInParallel(t *testing.T) {
// }
require.NoError(t, err)

t.Logf("Parallel container [iteration_%d] listening on %d\n", i, port.Int())
t.Logf("Parallel container [iteration_%d] listening on %d\n", i, port.Num())
})
}
}
Expand Down
Loading