Skip to content
Draft
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
39 changes: 5 additions & 34 deletions container.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ import (
"github.com/docker/docker/pkg/archive"
"github.com/docker/go-connections/nat"
"github.com/google/uuid"
"github.com/moby/patternmatcher/ignorefile"

tcexec "github.com/testcontainers/testcontainers-go/exec"
"github.com/testcontainers/testcontainers-go/image"
"github.com/testcontainers/testcontainers-go/internal/core"
"github.com/testcontainers/testcontainers-go/log"
"github.com/testcontainers/testcontainers-go/wait"
Expand Down Expand Up @@ -71,18 +71,9 @@ type Container interface {
GetLogProductionErrorChannel() <-chan error
}

// Deprecated: Use image.Builder instead
// ImageBuildInfo defines what is needed to build an image
type ImageBuildInfo interface {
BuildOptions() (types.ImageBuildOptions, error) // converts the ImageBuildInfo to a types.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
}
type ImageBuildInfo = image.Builder

// FromDockerfile represents the parameters needed to build an image from a Dockerfile
// rather than using a pre-built one
Expand Down Expand Up @@ -131,7 +122,7 @@ type ContainerRequest struct {
FromDockerfile
HostAccessPorts []int
Image string
ImageSubstitutors []ImageSubstitutor
ImageSubstitutors []image.Substitutor
Entrypoint []string
Env map[string]string
ExposedPorts []string // allow specifying protocol info
Expand Down Expand Up @@ -240,7 +231,7 @@ func (c *ContainerRequest) GetContext() (io.Reader, error) {
}
c.Context = abs

dockerIgnoreExists, excluded, err := parseDockerIgnore(abs)
dockerIgnoreExists, excluded, err := image.ParseDockerIgnore(abs)
if err != nil {
return nil, err
}
Expand All @@ -263,26 +254,6 @@ func (c *ContainerRequest) GetContext() (io.Reader, error) {
return buildContext, nil
}

// parseDockerIgnore returns if the file exists, the excluded files and an error if any
func parseDockerIgnore(targetDir string) (bool, []string, error) {
// based on https://github.com/docker/cli/blob/master/cli/command/image/build/dockerignore.go#L14
fileLocation := filepath.Join(targetDir, ".dockerignore")
var excluded []string
exists := false
if f, openErr := os.Open(fileLocation); openErr == nil {
defer f.Close()

exists = true

var err error
excluded, err = ignorefile.ReadAll(f)
if err != nil {
return true, excluded, fmt.Errorf("error reading .dockerignore: %w", err)
}
}
return exists, excluded, nil
}

// GetBuildArgs returns the env args to be used when creating from Dockerfile
func (c *ContainerRequest) GetBuildArgs() map[string]*string {
return c.FromDockerfile.BuildArgs
Expand Down
44 changes: 0 additions & 44 deletions container_ignore_test.go

This file was deleted.

110 changes: 2 additions & 108 deletions container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"archive/tar"
"bytes"
"context"
"errors"
"fmt"
"io"
"testing"
Expand All @@ -16,6 +15,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/image"
"github.com/testcontainers/testcontainers-go/log"
"github.com/testcontainers/testcontainers-go/wait"
)
Expand Down Expand Up @@ -400,112 +400,6 @@ func Test_GetLogsFromFailedContainer(t *testing.T) {
require.Contains(t, log, "I was not expecting this")
}

// dockerImageSubstitutor {
type dockerImageSubstitutor struct{}

func (s dockerImageSubstitutor) Description() string {
return "DockerImageSubstitutor (prepends registry.hub.docker.com)"
}

func (s dockerImageSubstitutor) Substitute(image string) (string, error) {
return "registry.hub.docker.com/library/" + image, nil
}

// }

// noopImageSubstitutor {
type NoopImageSubstitutor struct{}

// Description returns a description of what is expected from this Substitutor,
// which is used in logs.
func (s NoopImageSubstitutor) Description() string {
return "NoopImageSubstitutor (noop)"
}

// Substitute returns the original image, without any change
func (s NoopImageSubstitutor) Substitute(image string) (string, error) {
return image, nil
}

// }

type errorSubstitutor struct{}

var errSubstitution = errors.New("substitution error")

// Description returns a description of what is expected from this Substitutor,
// which is used in logs.
func (s errorSubstitutor) Description() string {
return "errorSubstitutor"
}

// Substitute returns the original image, but returns an error
func (s errorSubstitutor) Substitute(image string) (string, error) {
return image, errSubstitution
}

func TestImageSubstitutors(t *testing.T) {
tests := []struct {
name string
image string // must be a valid image, as the test will try to create a container from it
substitutors []testcontainers.ImageSubstitutor
expectedImage string
expectedError error
}{
{
name: "No substitutors",
image: "alpine",
expectedImage: "alpine",
},
{
name: "Noop substitutor",
image: "alpine",
substitutors: []testcontainers.ImageSubstitutor{NoopImageSubstitutor{}},
expectedImage: "alpine",
},
{
name: "Prepend namespace",
image: "alpine",
substitutors: []testcontainers.ImageSubstitutor{dockerImageSubstitutor{}},
expectedImage: "registry.hub.docker.com/library/alpine",
},
{
name: "Substitution with error",
image: "alpine",
substitutors: []testcontainers.ImageSubstitutor{errorSubstitutor{}},
expectedImage: "alpine",
expectedError: errSubstitution,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ctx := context.Background()
req := testcontainers.ContainerRequest{
Image: test.image,
ImageSubstitutors: test.substitutors,
}

ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
testcontainers.CleanupContainer(t, ctr)
if test.expectedError != nil {
require.ErrorIs(t, err, test.expectedError)
return
}

require.NoError(t, err)

// enforce the concrete type, as GenericContainer returns an interface,
// which will be changed in future implementations of the library
dockerContainer := ctr.(*testcontainers.DockerContainer)
assert.Equal(t, test.expectedImage, dockerContainer.Image)
})
}
}

func TestShouldStartContainersInParallel(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
t.Cleanup(cancel)
Expand Down Expand Up @@ -544,7 +438,7 @@ func ExampleGenericContainer_withSubstitutors() {
ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "alpine:latest",
ImageSubstitutors: []testcontainers.ImageSubstitutor{dockerImageSubstitutor{}},
ImageSubstitutors: []image.Substitutor{image.DockerSubstitutor{}},
},
Started: true,
})
Expand Down
Loading
Loading