Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Use the testcontainers_test package for root tests to improve documentation #2202

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
9 changes: 5 additions & 4 deletions config_test.go
@@ -1,10 +1,11 @@
package testcontainers
package testcontainers_test

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/internal/config"
)

Expand All @@ -26,9 +27,9 @@ func TestReadConfig(t *testing.T) {
t.Setenv("USERPROFILE", "") // Windows support
t.Setenv("TESTCONTAINERS_RYUK_DISABLED", "true")

cfg := ReadConfig()
cfg := testcontainers.ReadConfig()

expected := TestcontainersConfig{
expected := testcontainers.TestcontainersConfig{
RyukDisabled: true,
Config: config.Config{
RyukDisabled: true,
Expand All @@ -38,7 +39,7 @@ func TestReadConfig(t *testing.T) {
assert.Equal(t, expected, cfg)

t.Setenv("TESTCONTAINERS_RYUK_DISABLED", "false")
cfg = ReadConfig()
cfg = testcontainers.ReadConfig()
assert.Equal(t, expected, cfg)
})
}
34 changes: 34 additions & 0 deletions container_ignore_test.go
@@ -0,0 +1,34 @@
// This test is testing very internal logic that should not be exported away from this package. We'll
// leave it in the main testcontainers package. Do not use for user facing examples.
package testcontainers

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestParseDockerIgnore(t *testing.T) {
testCases := []struct {
filePath string
expectedErr error
expectedExcluded []string
}{
{
filePath: "./testdata/dockerignore",
expectedErr: nil,
expectedExcluded: []string{"vendor", "foo", "bar"},
},
{
filePath: "./testdata",
expectedErr: nil,
expectedExcluded: []string(nil),
},
}

for _, testCase := range testCases {
excluded, err := parseDockerIgnore(testCase.filePath)
assert.Equal(t, testCase.expectedErr, err)
assert.Equal(t, testCase.expectedExcluded, excluded)
}
}
94 changes: 35 additions & 59 deletions container_test.go
@@ -1,4 +1,4 @@
package testcontainers
package testcontainers_test

import (
"archive/tar"
Expand All @@ -16,22 +16,23 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)

func Test_ContainerValidation(t *testing.T) {
type ContainerValidationTestCase struct {
Name string
ExpectedError error
ContainerRequest ContainerRequest
ContainerRequest testcontainers.ContainerRequest
}

testTable := []ContainerValidationTestCase{
{
Name: "cannot set both context and image",
ExpectedError: errors.New("you cannot specify both an Image and Context in a ContainerRequest"),
ContainerRequest: ContainerRequest{
FromDockerfile: FromDockerfile{
ContainerRequest: testcontainers.ContainerRequest{
FromDockerfile: testcontainers.FromDockerfile{
Context: ".",
},
Image: "redis:latest",
Expand All @@ -40,23 +41,23 @@ func Test_ContainerValidation(t *testing.T) {
{
Name: "can set image without context",
ExpectedError: nil,
ContainerRequest: ContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "redis:latest",
},
},
{
Name: "can set context without image",
ExpectedError: nil,
ContainerRequest: ContainerRequest{
FromDockerfile: FromDockerfile{
ContainerRequest: testcontainers.ContainerRequest{
FromDockerfile: testcontainers.FromDockerfile{
Context: ".",
},
},
},
{
Name: "Can mount same source to multiple targets",
ExpectedError: nil,
ContainerRequest: ContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "redis:latest",
HostConfigModifier: func(hc *container.HostConfig) {
hc.Binds = []string{"/data:/srv", "/data:/data"}
Expand All @@ -66,7 +67,7 @@ func Test_ContainerValidation(t *testing.T) {
{
Name: "Cannot mount multiple sources to same target",
ExpectedError: errors.New("duplicate mount target detected: /data"),
ContainerRequest: ContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "redis:latest",
HostConfigModifier: func(hc *container.HostConfig) {
hc.Binds = []string{"/data:/data", "/data:/data"}
Expand All @@ -76,7 +77,7 @@ func Test_ContainerValidation(t *testing.T) {
{
Name: "Invalid bind mount",
ExpectedError: errors.New("invalid bind mount: /data:/data:/data"),
ContainerRequest: ContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "redis:latest",
HostConfigModifier: func(hc *container.HostConfig) {
hc.Binds = []string{"/data:/data:/data"}
Expand Down Expand Up @@ -106,27 +107,27 @@ func Test_GetDockerfile(t *testing.T) {
type TestCase struct {
name string
ExpectedDockerfileName string
ContainerRequest ContainerRequest
ContainerRequest testcontainers.ContainerRequest
}

testTable := []TestCase{
{
name: "defaults to \"Dockerfile\" 1",
ExpectedDockerfileName: "Dockerfile",
ContainerRequest: ContainerRequest{},
ContainerRequest: testcontainers.ContainerRequest{},
},
{
name: "defaults to \"Dockerfile\" 2",
ExpectedDockerfileName: "Dockerfile",
ContainerRequest: ContainerRequest{
FromDockerfile: FromDockerfile{},
ContainerRequest: testcontainers.ContainerRequest{
FromDockerfile: testcontainers.FromDockerfile{},
},
},
{
name: "will override name",
ExpectedDockerfileName: "CustomDockerfile",
ContainerRequest: ContainerRequest{
FromDockerfile: FromDockerfile{
ContainerRequest: testcontainers.ContainerRequest{
FromDockerfile: testcontainers.FromDockerfile{
Dockerfile: "CustomDockerfile",
},
},
Expand Down Expand Up @@ -278,16 +279,16 @@ func Test_BuildImageWithContexts(t *testing.T) {
if err != nil {
t.Fatal(err)
}
req := ContainerRequest{
FromDockerfile: FromDockerfile{
req := testcontainers.ContainerRequest{
FromDockerfile: testcontainers.FromDockerfile{
ContextArchive: a,
Context: testCase.ContextPath,
Dockerfile: testCase.Dockerfile,
},
WaitingFor: wait.ForLog(testCase.ExpectedEchoOutput).WithStartupTimeout(1 * time.Minute),
}

c, err := GenericContainer(ctx, GenericContainerRequest{
c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
Expand All @@ -308,14 +309,14 @@ func Test_BuildImageWithContexts(t *testing.T) {
func Test_GetLogsFromFailedContainer(t *testing.T) {
ctx := context.Background()
// directDockerHubReference {
req := ContainerRequest{
req := testcontainers.ContainerRequest{
Image: "docker.io/alpine",
Cmd: []string{"echo", "-n", "I was not expecting this"},
WaitingFor: wait.ForLog("I was expecting this").WithStartupTimeout(5 * time.Second),
}
// }

c, err := GenericContainer(ctx, GenericContainerRequest{
c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
Expand Down Expand Up @@ -391,7 +392,7 @@ 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 []ImageSubstitutor
substitutors []testcontainers.ImageSubstitutor
expectedImage string
expectedError error
}{
Expand All @@ -403,19 +404,19 @@ func TestImageSubstitutors(t *testing.T) {
{
name: "Noop substitutor",
image: "alpine",
substitutors: []ImageSubstitutor{NoopImageSubstitutor{}},
substitutors: []testcontainers.ImageSubstitutor{NoopImageSubstitutor{}},
expectedImage: "alpine",
},
{
name: "Prepend namespace",
image: "alpine",
substitutors: []ImageSubstitutor{dockerImageSubstitutor{}},
substitutors: []testcontainers.ImageSubstitutor{dockerImageSubstitutor{}},
expectedImage: "docker.io/alpine",
},
{
name: "Substitution with error",
image: "alpine",
substitutors: []ImageSubstitutor{errorSubstitutor{}},
substitutors: []testcontainers.ImageSubstitutor{errorSubstitutor{}},
expectedImage: "alpine",
expectedError: errSubstitution,
},
Expand All @@ -424,12 +425,12 @@ func TestImageSubstitutors(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ctx := context.Background()
req := ContainerRequest{
req := testcontainers.ContainerRequest{
Image: test.image,
ImageSubstitutors: test.substitutors,
}

container, err := GenericContainer(ctx, GenericContainerRequest{
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
Expand All @@ -447,7 +448,7 @@ func TestImageSubstitutors(t *testing.T) {

// enforce the concrete type, as GenericContainer returns an interface,
// which will be changed in future implementations of the library
dockerContainer := container.(*DockerContainer)
dockerContainer := container.(*testcontainers.DockerContainer)
assert.Equal(t, test.expectedImage, dockerContainer.Image)
})
}
Expand All @@ -462,12 +463,12 @@ func TestShouldStartContainersInParallel(t *testing.T) {
t.Run(fmt.Sprintf("iteration_%d", i), func(t *testing.T) {
t.Parallel()

req := ContainerRequest{
req := testcontainers.ContainerRequest{
Image: nginxAlpineImage,
ExposedPorts: []string{nginxDefaultPort},
WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second),
}
container, err := GenericContainer(ctx, GenericContainerRequest{
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
Expand All @@ -488,39 +489,14 @@ func TestShouldStartContainersInParallel(t *testing.T) {
}
}

func TestParseDockerIgnore(t *testing.T) {
testCases := []struct {
filePath string
expectedErr error
expectedExcluded []string
}{
{
filePath: "./testdata/dockerignore",
expectedErr: nil,
expectedExcluded: []string{"vendor", "foo", "bar"},
},
{
filePath: "./testdata",
expectedErr: nil,
expectedExcluded: []string(nil),
},
}

for _, testCase := range testCases {
excluded, err := parseDockerIgnore(testCase.filePath)
assert.Equal(t, testCase.expectedErr, err)
assert.Equal(t, testCase.expectedExcluded, excluded)
}
}

func ExampleGenericContainer_withSubstitutors() {
ctx := context.Background()

// applyImageSubstitutors {
container, err := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: ContainerRequest{
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "alpine:latest",
ImageSubstitutors: []ImageSubstitutor{dockerImageSubstitutor{}},
ImageSubstitutors: []testcontainers.ImageSubstitutor{dockerImageSubstitutor{}},
},
Started: true,
})
Expand All @@ -538,7 +514,7 @@ func ExampleGenericContainer_withSubstitutors() {

// enforce the concrete type, as GenericContainer returns an interface,
// which will be changed in future implementations of the library
dockerContainer := container.(*DockerContainer)
dockerContainer := container.(*testcontainers.DockerContainer)

fmt.Println(dockerContainer.Image)

Expand Down
16 changes: 8 additions & 8 deletions docker.go
Expand Up @@ -922,7 +922,7 @@
// If default network is not bridge make sure it is attached to the request
// as container won't be attached to it automatically
// in case of Podman the bridge network is called 'podman' as 'bridge' would conflict
if p.DefaultNetwork != p.defaultBridgeNetworkName {
if p.DefaultNetwork != p.DefaultBridgeNetworkName {
isAttached := false
for _, net := range req.Networks {
if net == p.DefaultNetwork {
Expand Down Expand Up @@ -1076,13 +1076,13 @@
// default hooks include logger hook and pre-create hook
defaultHooks := []ContainerLifecycleHooks{
DefaultLoggingHook(p.Logger),
defaultPreCreateHook(ctx, p, req, dockerInput, hostConfig, networkingConfig),
defaultCopyFileToContainerHook(req.Files),
defaultLogConsumersHook(req.LogConsumerCfg),
defaultReadinessHook(),
DefaultPreCreateHook(p, dockerInput, hostConfig, networkingConfig),
DefaultCopyFileToContainerHook(req.Files),
DefaultLogConsumersHook(req.LogConsumerCfg),
DefaultReadinessHook(),
}

req.LifecycleHooks = []ContainerLifecycleHooks{combineContainerHooks(defaultHooks, req.LifecycleHooks)}
req.LifecycleHooks = []ContainerLifecycleHooks{CombineContainerHooks(defaultHooks, req.LifecycleHooks)}

err = req.creatingHook(ctx)
if err != nil {
Expand Down Expand Up @@ -1211,8 +1211,8 @@
// default hooks include logger hook and pre-create hook
defaultHooks := []ContainerLifecycleHooks{
DefaultLoggingHook(p.Logger),
defaultReadinessHook(),

Check failure on line 1214 in docker.go

View workflow job for this annotation

GitHub Actions / Test with Rootless Docker (1.x, ubuntu-latest) / ./ubuntu-latest/1.x

undefined: defaultReadinessHook

Check failure on line 1214 in docker.go

View workflow job for this annotation

GitHub Actions / test (1.20.x, macos-latest) / ./macos-latest/1.20.x

undefined: defaultReadinessHook

Check failure on line 1214 in docker.go

View workflow job for this annotation

GitHub Actions / test (1.x, ubuntu-latest) / ./ubuntu-latest/1.x

undefined: defaultReadinessHook

Check failure on line 1214 in docker.go

View workflow job for this annotation

GitHub Actions / Test with Rootless Docker (1.20.x, ubuntu-latest) / ./ubuntu-latest/1.20.x

undefined: defaultReadinessHook

Check failure on line 1214 in docker.go

View workflow job for this annotation

GitHub Actions / Test with Rootless Docker (1.20.x, ubuntu-latest) / ./ubuntu-latest/1.20.x

undefined: defaultReadinessHook

Check failure on line 1214 in docker.go

View workflow job for this annotation

GitHub Actions / Test with reaper off (1.x) / ./ubuntu-latest/1.x

undefined: defaultReadinessHook

Check failure on line 1214 in docker.go

View workflow job for this annotation

GitHub Actions / Test with reaper off (1.20.x) / ./ubuntu-latest/1.20.x

undefined: defaultReadinessHook

Check failure on line 1214 in docker.go

View workflow job for this annotation

GitHub Actions / Test with reaper off (1.20.x) / ./ubuntu-latest/1.20.x

undefined: defaultReadinessHook
defaultLogConsumersHook(req.LogConsumerCfg),

Check failure on line 1215 in docker.go

View workflow job for this annotation

GitHub Actions / Test with Rootless Docker (1.x, ubuntu-latest) / ./ubuntu-latest/1.x

undefined: defaultLogConsumersHook

Check failure on line 1215 in docker.go

View workflow job for this annotation

GitHub Actions / test (1.20.x, macos-latest) / ./macos-latest/1.20.x

undefined: defaultLogConsumersHook

Check failure on line 1215 in docker.go

View workflow job for this annotation

GitHub Actions / test (1.x, ubuntu-latest) / ./ubuntu-latest/1.x

undefined: defaultLogConsumersHook

Check failure on line 1215 in docker.go

View workflow job for this annotation

GitHub Actions / Test with Rootless Docker (1.20.x, ubuntu-latest) / ./ubuntu-latest/1.20.x

undefined: defaultLogConsumersHook

Check failure on line 1215 in docker.go

View workflow job for this annotation

GitHub Actions / Test with Rootless Docker (1.20.x, ubuntu-latest) / ./ubuntu-latest/1.20.x

undefined: defaultLogConsumersHook

Check failure on line 1215 in docker.go

View workflow job for this annotation

GitHub Actions / Test with reaper off (1.x) / ./ubuntu-latest/1.x

undefined: defaultLogConsumersHook

Check failure on line 1215 in docker.go

View workflow job for this annotation

GitHub Actions / Test with reaper off (1.20.x) / ./ubuntu-latest/1.20.x

undefined: defaultLogConsumersHook

Check failure on line 1215 in docker.go

View workflow job for this annotation

GitHub Actions / Test with reaper off (1.20.x) / ./ubuntu-latest/1.20.x

undefined: defaultLogConsumersHook
}

dc := &DockerContainer{
Expand All @@ -1224,7 +1224,7 @@
terminationSignal: termSignal,
stopLogProductionCh: nil,
logger: p.Logger,
lifecycleHooks: []ContainerLifecycleHooks{combineContainerHooks(defaultHooks, req.LifecycleHooks)},

Check failure on line 1227 in docker.go

View workflow job for this annotation

GitHub Actions / Test with Rootless Docker (1.x, ubuntu-latest) / ./ubuntu-latest/1.x

undefined: combineContainerHooks

Check failure on line 1227 in docker.go

View workflow job for this annotation

GitHub Actions / test (1.20.x, macos-latest) / ./macos-latest/1.20.x

undefined: combineContainerHooks

Check failure on line 1227 in docker.go

View workflow job for this annotation

GitHub Actions / test (1.x, ubuntu-latest) / ./ubuntu-latest/1.x

undefined: combineContainerHooks

Check failure on line 1227 in docker.go

View workflow job for this annotation

GitHub Actions / Test with Rootless Docker (1.20.x, ubuntu-latest) / ./ubuntu-latest/1.20.x

undefined: combineContainerHooks) (typecheck)

Check failure on line 1227 in docker.go

View workflow job for this annotation

GitHub Actions / Test with reaper off (1.x) / ./ubuntu-latest/1.x

undefined: combineContainerHooks

Check failure on line 1227 in docker.go

View workflow job for this annotation

GitHub Actions / Test with reaper off (1.20.x) / ./ubuntu-latest/1.20.x

undefined: combineContainerHooks) (typecheck)
}

err = dc.startedHook(ctx)
Expand Down Expand Up @@ -1479,8 +1479,8 @@
reaperNetworkExists := false

for _, net := range networkResources {
if net.Name == p.defaultBridgeNetworkName {
return p.defaultBridgeNetworkName, nil
if net.Name == p.DefaultBridgeNetworkName {
return p.DefaultBridgeNetworkName, nil
}

if net.Name == reaperNetwork {
Expand Down