From 7ca3d8e326eeaf546f8389f327de0b1df3aa096e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 23 Oct 2024 14:14:03 +0200 Subject: [PATCH 1/4] fix: simplify fully-qualified image names (#2846) * chore: do not prepend an invalid Docker registry Images used in the tests, and in the modules are using a wrong Docker image prefix: docker.io. It's better to ask for "nginx:latest" and let the engine deal with the image references. * fix: committed by mistake * chore: update more tests * fix: image cut * fix: removed too much * fix: removed too much Co-authored-by: Steven Hartland * chore: pin bash image * chore: extract to constant * chore: reuse constant --------- Co-authored-by: Steven Hartland --- container_test.go | 14 +++---- docker_files_test.go | 12 +++--- docker_test.go | 42 +++++++++---------- docs/features/image_name_substitution.md | 4 +- docs/features/wait/exit.md | 2 +- docs/features/wait/health.md | 2 +- docs/features/wait/host_port.md | 8 ++-- docs/features/wait/log.md | 4 +- docs/features/wait/multi.md | 2 +- docs/modules/artemis.md | 2 +- docs/modules/consul.md | 2 +- docs/modules/couchbase.md | 2 +- docs/modules/index.md | 2 +- docs/modules/k3s.md | 2 +- docs/modules/neo4j.md | 2 +- docs/modules/postgres.md | 2 +- docs/modules/pulsar.md | 2 +- docs/modules/redis.md | 2 +- docs/system_requirements/using_podman.md | 2 +- image_substitutors_test.go | 8 ++-- lifecycle_test.go | 2 +- logconsumer_test.go | 2 +- modulegen/main_test.go | 8 ++-- modules/artemis/artemis.go | 2 +- modules/artemis/artemis_test.go | 2 +- modules/artemis/examples_test.go | 2 +- modules/compose/compose_api_test.go | 4 +- .../testdata/docker-compose-complex.yml | 4 +- .../docker-compose-container-name.yml | 2 +- .../docker-compose-no-exposed-ports.yml | 2 +- .../testdata/docker-compose-override.yml | 4 +- .../testdata/docker-compose-postgres.yml | 2 +- .../testdata/docker-compose-profiles.yml | 8 ++-- .../docker-compose-short-lifespan.yml | 4 +- .../testdata/docker-compose-simple.yml | 2 +- .../testdata/docker-compose-volume.yml | 2 +- .../compose/testdata/echoserver.Dockerfile | 2 +- modules/consul/consul.go | 4 +- modules/consul/consul_test.go | 2 +- modules/consul/examples_test.go | 4 +- modules/k3s/k3s.go | 2 +- modules/k3s/k3s_example_test.go | 2 +- modules/k3s/k3s_test.go | 6 +-- modules/minio/minio.go | 2 +- modules/neo4j/examples_test.go | 2 +- modules/neo4j/neo4j_test.go | 4 +- modules/postgres/examples_test.go | 2 +- modules/postgres/postgres.go | 2 +- modules/postgres/postgres_test.go | 26 ++++++------ modules/pulsar/examples_test.go | 2 +- modules/pulsar/pulsar.go | 4 +- modules/pulsar/pulsar_test.go | 2 +- modules/redis/examples_test.go | 2 +- modules/redis/redis.go | 2 +- modules/redis/redis_test.go | 16 +++---- modules/redis/testdata/Dockerfile | 2 +- modules/valkey/examples_test.go | 2 +- modules/valkey/valkey.go | 2 +- modules/valkey/valkey_test.go | 10 ++--- network/network_test.go | 6 +-- options.go | 2 +- scripts/bump-reaper.sh | 4 +- scripts/release.sh | 2 +- testdata/Dockerfile | 2 +- testdata/args.Dockerfile | 2 +- testdata/buildlog.Dockerfile | 2 +- testdata/echo.Dockerfile | 2 +- testdata/echoserver.Dockerfile | 2 +- testdata/error.Dockerfile | 2 +- testdata/target.Dockerfile | 2 +- testhelpers_test.go | 2 +- wait/exec_test.go | 2 +- wait/file_test.go | 2 +- 73 files changed, 155 insertions(+), 153 deletions(-) diff --git a/container_test.go b/container_test.go index 16411283c6..72927bc55a 100644 --- a/container_test.go +++ b/container_test.go @@ -167,7 +167,7 @@ func Test_BuildImageWithContexts(t *testing.T) { }{ { Name: "Dockerfile", - Contents: `FROM docker.io/alpine + Contents: `FROM alpine CMD ["echo", "this is from the archive"]`, }, } @@ -216,7 +216,7 @@ func Test_BuildImageWithContexts(t *testing.T) { }, { Name: "Dockerfile", - Contents: `FROM docker.io/alpine + Contents: `FROM alpine WORKDIR /app COPY . . CMD ["sh", "./say_hi.sh"]`, @@ -365,7 +365,7 @@ func Test_GetLogsFromFailedContainer(t *testing.T) { ctx := context.Background() // directDockerHubReference { req := testcontainers.ContainerRequest{ - Image: "docker.io/alpine", + Image: "alpine", Cmd: []string{"echo", "-n", "I was not expecting this"}, WaitingFor: wait.ForLog("I was expecting this").WithStartupTimeout(5 * time.Second), } @@ -392,11 +392,11 @@ func Test_GetLogsFromFailedContainer(t *testing.T) { type dockerImageSubstitutor struct{} func (s dockerImageSubstitutor) Description() string { - return "DockerImageSubstitutor (prepends docker.io)" + return "DockerImageSubstitutor (prepends registry.hub.docker.com)" } func (s dockerImageSubstitutor) Substitute(image string) (string, error) { - return "docker.io/" + image, nil + return "registry.hub.docker.com/library/" + image, nil } // } @@ -455,7 +455,7 @@ func TestImageSubstitutors(t *testing.T) { name: "Prepend namespace", image: "alpine", substitutors: []testcontainers.ImageSubstitutor{dockerImageSubstitutor{}}, - expectedImage: "docker.io/alpine", + expectedImage: "registry.hub.docker.com/library/alpine", }, { name: "Substitution with error", @@ -554,5 +554,5 @@ func ExampleGenericContainer_withSubstitutors() { fmt.Println(dockerContainer.Image) - // Output: docker.io/alpine:latest + // Output: registry.hub.docker.com/library/alpine:latest } diff --git a/docker_files_test.go b/docker_files_test.go index 6a767e6163..9b8551f325 100644 --- a/docker_files_test.go +++ b/docker_files_test.go @@ -13,6 +13,8 @@ import ( "github.com/testcontainers/testcontainers-go/wait" ) +const testBashImage string = "bash:5.2.26" + func TestCopyFileToContainer(t *testing.T) { ctx, cnl := context.WithTimeout(context.Background(), 30*time.Second) defer cnl() @@ -30,7 +32,7 @@ func TestCopyFileToContainer(t *testing.T) { ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ - Image: "docker.io/bash", + Image: testBashImage, Files: []testcontainers.ContainerFile{ { Reader: r, @@ -66,7 +68,7 @@ func TestCopyFileToRunningContainer(t *testing.T) { ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ - Image: "docker.io/bash:5.2.26", + Image: testBashImage, Files: []testcontainers.ContainerFile{ { HostFilePath: waitForPath, @@ -104,7 +106,7 @@ func TestCopyDirectoryToContainer(t *testing.T) { ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ - Image: "docker.io/bash", + Image: testBashImage, Files: []testcontainers.ContainerFile{ { HostFilePath: dataDirectory, @@ -141,7 +143,7 @@ func TestCopyDirectoryToRunningContainerAsFile(t *testing.T) { ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ - Image: "docker.io/bash", + Image: testBashImage, Files: []testcontainers.ContainerFile{ { HostFilePath: waitForPath, @@ -183,7 +185,7 @@ func TestCopyDirectoryToRunningContainerAsDir(t *testing.T) { ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ - Image: "docker.io/bash", + Image: testBashImage, Files: []testcontainers.ContainerFile{ { HostFilePath: waitForPath, diff --git a/docker_test.go b/docker_test.go index d01f21f01f..2cc762a6aa 100644 --- a/docker_test.go +++ b/docker_test.go @@ -29,10 +29,10 @@ import ( ) const ( - mysqlImage = "docker.io/mysql:8.0.36" - nginxDelayedImage = "docker.io/menedev/delayed-nginx:1.15.2" - nginxImage = "docker.io/nginx" - nginxAlpineImage = "docker.io/nginx:alpine" + mysqlImage = "mysql:8.0.36" + nginxDelayedImage = "menedev/delayed-nginx:1.15.2" + nginxImage = "nginx" + nginxAlpineImage = "nginx:alpine" nginxDefaultPort = "80/tcp" nginxHighPort = "8080/tcp" daemonMaxVersion = "1.41" @@ -804,8 +804,8 @@ func Test_BuildContainerFromDockerfileWithBuildLog(t *testing.T) { temp := strings.Split(string(out), "\n") - if !regexp.MustCompile(`^Step\s*1/\d+\s*:\s*FROM docker.io/alpine$`).MatchString(temp[0]) { - t.Errorf("Expected stdout first line to be %s. Got '%s'.", "Step 1/* : FROM docker.io/alpine", temp[0]) + if !regexp.MustCompile(`^Step\s*1/\d+\s*:\s*FROM alpine$`).MatchString(temp[0]) { + t.Errorf("Expected stdout first line to be %s. Got '%s'.", "Step 1/* : FROM alpine", temp[0]) } } @@ -878,7 +878,7 @@ func TestCMD(t *testing.T) { ctx := context.Background() req := ContainerRequest{ - Image: "docker.io/alpine", + Image: "alpine", WaitingFor: wait.ForAll( wait.ForLog("command override!"), ), @@ -904,7 +904,7 @@ func TestEntrypoint(t *testing.T) { ctx := context.Background() req := ContainerRequest{ - Image: "docker.io/alpine", + Image: "alpine", WaitingFor: wait.ForAll( wait.ForLog("entrypoint override!"), ), @@ -930,7 +930,7 @@ func TestWorkingDir(t *testing.T) { ctx := context.Background() req := ContainerRequest{ - Image: "docker.io/alpine", + Image: "alpine", WaitingFor: wait.ForAll( wait.ForLog("/var/tmp/test"), ), @@ -950,7 +950,7 @@ func TestWorkingDir(t *testing.T) { func ExampleDockerProvider_CreateContainer() { ctx := context.Background() req := ContainerRequest{ - Image: "docker.io/nginx:alpine", + Image: "nginx:alpine", ExposedPorts: []string{"80/tcp"}, WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second), } @@ -983,7 +983,7 @@ func ExampleDockerProvider_CreateContainer() { func ExampleContainer_Host() { ctx := context.Background() req := ContainerRequest{ - Image: "docker.io/nginx:alpine", + Image: "nginx:alpine", ExposedPorts: []string{"80/tcp"}, WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second), } @@ -1025,7 +1025,7 @@ func ExampleContainer_Host() { func ExampleContainer_Start() { ctx := context.Background() req := ContainerRequest{ - Image: "docker.io/nginx:alpine", + Image: "nginx:alpine", ExposedPorts: []string{"80/tcp"}, WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second), } @@ -1062,7 +1062,7 @@ func ExampleContainer_Start() { func ExampleContainer_Stop() { ctx := context.Background() req := ContainerRequest{ - Image: "docker.io/nginx:alpine", + Image: "nginx:alpine", ExposedPorts: []string{"80/tcp"}, WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second), } @@ -1096,7 +1096,7 @@ func ExampleContainer_Stop() { func ExampleContainer_MappedPort() { ctx := context.Background() req := ContainerRequest{ - Image: "docker.io/nginx:alpine", + Image: "nginx:alpine", ExposedPorts: []string{"80/tcp"}, WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second), } @@ -1147,7 +1147,7 @@ func TestContainerCreationWithVolumeAndFileWritingToIt(t *testing.T) { bashC, err := GenericContainer(ctx, GenericContainerRequest{ ProviderType: providerType, ContainerRequest: ContainerRequest{ - Image: "docker.io/bash", + Image: "bash:5.2.26", Files: []ContainerFile{ { HostFilePath: absPath, @@ -1167,7 +1167,7 @@ func TestContainerCreationWithVolumeAndFileWritingToIt(t *testing.T) { func TestContainerWithTmpFs(t *testing.T) { ctx := context.Background() req := ContainerRequest{ - Image: "docker.io/busybox", + Image: "busybox", Cmd: []string{"sleep", "10"}, Tmpfs: map[string]string{"/testtmpfs": "rw"}, } @@ -1242,7 +1242,7 @@ func TestContainerNonExistentImage(t *testing.T) { c, err := GenericContainer(ctx, GenericContainerRequest{ ProviderType: providerType, ContainerRequest: ContainerRequest{ - Image: "docker.io/postgres:12", + Image: "postgres:12", WaitingFor: wait.ForLog("log"), }, Started: true, @@ -1266,7 +1266,7 @@ func TestContainerCustomPlatformImage(t *testing.T) { c, err := GenericContainer(ctx, GenericContainerRequest{ ProviderType: providerType, ContainerRequest: ContainerRequest{ - Image: "docker.io/redis:latest", + Image: "redis:latest", ImagePlatform: nonExistentPlatform, }, Started: false, @@ -1282,7 +1282,7 @@ func TestContainerCustomPlatformImage(t *testing.T) { c, err := GenericContainer(ctx, GenericContainerRequest{ ProviderType: providerType, ContainerRequest: ContainerRequest{ - Image: "docker.io/mysql:8.0.36", + Image: "mysql:8.0.36", ImagePlatform: "linux/amd64", }, Started: false, @@ -1817,7 +1817,7 @@ func TestContainerRunningCheckingStatusCode(t *testing.T) { func TestContainerWithUserID(t *testing.T) { ctx := context.Background() req := ContainerRequest{ - Image: "docker.io/alpine:latest", + Image: "alpine:latest", User: "60125", Cmd: []string{"sh", "-c", "id -u"}, WaitingFor: wait.ForExit(), @@ -1846,7 +1846,7 @@ func TestContainerWithUserID(t *testing.T) { func TestContainerWithNoUserID(t *testing.T) { ctx := context.Background() req := ContainerRequest{ - Image: "docker.io/alpine:latest", + Image: "alpine:latest", Cmd: []string{"sh", "-c", "id -u"}, WaitingFor: wait.ForExit(), } diff --git a/docs/features/image_name_substitution.md b/docs/features/image_name_substitution.md index 08e9e1d6a0..4272d35c1e 100644 --- a/docs/features/image_name_substitution.md +++ b/docs/features/image_name_substitution.md @@ -45,7 +45,7 @@ _Testcontainers for Go_ will automatically apply the prefix to every image that _Testcontainers for Go_ will not apply the prefix to: * non-Hub image names (e.g. where another registry is set) -* Docker Hub image names where the hub registry is explicitly part of the name (i.e. anything with a `docker.io` or `registry.hub.docker.com` host part) +* Docker Hub image names where the hub registry is explicitly part of the name (i.e. anything with a `registry.hub.docker.com` host part) ## Developing a custom function for transforming image names on the fly @@ -68,7 +68,7 @@ You can implement a custom image name substitutor by: * implementing the `ImageNameSubstitutor` interface, exposed by the `testcontainers` package. * configuring _Testcontainers for Go_ to use your custom implementation, defined at the `ContainerRequest` level. -The following is an example image substitutor implementation prepending the `docker.io/` prefix, used in the tests: +The following is an example image substitutor implementation prepending the `registry.hub.docker.com/library/` prefix, used in the tests: [Image Substitutor Interface](../../options.go) inside_block:imageSubstitutor diff --git a/docs/features/wait/exit.md b/docs/features/wait/exit.md index 3487cb2d21..bcb1aaca36 100644 --- a/docs/features/wait/exit.md +++ b/docs/features/wait/exit.md @@ -9,7 +9,7 @@ The exit wait strategy will check that the container is not in the running state ```golang req := ContainerRequest{ - Image: "docker.io/alpine:latest", + Image: "alpine:latest", WaitingFor: wait.ForExit(), } ``` diff --git a/docs/features/wait/health.md b/docs/features/wait/health.md index d4756f47bd..f724a11010 100644 --- a/docs/features/wait/health.md +++ b/docs/features/wait/health.md @@ -7,7 +7,7 @@ The health wait strategy will check that the container is in the healthy state a ```golang req := ContainerRequest{ - Image: "docker.io/alpine:latest", + Image: "alpine:latest", WaitingFor: wait.ForHealthCheck(), } ``` diff --git a/docs/features/wait/host_port.md b/docs/features/wait/host_port.md index 1b6090b584..10531e5e64 100644 --- a/docs/features/wait/host_port.md +++ b/docs/features/wait/host_port.md @@ -14,7 +14,7 @@ Variations on the HostPort wait strategy are supported, including: ```golang req := ContainerRequest{ - Image: "docker.io/nginx:alpine", + Image: "nginx:alpine", ExposedPorts: []string{"80/tcp"}, WaitingFor: wait.ForListeningPort("80/tcp"), } @@ -26,7 +26,7 @@ The wait strategy will use the lowest exposed port from the container configurat ```golang req := ContainerRequest{ - Image: "docker.io/nginx:alpine", + Image: "nginx:alpine", WaitingFor: wait.ForExposedPort(), } ``` @@ -35,7 +35,7 @@ Said that, it could be the case that the container request included ports to be ```golang req := ContainerRequest{ - Image: "docker.io/nginx:alpine", + Image: "nginx:alpine", ExposedPorts: []string{"80/tcp", "9080/tcp"}, WaitingFor: wait.ForExposedPort(), } @@ -55,7 +55,7 @@ In this case, the `wait.ForExposedPort.SkipInternalCheck` can be used to skip th ```golang req := ContainerRequest{ - Image: "docker.io/nginx:alpine", + Image: "nginx:alpine", ExposedPorts: []string{"80/tcp", "9080/tcp"}, WaitingFor: wait.ForExposedPort().SkipInternalCheck(), } diff --git a/docs/features/wait/log.md b/docs/features/wait/log.md index 66c418b284..f1d40ff360 100644 --- a/docs/features/wait/log.md +++ b/docs/features/wait/log.md @@ -10,7 +10,7 @@ The Log wait strategy will check if a string occurs in the container logs for a ```golang req := ContainerRequest{ - Image: "docker.io/mysql:8.0.36", + Image: "mysql:8.0.36", ExposedPorts: []string{"3306/tcp", "33060/tcp"}, Env: map[string]string{ "MYSQL_ROOT_PASSWORD": "password", @@ -24,7 +24,7 @@ Using a regular expression: ```golang req := ContainerRequest{ - Image: "docker.io/mysql:8.0.36", + Image: "mysql:8.0.36", ExposedPorts: []string{"3306/tcp", "33060/tcp"}, Env: map[string]string{ "MYSQL_ROOT_PASSWORD": "password", diff --git a/docs/features/wait/multi.md b/docs/features/wait/multi.md index bfd053955b..d5f809d6c2 100644 --- a/docs/features/wait/multi.md +++ b/docs/features/wait/multi.md @@ -9,7 +9,7 @@ Available Options: ```golang req := ContainerRequest{ - Image: "docker.io/mysql:8.0.36", + Image: "mysql:8.0.36", ExposedPorts: []string{"3306/tcp", "33060/tcp"}, Env: map[string]string{ "MYSQL_ROOT_PASSWORD": "password", diff --git a/docs/modules/artemis.md b/docs/modules/artemis.md index 395f1b304b..da13e2178a 100644 --- a/docs/modules/artemis.md +++ b/docs/modules/artemis.md @@ -50,7 +50,7 @@ When starting the Artemis container, you can pass options in a variadic way to c #### Image If you need to set a different Artemis Docker image, you can set a valid Docker image as the second argument in the `Run` function. -E.g. `Run(context.Background(), "docker.io/apache/activemq-artemis:2.30.0")`. +E.g. `Run(context.Background(), "apache/activemq-artemis:2.30.0")`. {% include "../features/common_functional_options.md" %} diff --git a/docs/modules/consul.md b/docs/modules/consul.md index 813799e28a..b2b77921df 100644 --- a/docs/modules/consul.md +++ b/docs/modules/consul.md @@ -46,7 +46,7 @@ When starting the Consul container, you can pass options in a variadic way to co #### Image If you need to set a different Consul Docker image, you can set a valid Docker image as the second argument in the `Run` function. -E.g. `Run(context.Background(), "docker.io/hashicorp/consul:1.15")`. +E.g. `Run(context.Background(), "hashicorp/consul:1.15")`. {% include "../features/common_functional_options.md" %} diff --git a/docs/modules/couchbase.md b/docs/modules/couchbase.md index ac07889bfa..43b0c85007 100644 --- a/docs/modules/couchbase.md +++ b/docs/modules/couchbase.md @@ -73,7 +73,7 @@ When starting the Couchbase container, you can pass options in a variadic way to #### Image If you need to set a different Couchbase Docker image, you can set a valid Docker image as the second argument in the `Run` function. -E.g. `Run(context.Background(), "docker.io/couchbase:6.5.1")`. +E.g. `Run(context.Background(), "couchbase:6.5.1")`. You can find the Docker images that are currently tested in this module, for the Enterprise and Community editions, in the following list: diff --git a/docs/modules/index.md b/docs/modules/index.md index 629787fedf..8db41723fa 100644 --- a/docs/modules/index.md +++ b/docs/modules/index.md @@ -72,7 +72,7 @@ We have provided a command line tool to generate the scaffolding for the code of | Flag | Short | Type | Required | Description | |---------|-------|--------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------| | --name | -n | string | Yes | Name of the module, use camel-case when needed. Only alphanumerical characters are allowed (leading character must be a letter). | -| --image | -i | string | Yes | Fully-qualified name of the Docker image to be used in the examples and tests (i.e. 'docker.io/org/project:tag') | +| --image | -i | string | Yes | Fully-qualified name of the Docker image to be used in the examples and tests (i.e. 'org/project:tag') | | --title | -t | string | No | A variant of the name supporting mixed casing (i.e. 'MongoDB'). Only alphanumerical characters are allowed (leading character must be a letter). | diff --git a/docs/modules/k3s.md b/docs/modules/k3s.md index 6ada392534..617c1d4ffe 100644 --- a/docs/modules/k3s.md +++ b/docs/modules/k3s.md @@ -52,7 +52,7 @@ When starting the K3s container, you can pass options in a variadic way to confi #### Image If you need to set a different K3s Docker image, you can set a valid Docker image as the second argument in the `Run` function. -E.g. `Run(context.Background(), "docker.io/rancher/k3s:v1.27.1-k3s1")`. +E.g. `Run(context.Background(), "rancher/k3s:v1.27.1-k3s1")`. {% include "../features/common_functional_options.md" %} diff --git a/docs/modules/neo4j.md b/docs/modules/neo4j.md index aadda970e1..0431df12a1 100644 --- a/docs/modules/neo4j.md +++ b/docs/modules/neo4j.md @@ -56,7 +56,7 @@ When starting the Neo4j container, you can pass options in a variadic way to con #### Image If you need to set a different Neo4j Docker image, you can set a valid Docker image as the second argument in the `Run` function. -E.g. `Run(context.Background(), "docker.io/neo4j:4.4")`. +E.g. `Run(context.Background(), "neo4j:4.4")`. By default, the container will use the following Docker image: diff --git a/docs/modules/postgres.md b/docs/modules/postgres.md index 82b1e04351..930de50c15 100644 --- a/docs/modules/postgres.md +++ b/docs/modules/postgres.md @@ -49,7 +49,7 @@ When starting the Postgres container, you can pass options in a variadic way to #### Image If you need to set a different Postgres Docker image, you can set a valid Docker image as the second argument in the `Run` function. -E.g. `Run(context.Background(), "docker.io/postgres:16-alpine")`. +E.g. `Run(context.Background(), "postgres:16-alpine")`. {% include "../features/common_functional_options.md" %} diff --git a/docs/modules/pulsar.md b/docs/modules/pulsar.md index d8c3db5735..99f93b2222 100644 --- a/docs/modules/pulsar.md +++ b/docs/modules/pulsar.md @@ -52,7 +52,7 @@ When starting the Pulsar container, you can pass options in a variadic way to co #### Image If you need to set a different Pulsar Docker image, you can set a valid Docker image as the second argument in the `Run` function. -E.g. `Run(context.Background(), "docker.io/apachepulsar/pulsar:2.10.2")`. +E.g. `Run(context.Background(), "apachepulsar/pulsar:2.10.2")`. {% include "../features/common_functional_options.md" %} diff --git a/docs/modules/redis.md b/docs/modules/redis.md index 51e111dfff..e6bbd90851 100644 --- a/docs/modules/redis.md +++ b/docs/modules/redis.md @@ -49,7 +49,7 @@ When starting the Redis container, you can pass options in a variadic way to con #### Image If you need to set a different Redis Docker image, you can set a valid Docker image as the second argument in the `Run` function. -E.g. `Run(context.Background(), "docker.io/redis:7")`. +E.g. `Run(context.Background(), "redis:7")`. {% include "../features/common_functional_options.md" %} diff --git a/docs/system_requirements/using_podman.md b/docs/system_requirements/using_podman.md index cf65792bbd..4143306901 100644 --- a/docs/system_requirements/using_podman.md +++ b/docs/system_requirements/using_podman.md @@ -27,7 +27,7 @@ func TestSomething(t *testing.T) { req := tc.GenericContainerRequest{ ProviderType: tc.ProviderPodman, ContainerRequest: tc.ContainerRequest{ - Image: "docker.io/nginx:alpine" + Image: "nginx:alpine" }, } diff --git a/image_substitutors_test.go b/image_substitutors_test.go index 4a41f31ce6..92b42e63b3 100644 --- a/image_substitutors_test.go +++ b/image_substitutors_test.go @@ -104,16 +104,16 @@ func TestPrependHubRegistrySubstitutor(t *testing.T) { } }) - t.Run("explicitly including docker.io", func(t *testing.T) { + t.Run("explicitly including registry.hub.docker.com/library", func(t *testing.T) { s := newPrependHubRegistry("my-registry") - img, err := s.Substitute("docker.io/foo:latest") + img, err := s.Substitute("registry.hub.docker.com/library/foo:latest") if err != nil { t.Fatal(err) } - if img != "docker.io/foo:latest" { - t.Errorf("expected docker.io/foo:latest, got %s", img) + if img != "registry.hub.docker.com/library/foo:latest" { + t.Errorf("expected registry.hub.docker.com/library/foo:latest, got %s", img) } }) diff --git a/lifecycle_test.go b/lifecycle_test.go index b1cff8dad8..0d7e9c7861 100644 --- a/lifecycle_test.go +++ b/lifecycle_test.go @@ -887,7 +887,7 @@ func TestPrintContainerLogsOnError(t *testing.T) { ctx := context.Background() req := ContainerRequest{ - Image: "docker.io/alpine", + Image: "alpine", Cmd: []string{"echo", "-n", "I am expecting this"}, WaitingFor: wait.ForLog("I was expecting that").WithStartupTimeout(5 * time.Second), } diff --git a/logconsumer_test.go b/logconsumer_test.go index 9f4b0b61f9..f16c2fc007 100644 --- a/logconsumer_test.go +++ b/logconsumer_test.go @@ -251,7 +251,7 @@ func TestContainerLogWithErrClosed(t *testing.T) { dind, err := GenericContainer(ctx, GenericContainerRequest{ Started: true, ContainerRequest: ContainerRequest{ - Image: "docker.io/docker:dind", + Image: "docker:dind", ExposedPorts: []string{"2375/tcp"}, Env: map[string]string{"DOCKER_TLS_CERTDIR": ""}, WaitingFor: wait.ForListeningPort("2375/tcp"), diff --git a/modulegen/main_test.go b/modulegen/main_test.go index eeb836a8a5..bbad5a5abb 100644 --- a/modulegen/main_test.go +++ b/modulegen/main_test.go @@ -187,7 +187,7 @@ func TestGenerateWrongModuleName(t *testing.T) { for _, test := range tests { module := context.TestcontainersModule{ Name: test.name, - Image: "docker.io/example/" + test.name + ":latest", + Image: "example/" + test.name + ":latest", } err = internal.GenerateFiles(tmpCtx, module) @@ -231,7 +231,7 @@ func TestGenerateWrongModuleTitle(t *testing.T) { module := context.TestcontainersModule{ Name: "foo", TitleName: test.title, - Image: "docker.io/example/foo:latest", + Image: "example/foo:latest", } err = internal.GenerateFiles(tmpCtx, module) @@ -266,7 +266,7 @@ func TestGenerate(t *testing.T) { Name: "foodb4tw", TitleName: "FooDB4TheWin", IsModule: false, - Image: "docker.io/example/foodb:latest", + Image: "example/foodb:latest", } moduleNameLower := module.Lower() @@ -322,7 +322,7 @@ func TestGenerateModule(t *testing.T) { Name: "foodb", TitleName: "FooDB", IsModule: true, - Image: "docker.io/example/foodb:latest", + Image: "example/foodb:latest", } moduleNameLower := module.Lower() diff --git a/modules/artemis/artemis.go b/modules/artemis/artemis.go index a8721ce189..e74b542cd7 100644 --- a/modules/artemis/artemis.go +++ b/modules/artemis/artemis.go @@ -81,7 +81,7 @@ func WithExtraArgs(args string) testcontainers.CustomizeRequestOption { // Deprecated: use Run instead. // RunContainer creates an instance of the Artemis container type. func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*Container, error) { - return Run(ctx, "docker.io/apache/activemq-artemis:2.30.0-alpine", opts...) + return Run(ctx, "apache/activemq-artemis:2.30.0-alpine", opts...) } // Run creates an instance of the Artemis container type with a given image diff --git a/modules/artemis/artemis_test.go b/modules/artemis/artemis_test.go index 8396b562f5..70dcab9440 100644 --- a/modules/artemis/artemis_test.go +++ b/modules/artemis/artemis_test.go @@ -65,7 +65,7 @@ func TestArtemis(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - ctr, err := artemis.Run(ctx, "docker.io/apache/activemq-artemis:2.30.0-alpine", test.opts...) + ctr, err := artemis.Run(ctx, "apache/activemq-artemis:2.30.0-alpine", test.opts...) testcontainers.CleanupContainer(t, ctr) require.NoError(t, err) diff --git a/modules/artemis/examples_test.go b/modules/artemis/examples_test.go index 78f8c2d13d..04e973a013 100644 --- a/modules/artemis/examples_test.go +++ b/modules/artemis/examples_test.go @@ -16,7 +16,7 @@ func ExampleRun() { ctx := context.Background() artemisContainer, err := artemis.Run(ctx, - "docker.io/apache/activemq-artemis:2.30.0", + "apache/activemq-artemis:2.30.0", artemis.WithCredentials("test", "test"), ) defer func() { diff --git a/modules/compose/compose_api_test.go b/modules/compose/compose_api_test.go index e5f30a5257..e13c6ca937 100644 --- a/modules/compose/compose_api_test.go +++ b/modules/compose/compose_api_test.go @@ -440,7 +440,7 @@ func TestDockerComposeAPIWithStackReader(t *testing.T) { composeContent := ` services: api-nginx: - image: docker.io/nginx:stable-alpine + image: nginx:stable-alpine environment: bar: ${bar} foo: ${foo} @@ -481,7 +481,7 @@ func TestDockerComposeAPIWithStackReaderAndComposeFile(t *testing.T) { composeContent := ` services: api-postgres: - image: docker.io/postgres:14 + image: postgres:14 environment: POSTGRES_PASSWORD: s3cr3t ` diff --git a/modules/compose/testdata/docker-compose-complex.yml b/modules/compose/testdata/docker-compose-complex.yml index fe0636dff2..d84f39ec16 100644 --- a/modules/compose/testdata/docker-compose-complex.yml +++ b/modules/compose/testdata/docker-compose-complex.yml @@ -1,10 +1,10 @@ services: {{ .ServiceType }}-nginx: - image: docker.io/nginx:stable-alpine + image: nginx:stable-alpine ports: - "{{ .Port_0 }}:80" {{ .ServiceType }}-mysql: - image: docker.io/mysql:8.0.36 + image: mysql:8.0.36 environment: - MYSQL_DATABASE=db - MYSQL_ROOT_PASSWORD=my-secret-pw diff --git a/modules/compose/testdata/docker-compose-container-name.yml b/modules/compose/testdata/docker-compose-container-name.yml index c46ca68888..d36bf96c87 100644 --- a/modules/compose/testdata/docker-compose-container-name.yml +++ b/modules/compose/testdata/docker-compose-container-name.yml @@ -1,7 +1,7 @@ services: {{ .ServiceType }}-nginx: container_name: {{ .ServiceType }}-nginxy - image: docker.io/nginx:stable-alpine + image: nginx:stable-alpine environment: bar: ${bar} ports: diff --git a/modules/compose/testdata/docker-compose-no-exposed-ports.yml b/modules/compose/testdata/docker-compose-no-exposed-ports.yml index 3f487156c3..e59e1a6fe9 100644 --- a/modules/compose/testdata/docker-compose-no-exposed-ports.yml +++ b/modules/compose/testdata/docker-compose-no-exposed-ports.yml @@ -1,5 +1,5 @@ services: {{ .ServiceType }}-nginx: - image: docker.io/nginx:stable-alpine + image: nginx:stable-alpine ports: - "80" diff --git a/modules/compose/testdata/docker-compose-override.yml b/modules/compose/testdata/docker-compose-override.yml index c8714256e0..6112c8d595 100644 --- a/modules/compose/testdata/docker-compose-override.yml +++ b/modules/compose/testdata/docker-compose-override.yml @@ -1,8 +1,8 @@ services: {{ .ServiceType }}-nginx: - image: docker.io/nginx:stable-alpine + image: nginx:stable-alpine {{ .ServiceType }}-mysql: - image: docker.io/mysql:8.0.36 + image: mysql:8.0.36 environment: MYSQL_RANDOM_ROOT_PASSWORD: Y ports: diff --git a/modules/compose/testdata/docker-compose-postgres.yml b/modules/compose/testdata/docker-compose-postgres.yml index 9671a7bdb5..012c2e0fda 100644 --- a/modules/compose/testdata/docker-compose-postgres.yml +++ b/modules/compose/testdata/docker-compose-postgres.yml @@ -1,6 +1,6 @@ services: {{ .ServiceType }}-postgres: - image: docker.io/postgres:14 + image: postgres:14 environment: POSTGRES_PASSWORD: s3cr3t ports: diff --git a/modules/compose/testdata/docker-compose-profiles.yml b/modules/compose/testdata/docker-compose-profiles.yml index fdb92853e1..a58bf014d3 100644 --- a/modules/compose/testdata/docker-compose-profiles.yml +++ b/modules/compose/testdata/docker-compose-profiles.yml @@ -1,24 +1,24 @@ services: starts-always: - image: docker.io/nginx:stable-alpine + image: nginx:stable-alpine ports: - ":80" # profiles: none defined, therefore always starts. only-dev: - image: docker.io/nginx:stable-alpine + image: nginx:stable-alpine ports: - ":80" profiles: - dev dev-or-test: - image: docker.io/nginx:stable-alpine + image: nginx:stable-alpine ports: - ":80" profiles: - dev - test only-prod: - image: docker.io/nginx:stable-alpine + image: nginx:stable-alpine ports: - ":80" profiles: diff --git a/modules/compose/testdata/docker-compose-short-lifespan.yml b/modules/compose/testdata/docker-compose-short-lifespan.yml index 47fd1314bb..19486a792b 100644 --- a/modules/compose/testdata/docker-compose-short-lifespan.yml +++ b/modules/compose/testdata/docker-compose-short-lifespan.yml @@ -1,7 +1,7 @@ services: tzatziki: - image: docker.io/alpine:latest + image: alpine:latest command: "sleep 5" falafel: - image: docker.io/alpine:latest + image: alpine:latest command: "echo 'World is your canvas'" diff --git a/modules/compose/testdata/docker-compose-simple.yml b/modules/compose/testdata/docker-compose-simple.yml index ebf8a64b6f..a3aad440bc 100644 --- a/modules/compose/testdata/docker-compose-simple.yml +++ b/modules/compose/testdata/docker-compose-simple.yml @@ -1,6 +1,6 @@ services: {{ .ServiceType }}-nginx: - image: docker.io/nginx:stable-alpine + image: nginx:stable-alpine environment: bar: ${bar} foo: ${foo} diff --git a/modules/compose/testdata/docker-compose-volume.yml b/modules/compose/testdata/docker-compose-volume.yml index f284a71452..9f904d41d9 100644 --- a/modules/compose/testdata/docker-compose-volume.yml +++ b/modules/compose/testdata/docker-compose-volume.yml @@ -1,6 +1,6 @@ services: {{ .ServiceType }}-nginx: - image: docker.io/nginx:stable-alpine + image: nginx:stable-alpine volumes: - type: volume source: mydata diff --git a/modules/compose/testdata/echoserver.Dockerfile b/modules/compose/testdata/echoserver.Dockerfile index 546489ffac..aaf835f35a 100644 --- a/modules/compose/testdata/echoserver.Dockerfile +++ b/modules/compose/testdata/echoserver.Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.13-alpine +FROM golang:1.13-alpine WORKDIR /app diff --git a/modules/consul/consul.go b/modules/consul/consul.go index c374938c32..0084786afb 100644 --- a/modules/consul/consul.go +++ b/modules/consul/consul.go @@ -15,7 +15,7 @@ const ( const ( // Deprecated: it will be removed in the next major version. - DefaultBaseImage = "docker.io/hashicorp/consul:1.15" + DefaultBaseImage = "hashicorp/consul:1.15" ) // ConsulContainer represents the Consul container type used in the module. @@ -65,7 +65,7 @@ func WithConfigFile(configPath string) testcontainers.CustomizeRequestOption { // Deprecated: use Run instead // RunContainer creates an instance of the Consul container type func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*ConsulContainer, error) { - return Run(ctx, "docker.io/hashicorp/consul:1.15", opts...) + return Run(ctx, "hashicorp/consul:1.15", opts...) } // Run creates an instance of the Consul container type diff --git a/modules/consul/consul_test.go b/modules/consul/consul_test.go index 79b626d359..6f359b7261 100644 --- a/modules/consul/consul_test.go +++ b/modules/consul/consul_test.go @@ -39,7 +39,7 @@ func TestConsul(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - ctr, err := consul.Run(ctx, "docker.io/hashicorp/consul:1.15", test.opts...) + ctr, err := consul.Run(ctx, "hashicorp/consul:1.15", test.opts...) testcontainers.CleanupContainer(t, ctr) require.NoError(t, err) diff --git a/modules/consul/examples_test.go b/modules/consul/examples_test.go index 32d323fe3d..d833575880 100644 --- a/modules/consul/examples_test.go +++ b/modules/consul/examples_test.go @@ -15,7 +15,7 @@ func ExampleRun() { // runConsulContainer { ctx := context.Background() - consulContainer, err := consul.Run(ctx, "docker.io/hashicorp/consul:1.15") + consulContainer, err := consul.Run(ctx, "hashicorp/consul:1.15") defer func() { if err := testcontainers.TerminateContainer(consulContainer); err != nil { log.Printf("failed to terminate container: %s", err) @@ -43,7 +43,7 @@ func ExampleRun_connect() { // connectConsul { ctx := context.Background() - consulContainer, err := consul.Run(ctx, "docker.io/hashicorp/consul:1.15") + consulContainer, err := consul.Run(ctx, "hashicorp/consul:1.15") defer func() { if err := testcontainers.TerminateContainer(consulContainer); err != nil { log.Printf("failed to terminate container: %s", err) diff --git a/modules/k3s/k3s.go b/modules/k3s/k3s.go index 509719bd64..8a3625eb65 100644 --- a/modules/k3s/k3s.go +++ b/modules/k3s/k3s.go @@ -50,7 +50,7 @@ func WithManifest(manifestPath string) testcontainers.CustomizeRequestOption { // Deprecated: use Run instead // RunContainer creates an instance of the K3s container type func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*K3sContainer, error) { - return Run(ctx, "docker.io/rancher/k3s:v1.27.1-k3s1", opts...) + return Run(ctx, "rancher/k3s:v1.27.1-k3s1", opts...) } // Run creates an instance of the K3s container type diff --git a/modules/k3s/k3s_example_test.go b/modules/k3s/k3s_example_test.go index ef2ca36538..cd1c7afc7e 100644 --- a/modules/k3s/k3s_example_test.go +++ b/modules/k3s/k3s_example_test.go @@ -17,7 +17,7 @@ func ExampleRun() { // runK3sContainer { ctx := context.Background() - k3sContainer, err := k3s.Run(ctx, "docker.io/rancher/k3s:v1.27.1-k3s1") + k3sContainer, err := k3s.Run(ctx, "rancher/k3s:v1.27.1-k3s1") defer func() { if err := testcontainers.TerminateContainer(k3sContainer); err != nil { log.Printf("failed to terminate container: %s", err) diff --git a/modules/k3s/k3s_test.go b/modules/k3s/k3s_test.go index f3970a25da..d89121dde3 100644 --- a/modules/k3s/k3s_test.go +++ b/modules/k3s/k3s_test.go @@ -23,7 +23,7 @@ func Test_LoadImages(t *testing.T) { ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(3*time.Minute)) defer cancel() - k3sContainer, err := k3s.Run(ctx, "docker.io/rancher/k3s:v1.27.1-k3s1") + k3sContainer, err := k3s.Run(ctx, "rancher/k3s:v1.27.1-k3s1") testcontainers.CleanupContainer(t, k3sContainer) require.NoError(t, err) @@ -105,7 +105,7 @@ func getTestPodState(ctx context.Context, k8s *kubernetes.Clientset) (corev1.Con func Test_APIServerReady(t *testing.T) { ctx := context.Background() - k3sContainer, err := k3s.Run(ctx, "docker.io/rancher/k3s:v1.27.1-k3s1") + k3sContainer, err := k3s.Run(ctx, "rancher/k3s:v1.27.1-k3s1") testcontainers.CleanupContainer(t, k3sContainer) require.NoError(t, err) @@ -144,7 +144,7 @@ func Test_WithManifestOption(t *testing.T) { ctx := context.Background() k3sContainer, err := k3s.Run(ctx, - "docker.io/rancher/k3s:v1.27.1-k3s1", + "rancher/k3s:v1.27.1-k3s1", k3s.WithManifest("nginx-manifest.yaml"), testcontainers.WithWaitStrategy(wait.ForExec([]string{"kubectl", "wait", "pod", "nginx", "--for=condition=Ready"})), ) diff --git a/modules/minio/minio.go b/modules/minio/minio.go index 6907b1372b..88c4f365d5 100644 --- a/modules/minio/minio.go +++ b/modules/minio/minio.go @@ -59,7 +59,7 @@ func (c *MinioContainer) ConnectionString(ctx context.Context) (string, error) { // Deprecated: use Run instead // RunContainer creates an instance of the Minio container type func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*MinioContainer, error) { - return Run(ctx, "docker.io/minio/minio:RELEASE.2024-01-16T16-07-38Z", opts...) + return Run(ctx, "minio/minio:RELEASE.2024-01-16T16-07-38Z", opts...) } // Run creates an instance of the Minio container type diff --git a/modules/neo4j/examples_test.go b/modules/neo4j/examples_test.go index 6e8c42936a..51b11bf49a 100644 --- a/modules/neo4j/examples_test.go +++ b/modules/neo4j/examples_test.go @@ -16,7 +16,7 @@ func ExampleRun() { testPassword := "letmein!" neo4jContainer, err := neo4j.Run(ctx, - "docker.io/neo4j:4.4", + "neo4j:4.4", neo4j.WithAdminPassword(testPassword), neo4j.WithLabsPlugin(neo4j.Apoc), neo4j.WithNeo4jSetting("dbms.tx_log.rotation.size", "42M"), diff --git a/modules/neo4j/neo4j_test.go b/modules/neo4j/neo4j_test.go index d036fb8128..9d41e4afe5 100644 --- a/modules/neo4j/neo4j_test.go +++ b/modules/neo4j/neo4j_test.go @@ -63,8 +63,8 @@ func TestNeo4jWithEnterpriseLicense(t *testing.T) { ctx := context.Background() images := map[string]string{ - "StandardEdition": "docker.io/neo4j:4.4", - "EnterpriseEdition": "docker.io/neo4j:4.4-enterprise", + "StandardEdition": "neo4j:4.4", + "EnterpriseEdition": "neo4j:4.4-enterprise", } for edition, img := range images { diff --git a/modules/postgres/examples_test.go b/modules/postgres/examples_test.go index 8b7f562ea9..1f5b0e1c86 100644 --- a/modules/postgres/examples_test.go +++ b/modules/postgres/examples_test.go @@ -21,7 +21,7 @@ func ExampleRun() { dbPassword := "password" postgresContainer, err := postgres.Run(ctx, - "docker.io/postgres:16-alpine", + "postgres:16-alpine", postgres.WithInitScripts(filepath.Join("testdata", "init-user-db.sh")), postgres.WithConfigFile(filepath.Join("testdata", "my-postgres.conf")), postgres.WithDatabase(dbName), diff --git a/modules/postgres/postgres.go b/modules/postgres/postgres.go index ac51721f82..8bd32a49b7 100644 --- a/modules/postgres/postgres.go +++ b/modules/postgres/postgres.go @@ -136,7 +136,7 @@ func WithUsername(user string) testcontainers.CustomizeRequestOption { // Deprecated: use Run instead // RunContainer creates an instance of the Postgres container type func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*PostgresContainer, error) { - return Run(ctx, "docker.io/postgres:16-alpine", opts...) + return Run(ctx, "postgres:16-alpine", opts...) } // Run creates an instance of the Postgres container type diff --git a/modules/postgres/postgres_test.go b/modules/postgres/postgres_test.go index 7167da5c51..05b3f8110e 100644 --- a/modules/postgres/postgres_test.go +++ b/modules/postgres/postgres_test.go @@ -34,24 +34,24 @@ func TestPostgres(t *testing.T) { }{ { name: "Postgres", - image: "docker.io/postgres:15.2-alpine", + image: "postgres:15.2-alpine", }, { name: "Timescale", // timescale { - image: "docker.io/timescale/timescaledb:2.1.0-pg11", + image: "timescale/timescaledb:2.1.0-pg11", // } }, { name: "Postgis", // postgis { - image: "docker.io/postgis/postgis:12-3.0", + image: "postgis/postgis:12-3.0", // } }, { name: "Pgvector", // pgvector { - image: "docker.io/pgvector/pgvector:pg16", + image: "pgvector/pgvector:pg16", // } }, } @@ -112,7 +112,7 @@ func TestContainerWithWaitForSQL(t *testing.T) { t.Run("default query", func(t *testing.T) { ctr, err := postgres.Run( ctx, - "docker.io/postgres:16-alpine", + "postgres:16-alpine", postgres.WithDatabase(dbname), postgres.WithUsername(user), postgres.WithPassword(password), @@ -125,7 +125,7 @@ func TestContainerWithWaitForSQL(t *testing.T) { t.Run("custom query", func(t *testing.T) { ctr, err := postgres.Run( ctx, - "docker.io/postgres:16-alpine", + "postgres:16-alpine", postgres.WithDatabase(dbname), postgres.WithUsername(user), postgres.WithPassword(password), @@ -138,7 +138,7 @@ func TestContainerWithWaitForSQL(t *testing.T) { t.Run("custom bad query", func(t *testing.T) { ctr, err := postgres.Run( ctx, - "docker.io/postgres:16-alpine", + "postgres:16-alpine", postgres.WithDatabase(dbname), postgres.WithUsername(user), postgres.WithPassword(password), @@ -153,7 +153,7 @@ func TestWithConfigFile(t *testing.T) { ctx := context.Background() ctr, err := postgres.Run(ctx, - "docker.io/postgres:16-alpine", + "postgres:16-alpine", postgres.WithConfigFile(filepath.Join("testdata", "my-postgres.conf")), postgres.WithDatabase(dbname), postgres.WithUsername(user), @@ -177,7 +177,7 @@ func TestWithInitScript(t *testing.T) { ctx := context.Background() ctr, err := postgres.Run(ctx, - "docker.io/postgres:15.2-alpine", + "postgres:15.2-alpine", postgres.WithInitScripts(filepath.Join("testdata", "init-user-db.sh")), postgres.WithDatabase(dbname), postgres.WithUsername(user), @@ -228,7 +228,7 @@ func TestSnapshot(t *testing.T) { // 1. Start the postgres ctr and run any migrations on it ctr, err := postgres.Run( ctx, - "docker.io/postgres:16-alpine", + "postgres:16-alpine", postgres.WithDatabase(dbname), postgres.WithUsername(user), postgres.WithPassword(password), @@ -303,7 +303,7 @@ func TestSnapshotWithOverrides(t *testing.T) { ctr, err := postgres.Run( ctx, - "docker.io/postgres:16-alpine", + "postgres:16-alpine", postgres.WithDatabase(dbname), postgres.WithUsername(user), postgres.WithPassword(password), @@ -349,7 +349,7 @@ func TestSnapshotDuplicate(t *testing.T) { ctr, err := postgres.Run( ctx, - "docker.io/postgres:16-alpine", + "postgres:16-alpine", postgres.WithDatabase(dbname), postgres.WithUsername(user), postgres.WithPassword(password), @@ -375,7 +375,7 @@ func TestSnapshotWithDockerExecFallback(t *testing.T) { // 1. Start the postgres container and run any migrations on it ctr, err := postgres.Run( ctx, - "docker.io/postgres:16-alpine", + "postgres:16-alpine", postgres.WithDatabase(dbname), postgres.WithUsername(user), postgres.WithPassword(password), diff --git a/modules/pulsar/examples_test.go b/modules/pulsar/examples_test.go index ad871f1494..9561914207 100644 --- a/modules/pulsar/examples_test.go +++ b/modules/pulsar/examples_test.go @@ -13,7 +13,7 @@ func ExampleRun() { // runPulsarContainer { ctx := context.Background() - pulsarContainer, err := pulsar.Run(ctx, "docker.io/apachepulsar/pulsar:2.10.2") + pulsarContainer, err := pulsar.Run(ctx, "apachepulsar/pulsar:2.10.2") defer func() { if err := testcontainers.TerminateContainer(pulsarContainer); err != nil { log.Printf("failed to terminate container: %s", err) diff --git a/modules/pulsar/pulsar.go b/modules/pulsar/pulsar.go index 26c57b5742..be9ea10925 100644 --- a/modules/pulsar/pulsar.go +++ b/modules/pulsar/pulsar.go @@ -132,12 +132,12 @@ func WithTransactions() testcontainers.CustomizeRequestOption { // Deprecated: use Run instead // RunContainer creates an instance of the Pulsar container type func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*Container, error) { - return Run(ctx, "docker.io/apachepulsar/pulsar:2.10.2", opts...) + return Run(ctx, "apachepulsar/pulsar:2.10.2", opts...) } // Run creates an instance of the Pulsar container type, being possible to pass a custom request and options // The created container will use the following defaults: -// - image: docker.io/apachepulsar/pulsar:2.10.2 +// - image: apachepulsar/pulsar:2.10.2 // - exposed ports: 6650/tcp, 8080/tcp // - waiting strategy: wait for all the following strategies: // - the Pulsar admin API ("/admin/v2/clusters") to be ready on port 8080/tcp and return the response `["standalone"]` diff --git a/modules/pulsar/pulsar_test.go b/modules/pulsar/pulsar_test.go index cd04284913..8cea6a4119 100644 --- a/modules/pulsar/pulsar_test.go +++ b/modules/pulsar/pulsar_test.go @@ -98,7 +98,7 @@ func TestPulsar(t *testing.T) { t.Run(tt.name, func(t *testing.T) { c, err := testcontainerspulsar.Run( ctx, - "docker.io/apachepulsar/pulsar:2.10.2", + "apachepulsar/pulsar:2.10.2", tt.opts..., ) testcontainers.CleanupContainer(t, c) diff --git a/modules/redis/examples_test.go b/modules/redis/examples_test.go index e5e83a01a1..86be00be85 100644 --- a/modules/redis/examples_test.go +++ b/modules/redis/examples_test.go @@ -15,7 +15,7 @@ func ExampleRun() { ctx := context.Background() redisContainer, err := redis.Run(ctx, - "docker.io/redis:7", + "redis:7", redis.WithSnapshotting(10, 1), redis.WithLogLevel(redis.LogLevelVerbose), redis.WithConfigFile(filepath.Join("testdata", "redis7.conf")), diff --git a/modules/redis/redis.go b/modules/redis/redis.go index df75ad7311..d834a6c46d 100644 --- a/modules/redis/redis.go +++ b/modules/redis/redis.go @@ -46,7 +46,7 @@ func (c *RedisContainer) ConnectionString(ctx context.Context) (string, error) { // Deprecated: use Run instead // RunContainer creates an instance of the Redis container type func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*RedisContainer, error) { - return Run(ctx, "docker.io/redis:7", opts...) + return Run(ctx, "redis:7", opts...) } // Run creates an instance of the Redis container type diff --git a/modules/redis/redis_test.go b/modules/redis/redis_test.go index 4a872a0a87..58d1c14c9c 100644 --- a/modules/redis/redis_test.go +++ b/modules/redis/redis_test.go @@ -18,7 +18,7 @@ import ( func TestIntegrationSetGet(t *testing.T) { ctx := context.Background() - redisContainer, err := tcredis.Run(ctx, "docker.io/redis:7") + redisContainer, err := tcredis.Run(ctx, "redis:7") testcontainers.CleanupContainer(t, redisContainer) require.NoError(t, err) @@ -28,7 +28,7 @@ func TestIntegrationSetGet(t *testing.T) { func TestRedisWithConfigFile(t *testing.T) { ctx := context.Background() - redisContainer, err := tcredis.Run(ctx, "docker.io/redis:7", tcredis.WithConfigFile(filepath.Join("testdata", "redis7.conf"))) + redisContainer, err := tcredis.Run(ctx, "redis:7", tcredis.WithConfigFile(filepath.Join("testdata", "redis7.conf"))) testcontainers.CleanupContainer(t, redisContainer) require.NoError(t, err) @@ -44,22 +44,22 @@ func TestRedisWithImage(t *testing.T) { }{ { name: "Redis6", - image: "docker.io/redis:6", + image: "redis:6", }, { name: "Redis7", - image: "docker.io/redis:7", + image: "redis:7", }, { name: "Redis Stack", // redisStackImage { - image: "docker.io/redis/redis-stack:latest", + image: "redis/redis-stack:latest", // } }, { name: "Redis Stack Server", // redisStackServerImage { - image: "docker.io/redis/redis-stack-server:latest", + image: "redis/redis-stack-server:latest", // } }, } @@ -78,7 +78,7 @@ func TestRedisWithImage(t *testing.T) { func TestRedisWithLogLevel(t *testing.T) { ctx := context.Background() - redisContainer, err := tcredis.Run(ctx, "docker.io/redis:7", tcredis.WithLogLevel(tcredis.LogLevelVerbose)) + redisContainer, err := tcredis.Run(ctx, "redis:7", tcredis.WithLogLevel(tcredis.LogLevelVerbose)) testcontainers.CleanupContainer(t, redisContainer) require.NoError(t, err) @@ -88,7 +88,7 @@ func TestRedisWithLogLevel(t *testing.T) { func TestRedisWithSnapshotting(t *testing.T) { ctx := context.Background() - redisContainer, err := tcredis.Run(ctx, "docker.io/redis:7", tcredis.WithSnapshotting(10, 1)) + redisContainer, err := tcredis.Run(ctx, "redis:7", tcredis.WithSnapshotting(10, 1)) testcontainers.CleanupContainer(t, redisContainer) require.NoError(t, err) diff --git a/modules/redis/testdata/Dockerfile b/modules/redis/testdata/Dockerfile index 7157611a13..14cfaf1e23 100644 --- a/modules/redis/testdata/Dockerfile +++ b/modules/redis/testdata/Dockerfile @@ -1 +1 @@ -FROM docker.io/redis:5.0-alpine@sha256:1a3c609295332f1ce603948142a132656c92a08149d7096e203058533c415b8c +FROM redis:5.0-alpine@sha256:1a3c609295332f1ce603948142a132656c92a08149d7096e203058533c415b8c diff --git a/modules/valkey/examples_test.go b/modules/valkey/examples_test.go index 7e1d261850..c700e8d3f3 100644 --- a/modules/valkey/examples_test.go +++ b/modules/valkey/examples_test.go @@ -15,7 +15,7 @@ func ExampleRun() { ctx := context.Background() valkeyContainer, err := valkey.Run(ctx, - "docker.io/valkey/valkey:7.2.5", + "valkey/valkey:7.2.5", valkey.WithSnapshotting(10, 1), valkey.WithLogLevel(valkey.LogLevelVerbose), valkey.WithConfigFile(filepath.Join("testdata", "valkey7.conf")), diff --git a/modules/valkey/valkey.go b/modules/valkey/valkey.go index 00f4e91186..e8da1ed0e2 100644 --- a/modules/valkey/valkey.go +++ b/modules/valkey/valkey.go @@ -48,7 +48,7 @@ func (c *ValkeyContainer) ConnectionString(ctx context.Context) (string, error) // Deprecated: use Run instead // RunContainer creates an instance of the Valkey container type func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomizer) (*ValkeyContainer, error) { - return Run(ctx, "docker.io/valkey/valkey:7.2.5", opts...) + return Run(ctx, "valkey/valkey:7.2.5", opts...) } // Run creates an instance of the Valkey container type diff --git a/modules/valkey/valkey_test.go b/modules/valkey/valkey_test.go index 484c75dabe..26e2ea93b8 100644 --- a/modules/valkey/valkey_test.go +++ b/modules/valkey/valkey_test.go @@ -18,7 +18,7 @@ import ( func TestIntegrationSetGet(t *testing.T) { ctx := context.Background() - valkeyContainer, err := tcvalkey.Run(ctx, "docker.io/valkey/valkey:7.2.5") + valkeyContainer, err := tcvalkey.Run(ctx, "valkey/valkey:7.2.5") testcontainers.CleanupContainer(t, valkeyContainer) require.NoError(t, err) @@ -28,7 +28,7 @@ func TestIntegrationSetGet(t *testing.T) { func TestValkeyWithConfigFile(t *testing.T) { ctx := context.Background() - valkeyContainer, err := tcvalkey.Run(ctx, "docker.io/valkey/valkey:7.2.5", tcvalkey.WithConfigFile(filepath.Join("testdata", "valkey7.conf"))) + valkeyContainer, err := tcvalkey.Run(ctx, "valkey/valkey:7.2.5", tcvalkey.WithConfigFile(filepath.Join("testdata", "valkey7.conf"))) testcontainers.CleanupContainer(t, valkeyContainer) require.NoError(t, err) @@ -45,7 +45,7 @@ func TestValkeyWithImage(t *testing.T) { // There is only one release of Valkey at the time of writing { name: "Valkey7.2.5", - image: "docker.io/valkey/valkey:7.2.5", + image: "valkey/valkey:7.2.5", }, } @@ -63,7 +63,7 @@ func TestValkeyWithImage(t *testing.T) { func TestValkeyWithLogLevel(t *testing.T) { ctx := context.Background() - valkeyContainer, err := tcvalkey.Run(ctx, "docker.io/valkey/valkey:7.2.5", tcvalkey.WithLogLevel(tcvalkey.LogLevelVerbose)) + valkeyContainer, err := tcvalkey.Run(ctx, "valkey/valkey:7.2.5", tcvalkey.WithLogLevel(tcvalkey.LogLevelVerbose)) testcontainers.CleanupContainer(t, valkeyContainer) require.NoError(t, err) @@ -73,7 +73,7 @@ func TestValkeyWithLogLevel(t *testing.T) { func TestValkeyWithSnapshotting(t *testing.T) { ctx := context.Background() - valkeyContainer, err := tcvalkey.Run(ctx, "docker.io/valkey/valkey:7.2.5", tcvalkey.WithSnapshotting(10, 1)) + valkeyContainer, err := tcvalkey.Run(ctx, "valkey/valkey:7.2.5", tcvalkey.WithSnapshotting(10, 1)) testcontainers.CleanupContainer(t, valkeyContainer) require.NoError(t, err) diff --git a/network/network_test.go b/network/network_test.go index 5cee817ecc..bbe5d45c7c 100644 --- a/network/network_test.go +++ b/network/network_test.go @@ -16,7 +16,7 @@ import ( ) const ( - nginxAlpineImage = "docker.io/nginx:alpine" + nginxAlpineImage = "nginx:alpine" nginxDefaultPort = "80/tcp" ) @@ -37,7 +37,7 @@ func TestNew(t *testing.T) { nginxC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ - Image: "nginx:alpine", + Image: nginxAlpineImage, ExposedPorts: []string{ "80/tcp", }, @@ -275,7 +275,7 @@ func TestNew_withOptions(t *testing.T) { nginx, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ - Image: "nginx:alpine", + Image: nginxAlpineImage, ExposedPorts: []string{ "80/tcp", }, diff --git a/options.go b/options.go index 2849b15667..4eb39058c8 100644 --- a/options.go +++ b/options.go @@ -186,7 +186,7 @@ func (p prependHubRegistry) Description() string { // - if the prefix is empty, the image is returned as is. // - if the image is a non-hub image (e.g. where another registry is set), the image is returned as is. // - if the image is a Docker Hub image where the hub registry is explicitly part of the name -// (i.e. anything with a docker.io or registry.hub.docker.com host part), the image is returned as is. +// (i.e. anything with a registry.hub.docker.com host part), the image is returned as is. func (p prependHubRegistry) Substitute(image string) (string, error) { registry := core.ExtractRegistry(image, "") diff --git a/scripts/bump-reaper.sh b/scripts/bump-reaper.sh index 34d17ce463..86af6b31c0 100755 --- a/scripts/bump-reaper.sh +++ b/scripts/bump-reaper.sh @@ -5,11 +5,11 @@ # dry-run mode, which will print the commands that would be executed, without actually # executing them. # -# Usage: ./scripts/bump-reaper.sh "docker.io/testcontainers/ryuk:1.2.3" +# Usage: ./scripts/bump-reaper.sh "testcontainers/ryuk:1.2.3" # # It's possible to run the script without dry-run mode actually executing the commands. # -# Usage: DRY_RUN="false" ./scripts/bump-reaper.sh "docker.io/testcontainers/ryuk:1.2.3" +# Usage: DRY_RUN="false" ./scripts/bump-reaper.sh "testcontainers/ryuk:1.2.3" readonly CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" readonly DRY_RUN="${DRY_RUN:-true}" diff --git a/scripts/release.sh b/scripts/release.sh index 6709c5c358..b675cb51e2 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -13,7 +13,7 @@ # Usage: DRY_RUN="false" ./scripts/release.sh readonly BUMP_TYPE="${BUMP_TYPE:-minor}" -readonly DOCKER_IMAGE_SEMVER="docker.io/mdelapenya/semver-tool:3.4.0" +readonly DOCKER_IMAGE_SEMVER="mdelapenya/semver-tool:3.4.0" readonly DRY_RUN="${DRY_RUN:-true}" readonly CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" readonly ROOT_DIR="$(dirname "$CURRENT_DIR")" diff --git a/testdata/Dockerfile b/testdata/Dockerfile index 7157611a13..14cfaf1e23 100644 --- a/testdata/Dockerfile +++ b/testdata/Dockerfile @@ -1 +1 @@ -FROM docker.io/redis:5.0-alpine@sha256:1a3c609295332f1ce603948142a132656c92a08149d7096e203058533c415b8c +FROM redis:5.0-alpine@sha256:1a3c609295332f1ce603948142a132656c92a08149d7096e203058533c415b8c diff --git a/testdata/args.Dockerfile b/testdata/args.Dockerfile index 984ef51eee..0260639719 100644 --- a/testdata/args.Dockerfile +++ b/testdata/args.Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.13-alpine +FROM golang:1.13-alpine ARG FOO diff --git a/testdata/buildlog.Dockerfile b/testdata/buildlog.Dockerfile index 0a9bc82c98..67fd379018 100644 --- a/testdata/buildlog.Dockerfile +++ b/testdata/buildlog.Dockerfile @@ -1 +1 @@ -FROM docker.io/alpine +FROM alpine diff --git a/testdata/echo.Dockerfile b/testdata/echo.Dockerfile index 10ab9febf4..36951e1aa6 100644 --- a/testdata/echo.Dockerfile +++ b/testdata/echo.Dockerfile @@ -1,3 +1,3 @@ -FROM docker.io/alpine +FROM alpine CMD ["echo", "this is from the echo test Dockerfile"] \ No newline at end of file diff --git a/testdata/echoserver.Dockerfile b/testdata/echoserver.Dockerfile index 546489ffac..aaf835f35a 100644 --- a/testdata/echoserver.Dockerfile +++ b/testdata/echoserver.Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/golang:1.13-alpine +FROM golang:1.13-alpine WORKDIR /app diff --git a/testdata/error.Dockerfile b/testdata/error.Dockerfile index 1284e7285f..5d31293182 100644 --- a/testdata/error.Dockerfile +++ b/testdata/error.Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/alpine +FROM alpine RUN exit 1 diff --git a/testdata/target.Dockerfile b/testdata/target.Dockerfile index 996a83552f..f6a20273c7 100644 --- a/testdata/target.Dockerfile +++ b/testdata/target.Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/alpine AS target0 +FROM alpine AS target0 CMD ["echo", "target0"] FROM target0 AS target1 diff --git a/testhelpers_test.go b/testhelpers_test.go index 4f268a8aee..8d7587c17c 100644 --- a/testhelpers_test.go +++ b/testhelpers_test.go @@ -1,6 +1,6 @@ package testcontainers_test const ( - nginxAlpineImage = "docker.io/nginx:alpine" + nginxAlpineImage = "nginx:alpine" nginxDefaultPort = "80/tcp" ) diff --git a/wait/exec_test.go b/wait/exec_test.go index 8a82fb0211..4d2d97c51d 100644 --- a/wait/exec_test.go +++ b/wait/exec_test.go @@ -192,7 +192,7 @@ func TestExecStrategyWaitUntilReady_withExitCode(t *testing.T) { func TestExecStrategyWaitUntilReady_CustomResponseMatcher(t *testing.T) { // waitForExecExitCodeResponse { dockerReq := testcontainers.ContainerRequest{ - Image: "docker.io/nginx:latest", + Image: "nginx:latest", WaitingFor: wait.ForExec([]string{"echo", "hello world!"}). WithStartupTimeout(time.Second * 10). WithExitCodeMatcher(func(exitCode int) bool { diff --git a/wait/file_test.go b/wait/file_test.go index a25d8aa65f..22133ba349 100644 --- a/wait/file_test.go +++ b/wait/file_test.go @@ -79,7 +79,7 @@ func TestFileStrategyWaitUntilReady_WithMatcher(t *testing.T) { // waitForFileWithMatcher { var out bytes.Buffer dockerReq := testcontainers.ContainerRequest{ - Image: "docker.io/nginx:latest", + Image: "nginx:latest", WaitingFor: wait.ForFile("/etc/nginx/nginx.conf"). WithStartupTimeout(time.Second * 10). WithPollInterval(time.Second). From b7511cd05427318872e29e3b7b8e6ad4d2ec6889 Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 28 Oct 2024 10:25:18 +0100 Subject: [PATCH 2/4] chore: use require.(No)Error(t,err) instead of t.Fatal(err) (#2851) Signed-off-by: Matthieu MOREL --- container_file_test.go | 6 +- docker_files_test.go | 36 +--- docker_test.go | 184 +++++--------------- file_test.go | 36 +--- from_dockerfile_test.go | 24 +-- image_substitutors_test.go | 46 ++--- image_test.go | 6 +- lifecycle_test.go | 8 +- logconsumer_test.go | 29 +-- modules/cassandra/cassandra_test.go | 12 +- modules/dolt/dolt_test.go | 8 +- modules/elasticsearch/elasticsearch_test.go | 14 +- modules/k6/k6_test.go | 8 +- modules/neo4j/neo4j_test.go | 8 +- modules/rabbitmq/rabbitmq_test.go | 29 +-- modules/weaviate/weaviate_test.go | 20 +-- wait/exec_test.go | 20 +-- wait/exit_test.go | 5 +- wait/host_port_test.go | 50 ++---- wait/sql_test.go | 6 +- 20 files changed, 150 insertions(+), 405 deletions(-) diff --git a/container_file_test.go b/container_file_test.go index 31273c9966..166225f327 100644 --- a/container_file_test.go +++ b/container_file_test.go @@ -7,6 +7,8 @@ import ( "os" "path/filepath" "testing" + + "github.com/stretchr/testify/require" ) func TestContainerFileValidation(t *testing.T) { @@ -17,9 +19,7 @@ func TestContainerFileValidation(t *testing.T) { } f, err := os.Open(filepath.Join(".", "testdata", "hello.sh")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) testTable := []ContainerFileValidationTestCase{ { diff --git a/docker_files_test.go b/docker_files_test.go index 9b8551f325..6b32168081 100644 --- a/docker_files_test.go +++ b/docker_files_test.go @@ -21,14 +21,10 @@ func TestCopyFileToContainer(t *testing.T) { // copyFileOnCreate { absPath, err := filepath.Abs(filepath.Join(".", "testdata", "hello.sh")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) r, err := os.Open(absPath) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ @@ -58,13 +54,9 @@ func TestCopyFileToRunningContainer(t *testing.T) { // Not using the assertations here to avoid leaking the library into the example // copyFileAfterCreate { waitForPath, err := filepath.Abs(filepath.Join(".", "testdata", "waitForHello.sh")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) helloPath, err := filepath.Abs(filepath.Join(".", "testdata", "hello.sh")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ @@ -100,9 +92,7 @@ func TestCopyDirectoryToContainer(t *testing.T) { // Not using the assertations here to avoid leaking the library into the example // copyDirectoryToContainer { dataDirectory, err := filepath.Abs(filepath.Join(".", "testdata")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ @@ -133,13 +123,9 @@ func TestCopyDirectoryToRunningContainerAsFile(t *testing.T) { // copyDirectoryToRunningContainerAsFile { dataDirectory, err := filepath.Abs(filepath.Join(".", "testdata")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) waitForPath, err := filepath.Abs(filepath.Join(dataDirectory, "waitForHello.sh")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ @@ -175,13 +161,9 @@ func TestCopyDirectoryToRunningContainerAsDir(t *testing.T) { // Not using the assertations here to avoid leaking the library into the example // copyDirectoryToRunningContainerAsDir { waitForPath, err := filepath.Abs(filepath.Join(".", "testdata", "waitForHello.sh")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) dataDirectory, err := filepath.Abs(filepath.Join(".", "testdata")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ctr, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: testcontainers.ContainerRequest{ diff --git a/docker_test.go b/docker_test.go index 2cc762a6aa..a9fcbd03d6 100644 --- a/docker_test.go +++ b/docker_test.go @@ -55,9 +55,7 @@ func TestContainerWithHostNetworkOptions(t *testing.T) { SkipIfDockerDesktop(t, ctx) absPath, err := filepath.Abs(filepath.Join("testdata", "nginx-highport.conf")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) gcr := GenericContainerRequest{ ProviderType: providerType, @@ -114,9 +112,7 @@ func TestContainerWithHostNetworkOptions_UseExposePortsFromImageConfigs(t *testi nginxC, err := GenericContainer(ctx, gcr) CleanupContainer(t, nginxC) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) endpoint, err := nginxC.Endpoint(ctx, "http") if err != nil { @@ -124,9 +120,7 @@ func TestContainerWithHostNetworkOptions_UseExposePortsFromImageConfigs(t *testi } resp, err := http.Get(endpoint) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { @@ -173,9 +167,7 @@ func TestContainerWithHostNetwork(t *testing.T) { SkipIfDockerDesktop(t, ctx) absPath, err := filepath.Abs(filepath.Join("testdata", "nginx-highport.conf")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) gcr := GenericContainerRequest{ ProviderType: providerType, @@ -334,9 +326,7 @@ func TestContainerTerminationRemovesDockerImage(t *testing.T) { t.Run("if not built from Dockerfile", func(t *testing.T) { ctx := context.Background() dockerClient, err := NewDockerClientWithOpts(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer dockerClient.Close() ctr, err := GenericContainer(ctx, GenericContainerRequest{ @@ -364,9 +354,7 @@ func TestContainerTerminationRemovesDockerImage(t *testing.T) { t.Run("if built from Dockerfile", func(t *testing.T) { ctx := context.Background() dockerClient, err := NewDockerClientWithOpts(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer dockerClient.Close() req := ContainerRequest{ @@ -382,20 +370,14 @@ func TestContainerTerminationRemovesDockerImage(t *testing.T) { Started: true, }) CleanupContainer(t, ctr) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) containerID := ctr.GetContainerID() resp, err := dockerClient.ContainerInspect(ctx, containerID) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) imageID := resp.Config.Image err = ctr.Terminate(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, _, err = dockerClient.ImageInspectWithRaw(ctx, imageID) if err == nil { @@ -438,9 +420,7 @@ func TestTwoContainersExposingTheSamePort(t *testing.T) { require.NoError(t, err) resp, err := http.Get(endpointA) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { @@ -448,14 +428,10 @@ func TestTwoContainersExposingTheSamePort(t *testing.T) { } endpointB, err := nginxB.PortEndpoint(ctx, nginxDefaultPort, "http") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) resp, err = http.Get(endpointB) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { @@ -484,25 +460,19 @@ func TestContainerCreation(t *testing.T) { require.NoError(t, err) resp, err := http.Get(endpoint) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Errorf("Expected status code %d. Got %d.", http.StatusOK, resp.StatusCode) } networkIP, err := nginxC.ContainerIP(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if len(networkIP) == 0 { t.Errorf("Expected an IP address, got %v", networkIP) } networkAliases, err := nginxC.NetworkAliases(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if len(networkAliases) != 1 { fmt.Printf("%v", networkAliases) t.Errorf("Expected number of connected networks %d. Got %d.", 0, len(networkAliases)) @@ -536,18 +506,14 @@ func TestContainerCreationWithName(t *testing.T) { require.NoError(t, err) inspect, err := nginxC.Inspect(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) name := inspect.Name if name != expectedName { t.Errorf("Expected container name '%s'. Got '%s'.", expectedName, name) } networks, err := nginxC.Networks(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if len(networks) != 1 { t.Errorf("Expected networks 1. Got '%d'.", len(networks)) } @@ -567,9 +533,7 @@ func TestContainerCreationWithName(t *testing.T) { require.NoError(t, err) resp, err := http.Get(endpoint) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { @@ -596,13 +560,9 @@ func TestContainerCreationAndWaitForListeningPortLongEnough(t *testing.T) { require.NoError(t, err) origin, err := nginxC.PortEndpoint(ctx, nginxDefaultPort, "http") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) resp, err := http.Get(origin) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { @@ -649,13 +609,9 @@ func TestContainerRespondsWithHttp200ForIndex(t *testing.T) { require.NoError(t, err) origin, err := nginxC.PortEndpoint(ctx, nginxDefaultPort, "http") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) resp, err := http.Get(origin) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { @@ -1134,9 +1090,7 @@ func ExampleContainer_MappedPort() { func TestContainerCreationWithVolumeAndFileWritingToIt(t *testing.T) { absPath, err := filepath.Abs(filepath.Join(".", "testdata", "hello.sh")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ctx, cnl := context.WithTimeout(context.Background(), 30*time.Second) defer cnl() @@ -1184,18 +1138,14 @@ func TestContainerWithTmpFs(t *testing.T) { // exec_reader_example { c, reader, err := ctr.Exec(ctx, []string{"ls", path}) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if c != 1 { t.Fatalf("File %s should not have existed, expected return code 1, got %v", path, c) } buf := new(strings.Builder) _, err = io.Copy(buf, reader) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // See the logs from the command execution. t.Log(buf.String()) @@ -1203,18 +1153,14 @@ func TestContainerWithTmpFs(t *testing.T) { // exec_example { c, _, err = ctr.Exec(ctx, []string{"touch", path}) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if c != 0 { t.Fatalf("File %s should have been created successfully, expected return code 0, got %v", path, c) } // } c, _, err = ctr.Exec(ctx, []string{"ls", path}) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if c != 0 { t.Fatalf("File %s should exist, expected return code 0, got %v", path, c) } @@ -1393,9 +1339,7 @@ func TestDockerContainerCopyFileToContainer(t *testing.T) { _ = nginxC.CopyFileToContainer(ctx, filepath.Join(".", "testdata", "hello.sh"), tc.copiedFileName, 700) c, _, err := nginxC.Exec(ctx, []string{"bash", tc.copiedFileName}) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if c != 0 { t.Fatalf("File %s should exist, expected return code 0, got %v", tc.copiedFileName, c) } @@ -1424,9 +1368,7 @@ func TestDockerContainerCopyDirToContainer(t *testing.T) { p = filepath.Join(".", "testdata") err = nginxC.CopyDirToContainer(ctx, p, "/tmp/testdata", 700) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) assertExtractedFiles(t, ctx, nginxC, p, "/tmp/testdata/") } @@ -1604,17 +1546,11 @@ func TestDockerContainerCopyToContainer(t *testing.T) { require.NoError(t, err) fileContent, err := os.ReadFile(filepath.Join(".", "testdata", "hello.sh")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) err = nginxC.CopyToContainer(ctx, fileContent, tc.copiedFileName, 700) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) c, _, err := nginxC.Exec(ctx, []string{"bash", tc.copiedFileName}) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if c != 0 { t.Fatalf("File %s should exist, expected return code 0, got %v", tc.copiedFileName, c) } @@ -1624,9 +1560,7 @@ func TestDockerContainerCopyToContainer(t *testing.T) { func TestDockerContainerCopyFileFromContainer(t *testing.T) { fileContent, err := os.ReadFile(filepath.Join(".", "testdata", "hello.sh")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) ctx := context.Background() nginxC, err := GenericContainer(ctx, GenericContainerRequest{ @@ -1644,23 +1578,17 @@ func TestDockerContainerCopyFileFromContainer(t *testing.T) { copiedFileName := "hello_copy.sh" _ = nginxC.CopyFileToContainer(ctx, filepath.Join(".", "testdata", "hello.sh"), "/"+copiedFileName, 700) c, _, err := nginxC.Exec(ctx, []string{"bash", copiedFileName}) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if c != 0 { t.Fatalf("File %s should exist, expected return code 0, got %v", copiedFileName, c) } reader, err := nginxC.CopyFileFromContainer(ctx, "/"+copiedFileName) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer reader.Close() fileContentFromContainer, err := io.ReadAll(reader) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) assert.Equal(t, fileContent, fileContentFromContainer) } @@ -1682,23 +1610,17 @@ func TestDockerContainerCopyEmptyFileFromContainer(t *testing.T) { copiedFileName := "hello_copy.sh" _ = nginxC.CopyFileToContainer(ctx, filepath.Join(".", "testdata", "empty.sh"), "/"+copiedFileName, 700) c, _, err := nginxC.Exec(ctx, []string{"bash", copiedFileName}) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if c != 0 { t.Fatalf("File %s should exist, expected return code 0, got %v", copiedFileName, c) } reader, err := nginxC.CopyFileFromContainer(ctx, "/"+copiedFileName) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer reader.Close() fileContentFromContainer, err := io.ReadAll(reader) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) require.Empty(t, fileContentFromContainer) } @@ -1809,9 +1731,7 @@ func TestContainerRunningCheckingStatusCode(t *testing.T) { Started: true, }) CleanupContainer(t, influx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } func TestContainerWithUserID(t *testing.T) { @@ -1831,14 +1751,10 @@ func TestContainerWithUserID(t *testing.T) { require.NoError(t, err) r, err := ctr.Logs(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer r.Close() b, err := io.ReadAll(r) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) actual := regexp.MustCompile(`\D+`).ReplaceAllString(string(b), "") assert.Equal(t, req.User, actual) } @@ -1859,14 +1775,10 @@ func TestContainerWithNoUserID(t *testing.T) { require.NoError(t, err) r, err := ctr.Logs(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer r.Close() b, err := io.ReadAll(r) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) actual := regexp.MustCompile(`\D+`).ReplaceAllString(string(b), "") assert.Equal(t, "0", actual) } @@ -1875,15 +1787,11 @@ func TestGetGatewayIP(t *testing.T) { // When using docker compose with DinD mode, and using host port or http wait strategy // It's need to invoke GetGatewayIP for get the host provider, err := providerType.GetProvider(WithLogger(TestLogger(t))) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer provider.Close() ip, err := provider.(*DockerProvider).GetGatewayIP(context.Background()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if ip == "" { t.Fatal("could not get gateway ip") } diff --git a/file_test.go b/file_test.go index 1128304df7..06ef8905e7 100644 --- a/file_test.go +++ b/file_test.go @@ -78,34 +78,24 @@ func Test_TarDir(t *testing.T) { } buff, err := tarDir(src, 0o755) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) tmpDir := filepath.Join(t.TempDir(), "subfolder") err = untar(tmpDir, bytes.NewReader(buff.Bytes())) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) srcFiles, err := os.ReadDir(src) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) for _, srcFile := range srcFiles { if srcFile.IsDir() { continue } srcBytes, err := os.ReadFile(filepath.Join(src, srcFile.Name())) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) untarBytes, err := os.ReadFile(filepath.Join(tmpDir, "testdata", srcFile.Name())) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) assert.Equal(t, srcBytes, untarBytes) } }) @@ -114,28 +104,20 @@ func Test_TarDir(t *testing.T) { func Test_TarFile(t *testing.T) { b, err := os.ReadFile(filepath.Join(".", "testdata", "Dockerfile")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) buff, err := tarFile("Docker.file", func(tw io.Writer) error { _, err := tw.Write(b) return err }, int64(len(b)), 0o755) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) tmpDir := t.TempDir() err = untar(tmpDir, bytes.NewReader(buff.Bytes())) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) untarBytes, err := os.ReadFile(filepath.Join(tmpDir, "Docker.file")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) assert.Equal(t, b, untarBytes) } diff --git a/from_dockerfile_test.go b/from_dockerfile_test.go index 854492fbfd..75f80537d2 100644 --- a/from_dockerfile_test.go +++ b/from_dockerfile_test.go @@ -17,9 +17,7 @@ import ( func TestBuildImageFromDockerfile(t *testing.T) { provider, err := NewDockerProvider() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer provider.Close() cli := provider.Client() @@ -47,17 +45,13 @@ func TestBuildImageFromDockerfile(t *testing.T) { Force: true, PruneChildren: true, }) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) }) } func TestBuildImageFromDockerfile_NoRepo(t *testing.T) { provider, err := NewDockerProvider() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer provider.Close() cli := provider.Client() @@ -82,9 +76,7 @@ func TestBuildImageFromDockerfile_NoRepo(t *testing.T) { Force: true, PruneChildren: true, }) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) }) } @@ -112,9 +104,7 @@ func TestBuildImageFromDockerfile_BuildError(t *testing.T) { func TestBuildImageFromDockerfile_NoTag(t *testing.T) { provider, err := NewDockerProvider() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer provider.Close() cli := provider.Client() @@ -139,9 +129,7 @@ func TestBuildImageFromDockerfile_NoTag(t *testing.T) { Force: true, PruneChildren: true, }) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) }) } diff --git a/image_substitutors_test.go b/image_substitutors_test.go index 92b42e63b3..4a168254e6 100644 --- a/image_substitutors_test.go +++ b/image_substitutors_test.go @@ -4,6 +4,8 @@ import ( "context" "testing" + "github.com/stretchr/testify/require" + "github.com/testcontainers/testcontainers-go/internal/config" ) @@ -12,9 +14,7 @@ func TestCustomHubSubstitutor(t *testing.T) { s := NewCustomHubSubstitutor("quay.io") img, err := s.Substitute("foo/foo:latest") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if img != "quay.io/foo/foo:latest" { t.Errorf("expected quay.io/foo/foo:latest, got %s", img) @@ -24,9 +24,7 @@ func TestCustomHubSubstitutor(t *testing.T) { s := NewCustomHubSubstitutor("quay.io") img, err := s.Substitute("quay.io/foo/foo:latest") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if img != "quay.io/foo/foo:latest" { t.Errorf("expected quay.io/foo/foo:latest, got %s", img) @@ -39,9 +37,7 @@ func TestCustomHubSubstitutor(t *testing.T) { s := NewCustomHubSubstitutor("quay.io") img, err := s.Substitute("foo/foo:latest") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if img != "foo/foo:latest" { t.Errorf("expected foo/foo:latest, got %s", img) @@ -55,9 +51,7 @@ func TestPrependHubRegistrySubstitutor(t *testing.T) { s := newPrependHubRegistry("my-registry") img, err := s.Substitute("foo:latest") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if img != "my-registry/foo:latest" { t.Errorf("expected my-registry/foo, got %s", img) @@ -67,9 +61,7 @@ func TestPrependHubRegistrySubstitutor(t *testing.T) { s := newPrependHubRegistry("my-registry") img, err := s.Substitute("user/foo:latest") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if img != "my-registry/user/foo:latest" { t.Errorf("expected my-registry/foo, got %s", img) @@ -80,9 +72,7 @@ func TestPrependHubRegistrySubstitutor(t *testing.T) { s := newPrependHubRegistry("my-registry") img, err := s.Substitute("org/user/foo:latest") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if img != "my-registry/org/user/foo:latest" { t.Errorf("expected my-registry/org/foo:latest, got %s", img) @@ -95,9 +85,7 @@ func TestPrependHubRegistrySubstitutor(t *testing.T) { s := newPrependHubRegistry("my-registry") img, err := s.Substitute("quay.io/foo:latest") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if img != "quay.io/foo:latest" { t.Errorf("expected quay.io/foo:latest, got %s", img) @@ -108,9 +96,7 @@ func TestPrependHubRegistrySubstitutor(t *testing.T) { s := newPrependHubRegistry("my-registry") img, err := s.Substitute("registry.hub.docker.com/library/foo:latest") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if img != "registry.hub.docker.com/library/foo:latest" { t.Errorf("expected registry.hub.docker.com/library/foo:latest, got %s", img) @@ -121,9 +107,7 @@ func TestPrependHubRegistrySubstitutor(t *testing.T) { s := newPrependHubRegistry("my-registry") img, err := s.Substitute("registry.hub.docker.com/foo:latest") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if img != "registry.hub.docker.com/foo:latest" { t.Errorf("expected registry.hub.docker.com/foo:latest, got %s", img) @@ -150,14 +134,10 @@ func TestSubstituteBuiltImage(t *testing.T) { config.Reset() c, err := GenericContainer(context.Background(), req) CleanupContainer(t, c) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) json, err := c.Inspect(context.Background()) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if json.Config.Image != "my-registry/my-repo:my-image" { t.Errorf("expected my-registry/my-repo:my-image, got %s", json.Config.Image) diff --git a/image_test.go b/image_test.go index 2344c5063d..39f8134acd 100644 --- a/image_test.go +++ b/image_test.go @@ -6,6 +6,8 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/require" + "github.com/testcontainers/testcontainers-go/internal/core" ) @@ -79,9 +81,7 @@ func TestSaveImages(t *testing.T) { } info, err := os.Stat(output) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if info.Size() == 0 { t.Fatalf("output file is empty") diff --git a/lifecycle_test.go b/lifecycle_test.go index 0d7e9c7861..374d45bf80 100644 --- a/lifecycle_test.go +++ b/lifecycle_test.go @@ -904,14 +904,10 @@ func TestPrintContainerLogsOnError(t *testing.T) { }) CleanupContainer(t, ctr) // it should fail because the waiting for condition is not met - if err == nil { - t.Fatal(err) - } + require.Error(t, err) containerLogs, err := ctr.Logs(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer containerLogs.Close() // read container logs line by line, checking that each line is present in the stdout diff --git a/logconsumer_test.go b/logconsumer_test.go index f16c2fc007..e4ee916e0f 100644 --- a/logconsumer_test.go +++ b/logconsumer_test.go @@ -285,9 +285,7 @@ func TestContainerLogWithErrClosed(t *testing.T) { opts := []client.Opt{client.WithHost(remoteDocker), client.WithAPIVersionNegotiation()} dockerClient, err := NewDockerClientWithOpts(ctx, opts...) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer dockerClient.Close() provider := &DockerProvider{ @@ -313,18 +311,13 @@ func TestContainerLogWithErrClosed(t *testing.T) { Consumers: []LogConsumer{&consumer}, }, }) - if err != nil { - t.Fatal(err) - } - if err := nginx.Start(ctx); err != nil { - t.Fatal(err) - } + require.NoError(t, err) + err = nginx.Start(ctx) + require.NoError(t, err) CleanupContainer(t, nginx) port, err := nginx.MappedPort(ctx, "80/tcp") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Gather the initial container logs time.Sleep(time.Second * 1) @@ -384,19 +377,13 @@ func TestContainerLogsShouldBeWithoutStreamHeader(t *testing.T) { Started: true, }) CleanupContainer(t, ctr) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) r, err := ctr.Logs(ctx) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer r.Close() b, err := io.ReadAll(r) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) assert.Equal(t, "0", strings.TrimSpace(string(b))) } diff --git a/modules/cassandra/cassandra_test.go b/modules/cassandra/cassandra_test.go index 3c8cd1e918..f4979dff5f 100644 --- a/modules/cassandra/cassandra_test.go +++ b/modules/cassandra/cassandra_test.go @@ -62,9 +62,7 @@ func TestCassandraWithConfigFile(t *testing.T) { cluster := gocql.NewCluster(connectionHost) session, err := cluster.CreateSession() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer session.Close() var result string @@ -90,9 +88,7 @@ func TestCassandraWithInitScripts(t *testing.T) { cluster := gocql.NewCluster(connectionHost) session, err := cluster.CreateSession() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer session.Close() var test Test @@ -113,9 +109,7 @@ func TestCassandraWithInitScripts(t *testing.T) { cluster := gocql.NewCluster(connectionHost) session, err := cluster.CreateSession() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer session.Close() var test Test diff --git a/modules/dolt/dolt_test.go b/modules/dolt/dolt_test.go index b239136e38..a1e46cc976 100644 --- a/modules/dolt/dolt_test.go +++ b/modules/dolt/dolt_test.go @@ -72,14 +72,10 @@ func TestDoltWithPublicRemoteCloneUrl(t *testing.T) { func createTestCredsFile(t *testing.T) string { t.Helper() file, err := os.CreateTemp(t.TempDir(), "prefix") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer file.Close() _, err = file.WriteString("some-fake-creds") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) return file.Name() } diff --git a/modules/elasticsearch/elasticsearch_test.go b/modules/elasticsearch/elasticsearch_test.go index 69c4149fc4..fdfe636769 100644 --- a/modules/elasticsearch/elasticsearch_test.go +++ b/modules/elasticsearch/elasticsearch_test.go @@ -138,9 +138,8 @@ func TestElasticsearch(t *testing.T) { } var esResp ElasticsearchResponse - if err := json.NewDecoder(resp.Body).Decode(&esResp); err != nil { - t.Fatal(err) - } + err = json.NewDecoder(resp.Body).Decode(&esResp) + require.NoError(t, err) if tt.image == baseImage7 && esResp.Version.Number != "7.9.2" { t.Fatal("expected version to be 7.9.2 but got", esResp.Version.Number) @@ -203,9 +202,7 @@ func TestElasticsearch8WithoutCredentials(t *testing.T) { httpClient := configureHTTPClient(ctr) req, err := http.NewRequest("GET", ctr.Settings.Address, nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // elastic:changeme are the default credentials for Elasticsearch 8 req.SetBasicAuth(ctr.Settings.Username, ctr.Settings.Password) @@ -218,9 +215,8 @@ func TestElasticsearch8WithoutCredentials(t *testing.T) { defer resp.Body.Close() var esResp ElasticsearchResponse - if err := json.NewDecoder(resp.Body).Decode(&esResp); err != nil { - t.Fatal(err) - } + err = json.NewDecoder(resp.Body).Decode(&esResp) + require.NoError(t, err) if esResp.Tagline != "You Know, for Search" { t.Fatal("expected tagline to be 'You Know, for Search' but got", esResp.Tagline) diff --git a/modules/k6/k6_test.go b/modules/k6/k6_test.go index f2cc39ef72..bc40bd13a6 100644 --- a/modules/k6/k6_test.go +++ b/modules/k6/k6_test.go @@ -63,16 +63,12 @@ func TestK6(t *testing.T) { var options testcontainers.CustomizeRequestOption if !strings.HasPrefix(tc.script, "http") { absPath, err := filepath.Abs(filepath.Join("scripts", tc.script)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) options = k6.WithTestScript(absPath) } else { uri, err := url.Parse(tc.script) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) desc := k6.DownloadableFile{Uri: *uri, DownloadDir: t.TempDir()} options = k6.WithRemoteTestScript(desc) diff --git a/modules/neo4j/neo4j_test.go b/modules/neo4j/neo4j_test.go index 9d41e4afe5..a5cff51182 100644 --- a/modules/neo4j/neo4j_test.go +++ b/modules/neo4j/neo4j_test.go @@ -167,13 +167,9 @@ func createDriver(t *testing.T, ctx context.Context, container *neo4j.Neo4jConta // boltURL { boltUrl, err := container.BoltUrl(ctx) // } - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) driver, err := neo.NewDriverWithContext(boltUrl, neo.BasicAuth("neo4j", testPassword, "")) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) t.Cleanup(func() { if err := driver.Close(ctx); err != nil { t.Fatalf("failed to close neo: %s", err) diff --git a/modules/rabbitmq/rabbitmq_test.go b/modules/rabbitmq/rabbitmq_test.go index f0b82ca2db..6c4cca0c8c 100644 --- a/modules/rabbitmq/rabbitmq_test.go +++ b/modules/rabbitmq/rabbitmq_test.go @@ -93,9 +93,8 @@ func TestRunContainer_connectUsingAmqps(t *testing.T) { if amqpsConnection.IsClosed() { t.Fatal(fmt.Errorf("AMQPS Connection unexpectdely closed")) } - if err = amqpsConnection.Close(); err != nil { - t.Fatal(err) - } + err = amqpsConnection.Close() + require.NoError(t, err) } func TestRunContainer_withAllSettings(t *testing.T) { @@ -248,14 +247,10 @@ func assertEntity(t *testing.T, container testcontainers.Container, listCommand cmd := []string{"rabbitmqadmin", "list", listCommand} _, out, err := container.Exec(ctx, cmd) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) check, err := io.ReadAll(out) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) for _, e := range entities { if !strings.Contains(string(check), e) { @@ -277,14 +272,10 @@ func assertEntityWithVHost(t *testing.T, container testcontainers.Container, lis } _, out, err := container.Exec(ctx, cmd) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) check, err := io.ReadAll(out) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) for _, e := range entities { if !strings.Contains(string(check), e) { @@ -303,14 +294,10 @@ func assertPluginIsEnabled(t *testing.T, container testcontainers.Container, plu for _, plugin := range plugins { _, out, err := container.Exec(ctx, []string{"rabbitmq-plugins", "is_enabled", plugin}) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) check, err := io.ReadAll(out) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if !strings.Contains(string(check), plugin+" is enabled") { return false diff --git a/modules/weaviate/weaviate_test.go b/modules/weaviate/weaviate_test.go index d6dae679e6..faf8e42f92 100644 --- a/modules/weaviate/weaviate_test.go +++ b/modules/weaviate/weaviate_test.go @@ -42,9 +42,7 @@ func TestWeaviate(t *testing.T) { // gRPCHostAddress { host, err := ctr.GrpcHostAddress(ctx) // } - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) var opts []grpc.DialOption @@ -65,22 +63,14 @@ func TestWeaviate(t *testing.T) { t.Run("Weaviate client", func(tt *testing.T) { httpScheme, httpHost, err := ctr.HttpHostAddress(ctx) - if err != nil { - tt.Fatal(err) - } + require.NoError(tt, err) grpcHost, err := ctr.GrpcHostAddress(ctx) - if err != nil { - tt.Fatal(err) - } + require.NoError(tt, err) config := wvt.Config{Scheme: httpScheme, Host: httpHost, GrpcConfig: &wvtgrpc.Config{Host: grpcHost}} client, err := wvt.NewClient(config) - if err != nil { - tt.Fatal(err) - } + require.NoError(tt, err) meta, err := client.Misc().MetaGetter().Do(ctx) - if err != nil { - tt.Fatal(err) - } + require.NoError(tt, err) if meta == nil || meta.Version == "" { tt.Fatal("failed to get /v1/meta response") diff --git a/wait/exec_test.go b/wait/exec_test.go index 4d2d97c51d..ab84fabd17 100644 --- a/wait/exec_test.go +++ b/wait/exec_test.go @@ -114,18 +114,14 @@ func TestExecStrategyWaitUntilReady(t *testing.T) { wg := wait.NewExecStrategy([]string{"true"}). WithStartupTimeout(30 * time.Second) err := wg.WaitUntilReady(context.Background(), target) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } func TestExecStrategyWaitUntilReadyForExec(t *testing.T) { target := mockExecTarget{} wg := wait.ForExec([]string{"true"}) err := wg.WaitUntilReady(context.Background(), target) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } func TestExecStrategyWaitUntilReady_MultipleChecks(t *testing.T) { @@ -136,9 +132,7 @@ func TestExecStrategyWaitUntilReady_MultipleChecks(t *testing.T) { wg := wait.NewExecStrategy([]string{"true"}). WithPollInterval(500 * time.Millisecond) err := wg.WaitUntilReady(context.Background(), target) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } func TestExecStrategyWaitUntilReady_DeadlineExceeded(t *testing.T) { @@ -163,9 +157,7 @@ func TestExecStrategyWaitUntilReady_CustomExitCode(t *testing.T) { return exitCode == 10 }) err := wg.WaitUntilReady(context.Background(), target) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } func TestExecStrategyWaitUntilReady_withExitCode(t *testing.T) { @@ -176,9 +168,7 @@ func TestExecStrategyWaitUntilReady_withExitCode(t *testing.T) { // Default is 60. Let's shorten that wg.WithStartupTimeout(time.Second * 2) err := wg.WaitUntilReady(context.Background(), target) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // Ensure we aren't spuriously returning on any code wg = wait.NewExecStrategy([]string{"true"}).WithExitCode(0) diff --git a/wait/exit_test.go b/wait/exit_test.go index 4795fd4ad6..5c2ec004db 100644 --- a/wait/exit_test.go +++ b/wait/exit_test.go @@ -9,6 +9,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/go-connections/nat" + "github.com/stretchr/testify/require" tcexec "github.com/testcontainers/testcontainers-go/exec" ) @@ -56,7 +57,5 @@ func TestWaitForExit(t *testing.T) { } wg := NewExitStrategy().WithExitTimeout(100 * time.Millisecond) err := wg.WaitUntilReady(context.Background(), target) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) } diff --git a/wait/host_port_test.go b/wait/host_port_test.go index 1623ef95c0..4dbaad741f 100644 --- a/wait/host_port_test.go +++ b/wait/host_port_test.go @@ -19,16 +19,12 @@ import ( func TestWaitForListeningPortSucceeds(t *testing.T) { listener, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer listener.Close() rawPort := listener.Addr().(*net.TCPAddr).Port port, err := nat.NewPort("tcp", strconv.Itoa(rawPort)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) var mappedPortCount, execCount int target := &MockStrategyTarget{ @@ -60,23 +56,18 @@ func TestWaitForListeningPortSucceeds(t *testing.T) { WithStartupTimeout(5 * time.Second). WithPollInterval(100 * time.Millisecond) - if err := wg.WaitUntilReady(context.Background(), target); err != nil { - t.Fatal(err) - } + err = wg.WaitUntilReady(context.Background(), target) + require.NoError(t, err) } func TestWaitForExposedPortSucceeds(t *testing.T) { listener, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer listener.Close() rawPort := listener.Addr().(*net.TCPAddr).Port port, err := nat.NewPort("tcp", strconv.Itoa(rawPort)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) var mappedPortCount, execCount int target := &MockStrategyTarget{ @@ -124,9 +115,8 @@ func TestWaitForExposedPortSucceeds(t *testing.T) { WithStartupTimeout(5 * time.Second). WithPollInterval(100 * time.Millisecond) - if err := wg.WaitUntilReady(context.Background(), target); err != nil { - t.Fatal(err) - } + err = wg.WaitUntilReady(context.Background(), target) + require.NoError(t, err) } func TestHostPortStrategyFailsWhileGettingPortDueToOOMKilledContainer(t *testing.T) { @@ -298,16 +288,12 @@ func TestHostPortStrategyFailsWhileExternalCheckingDueToUnexpectedContainerStatu func TestHostPortStrategyFailsWhileInternalCheckingDueToOOMKilledContainer(t *testing.T) { listener, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer listener.Close() rawPort := listener.Addr().(*net.TCPAddr).Port port, err := nat.NewPort("tcp", strconv.Itoa(rawPort)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) var stateCount int target := &MockStrategyTarget{ @@ -342,16 +328,12 @@ func TestHostPortStrategyFailsWhileInternalCheckingDueToOOMKilledContainer(t *te func TestHostPortStrategyFailsWhileInternalCheckingDueToExitedContainer(t *testing.T) { listener, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer listener.Close() rawPort := listener.Addr().(*net.TCPAddr).Port port, err := nat.NewPort("tcp", strconv.Itoa(rawPort)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) var stateCount int target := &MockStrategyTarget{ @@ -387,16 +369,12 @@ func TestHostPortStrategyFailsWhileInternalCheckingDueToExitedContainer(t *testi func TestHostPortStrategyFailsWhileInternalCheckingDueToUnexpectedContainerStatus(t *testing.T) { listener, err := net.Listen("tcp", "localhost:0") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer listener.Close() rawPort := listener.Addr().(*net.TCPAddr).Port port, err := nat.NewPort("tcp", strconv.Itoa(rawPort)) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) var stateCount int target := &MockStrategyTarget{ diff --git a/wait/sql_test.go b/wait/sql_test.go index 053ed965e8..2a7db5b330 100644 --- a/wait/sql_test.go +++ b/wait/sql_test.go @@ -9,6 +9,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/go-connections/nat" + "github.com/stretchr/testify/require" ) func Test_waitForSql_WithQuery(t *testing.T) { @@ -102,9 +103,8 @@ func TestWaitForSQLSucceeds(t *testing.T) { WithStartupTimeout(500 * time.Millisecond). WithPollInterval(100 * time.Millisecond) - if err := wg.WaitUntilReady(context.Background(), target); err != nil { - t.Fatal(err) - } + err := wg.WaitUntilReady(context.Background(), target) + require.NoError(t, err) } func TestWaitForSQLFailsWhileGettingPortDueToOOMKilledContainer(t *testing.T) { From 11eb809752b0a8fbe86d5da84a075b54cc4f330d Mon Sep 17 00:00:00 2001 From: abhipranay Date: Mon, 28 Oct 2024 10:55:21 +0100 Subject: [PATCH 3/4] fix: mongodb replicaset should work with auth (#2847) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added custom entrypoint to setup keyfile with proper user permissions * added testcases for replicaset with auth * implementation to support replicaset with auth * removed unnecessary files * cleanup * added autodetection for user:group and entrypoint * added tests for replica set and auth for different images * renamed entrypoint to differentiate between custom entrypoint of testcontainers * code cleanup * renamed newly added tests * fixed names of tests to use slash separated options * fix: lint --------- Co-authored-by: Manuel de la Peña --- modules/mongodb/cli.go | 32 ++++++ modules/mongodb/mongodb.go | 129 +++++++++++++++++++------ modules/mongodb/mongodb_test.go | 59 ++++++++++- modules/mongodb/mount/entrypoint-tc.sh | 32 ++++++ 4 files changed, 218 insertions(+), 34 deletions(-) create mode 100644 modules/mongodb/cli.go create mode 100644 modules/mongodb/mount/entrypoint-tc.sh diff --git a/modules/mongodb/cli.go b/modules/mongodb/cli.go new file mode 100644 index 0000000000..f990bf17c8 --- /dev/null +++ b/modules/mongodb/cli.go @@ -0,0 +1,32 @@ +package mongodb + +import "fmt" + +// mongoCli is cli to interact with MongoDB. If username and password are provided +// it will use credentials to authenticate. +type mongoCli struct { + mongoshBaseCmd string + mongoBaseCmd string +} + +func newMongoCli(username string, password string) mongoCli { + authArgs := "" + if username != "" && password != "" { + authArgs = fmt.Sprintf("--username %s --password %s", username, password) + } + + return mongoCli{ + mongoshBaseCmd: fmt.Sprintf("mongosh %s --quiet", authArgs), + mongoBaseCmd: fmt.Sprintf("mongo %s --quiet", authArgs), + } +} + +func (m mongoCli) eval(command string, args ...any) []string { + command = "\"" + fmt.Sprintf(command, args...) + "\"" + + return []string{ + "sh", + "-c", + m.mongoshBaseCmd + " --eval " + command + " || " + m.mongoBaseCmd + " --eval " + command, + } +} diff --git a/modules/mongodb/mongodb.go b/modules/mongodb/mongodb.go index 3f73e5dc70..8acbf98ee2 100644 --- a/modules/mongodb/mongodb.go +++ b/modules/mongodb/mongodb.go @@ -1,7 +1,9 @@ package mongodb import ( + "bytes" "context" + _ "embed" "fmt" "time" @@ -9,11 +11,21 @@ import ( "github.com/testcontainers/testcontainers-go/wait" ) +//go:embed mount/entrypoint-tc.sh +var entrypointContent []byte + +const ( + entrypointPath = "/tmp/entrypoint-tc.sh" + keyFilePath = "/tmp/mongo_keyfile" + replicaSetOptEnvKey = "testcontainers.mongodb.replicaset_name" +) + // MongoDBContainer represents the MongoDB container type used in the module type MongoDBContainer struct { testcontainers.Container - username string - password string + username string + password string + replicaSet string } // Deprecated: use Run instead @@ -50,10 +62,17 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom return nil, fmt.Errorf("if you specify username or password, you must provide both of them") } + replicaSet := req.Env[replicaSetOptEnvKey] + if replicaSet != "" { + if err := configureRequestForReplicaset(username, password, replicaSet, &genericContainerReq); err != nil { + return nil, err + } + } + container, err := testcontainers.GenericContainer(ctx, genericContainerReq) var c *MongoDBContainer if container != nil { - c = &MongoDBContainer{Container: container, username: username, password: password} + c = &MongoDBContainer{Container: container, username: username, password: password, replicaSet: replicaSet} } if err != nil { @@ -85,28 +104,10 @@ func WithPassword(password string) testcontainers.CustomizeRequestOption { } } -// WithReplicaSet configures the container to run a single-node MongoDB replica set named "rs". -// It will wait until the replica set is ready. +// WithReplicaSet sets the replica set name for Single node MongoDB replica set. func WithReplicaSet(replSetName string) testcontainers.CustomizeRequestOption { return func(req *testcontainers.GenericContainerRequest) error { - req.Cmd = append(req.Cmd, "--replSet", replSetName) - req.WaitingFor = wait.ForAll( - req.WaitingFor, - wait.ForExec(eval("rs.status().ok")), - ).WithDeadline(60 * time.Second) - req.LifecycleHooks = append(req.LifecycleHooks, testcontainers.ContainerLifecycleHooks{ - PostStarts: []testcontainers.ContainerHook{ - func(ctx context.Context, c testcontainers.Container) error { - ip, err := c.ContainerIP(ctx) - if err != nil { - return fmt.Errorf("container ip: %w", err) - } - - cmd := eval("rs.initiate({ _id: '%s', members: [ { _id: 0, host: '%s:27017' } ] })", replSetName, ip) - return wait.ForExec(cmd).WaitUntilReady(ctx, c) - }, - }, - }) + req.Env[replicaSetOptEnvKey] = replSetName return nil } @@ -129,14 +130,80 @@ func (c *MongoDBContainer) ConnectionString(ctx context.Context) (string, error) return c.Endpoint(ctx, "mongodb") } -// eval builds an mongosh|mongo eval command. -func eval(command string, args ...any) []string { - command = "\"" + fmt.Sprintf(command, args...) + "\"" +func setupEntrypointForAuth(req *testcontainers.GenericContainerRequest) { + req.Files = append( + req.Files, testcontainers.ContainerFile{ + Reader: bytes.NewReader(entrypointContent), + ContainerFilePath: entrypointPath, + FileMode: 0o755, + }, + ) + req.Entrypoint = []string{entrypointPath} + req.Env["MONGO_KEYFILE"] = keyFilePath +} + +func configureRequestForReplicaset( + username string, + password string, + replicaSet string, + genericContainerReq *testcontainers.GenericContainerRequest, +) error { + if !(username != "" && password != "") { + return noAuthReplicaSet(replicaSet)(genericContainerReq) + } - return []string{ - "sh", - "-c", - // In previous versions, the binary "mongosh" was named "mongo". - "mongosh --quiet --eval " + command + " || mongo --quiet --eval " + command, + return withAuthReplicaset(replicaSet, username, password)(genericContainerReq) +} + +func noAuthReplicaSet(replSetName string) testcontainers.CustomizeRequestOption { + return func(req *testcontainers.GenericContainerRequest) error { + cli := newMongoCli("", "") + req.Cmd = append(req.Cmd, "--replSet", replSetName) + initiateReplicaSet(req, cli, replSetName) + + return nil + } +} + +func initiateReplicaSet(req *testcontainers.GenericContainerRequest, cli mongoCli, replSetName string) { + req.WaitingFor = wait.ForAll( + req.WaitingFor, + wait.ForExec(cli.eval("rs.status().ok")), + ).WithDeadline(60 * time.Second) + + req.LifecycleHooks = append( + req.LifecycleHooks, testcontainers.ContainerLifecycleHooks{ + PostStarts: []testcontainers.ContainerHook{ + func(ctx context.Context, c testcontainers.Container) error { + ip, err := c.ContainerIP(ctx) + if err != nil { + return fmt.Errorf("container ip: %w", err) + } + + cmd := cli.eval( + "rs.initiate({ _id: '%s', members: [ { _id: 0, host: '%s:27017' } ] })", + replSetName, + ip, + ) + + return wait.ForExec(cmd).WaitUntilReady(ctx, c) + }, + }, + }, + ) +} + +func withAuthReplicaset( + replSetName string, + username string, + password string, +) testcontainers.CustomizeRequestOption { + return func(req *testcontainers.GenericContainerRequest) error { + setupEntrypointForAuth(req) + cli := newMongoCli(username, password) + req.Cmd = append(req.Cmd, "--replSet", replSetName, "--keyFile", keyFilePath) + initiateReplicaSet(req, cli, replSetName) + + return nil } } diff --git a/modules/mongodb/mongodb_test.go b/modules/mongodb/mongodb_test.go index 03d669bb7e..8cc49e629c 100644 --- a/modules/mongodb/mongodb_test.go +++ b/modules/mongodb/mongodb_test.go @@ -36,26 +36,79 @@ func TestMongoDB(t *testing.T) { opts: []testcontainers.ContainerCustomizer{}, }, { - name: "With Replica set and mongo:4", + name: "with-replica/mongo:4", img: "mongo:4", opts: []testcontainers.ContainerCustomizer{ mongodb.WithReplicaSet("rs"), }, }, { - name: "With Replica set and mongo:6", + name: "with-replica/mongo:6", img: "mongo:6", opts: []testcontainers.ContainerCustomizer{ mongodb.WithReplicaSet("rs"), }, }, { - name: "With Replica set and mongo:7", + name: "with-replica/mongo:7", img: "mongo:7", opts: []testcontainers.ContainerCustomizer{ mongodb.WithReplicaSet("rs"), }, }, + { + name: "with-auth/replica/mongo:7", + img: "mongo:7", + opts: []testcontainers.ContainerCustomizer{ + mongodb.WithReplicaSet("rs"), + mongodb.WithUsername("tester"), + mongodb.WithPassword("testerpass"), + }, + }, + { + name: "with-auth/replica/mongo:6", + img: "mongo:6", + opts: []testcontainers.ContainerCustomizer{ + mongodb.WithReplicaSet("rs"), + mongodb.WithUsername("tester"), + mongodb.WithPassword("testerpass"), + }, + }, + { + name: "with-auth/mongo:6", + img: "mongo:6", + opts: []testcontainers.ContainerCustomizer{ + mongodb.WithUsername("tester"), + mongodb.WithPassword("testerpass"), + }, + }, + { + name: "with-auth/replica/mongodb-enterprise-server:7.0.0-ubi8", + img: "mongodb/mongodb-enterprise-server:7.0.0-ubi8", + opts: []testcontainers.ContainerCustomizer{ + mongodb.WithReplicaSet("rs"), + mongodb.WithUsername("tester"), + mongodb.WithPassword("testerpass"), + }, + }, + { + name: "with-auth/replica/mongodb-community-server:7.0.2-ubi8", + img: "mongodb/mongodb-community-server:7.0.2-ubi8", + opts: []testcontainers.ContainerCustomizer{ + mongodb.WithReplicaSet("rs"), + mongodb.WithUsername("tester"), + mongodb.WithPassword("testerpass"), + }, + }, + { + name: "with-auth/replica/mongo:4", + img: "mongo:4", + opts: []testcontainers.ContainerCustomizer{ + mongodb.WithReplicaSet("rs"), + mongodb.WithUsername("tester"), + mongodb.WithPassword("testerpass"), + }, + }, } for _, tc := range testCases { diff --git a/modules/mongodb/mount/entrypoint-tc.sh b/modules/mongodb/mount/entrypoint-tc.sh new file mode 100644 index 0000000000..1561415aad --- /dev/null +++ b/modules/mongodb/mount/entrypoint-tc.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +set -Eeuo pipefail + +# detect mongo user and group +function get_user_group() { + user_group=$(cut -d: -f1,5 /etc/passwd | grep mongo) + echo "${user_group}" +} + +# detect the entrypoint +function get_entrypoint() { + entrypoint=$(find /usr/local/bin -name 'docker-entrypoint.*') + if [[ "${entrypoint}" == *.py ]]; then + entrypoint="python3 ${entrypoint}" + else + entrypoint="exec ${entrypoint}" + fi + echo "${entrypoint}" +} + +ENTRYPOINT=$(get_entrypoint) +MONGO_USER_GROUP=$(get_user_group) + +# Create the keyfile +openssl rand -base64 756 > "${MONGO_KEYFILE}" + +# Set the permissions and ownership of the keyfile +chown "${MONGO_USER_GROUP}" "${MONGO_KEYFILE}" +chmod 400 "${MONGO_KEYFILE}" + +${ENTRYPOINT} "$@" From 032a69fc28557cefebf3040ffcf947e9ef5b64f8 Mon Sep 17 00:00:00 2001 From: Steven Hartland Date: Mon, 28 Oct 2024 11:36:34 +0000 Subject: [PATCH 4/4] fix!: data races (#2843) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ci: enable test race checks Enable race checks for all tests in CI. * fix!: data various data races Fix data race when determining default network, this required making DockerProviderOptions.DefaultNetwork field private which is a breaking change. Fix data race in test bufLogger. Fix data races on log production context cancellation and context timeout not being cancelled in read loop. BREAKING_CHANGE! --------- Co-authored-by: Manuel de la Peña --- commons-test.mk | 3 +- docker.go | 179 ++++++++++++++++++++++++++---------------------- docker_test.go | 11 +-- network.go | 4 +- provider.go | 2 +- reaper.go | 7 +- 6 files changed, 115 insertions(+), 91 deletions(-) diff --git a/commons-test.mk b/commons-test.mk index d168ff5c65..91ed6a1244 100644 --- a/commons-test.mk +++ b/commons-test.mk @@ -47,7 +47,8 @@ test-%: $(GOBIN)/gotestsum -- \ -v \ -coverprofile=coverage.out \ - -timeout=30m + -timeout=30m \ + -race .PHONY: tools tools: diff --git a/docker.go b/docker.go index 2ef8c6973a..f82cd55381 100644 --- a/docker.go +++ b/docker.go @@ -16,6 +16,7 @@ import ( "path/filepath" "regexp" "strings" + "sync" "time" "github.com/cenkalti/backoff/v4" @@ -762,11 +763,15 @@ func (c *DockerContainer) startLogProduction(ctx context.Context, opts ...LogPro // Setup the log production context which will be used to stop the log production. c.logProductionCtx, c.logProductionCancel = context.WithCancelCause(ctx) - go func() { - err := c.logProducer(stdout, stderr) - // Set context cancel cause, if not already set. - c.logProductionCancel(err) - }() + // We capture context cancel function to avoid data race with multiple + // calls to startLogProduction. + go func(cancel context.CancelCauseFunc) { + // Ensure the context is cancelled when log productions completes + // so that GetLogProductionErrorChannel functions correctly. + defer cancel(nil) + + c.logProducer(stdout, stderr) + }(c.logProductionCancel) return nil } @@ -775,40 +780,49 @@ func (c *DockerContainer) startLogProduction(ctx context.Context, opts ...LogPro // - logProductionCtx is done // - A fatal error occurs // - No more logs are available -func (c *DockerContainer) logProducer(stdout, stderr io.Writer) error { +func (c *DockerContainer) logProducer(stdout, stderr io.Writer) { // Clean up idle client connections. defer c.provider.Close() // Setup the log options, start from the beginning. - options := container.LogsOptions{ + options := &container.LogsOptions{ ShowStdout: true, ShowStderr: true, Follow: true, } - for { - timeoutCtx, cancel := context.WithTimeout(c.logProductionCtx, *c.logProductionTimeout) - defer cancel() + // Use a separate method so that timeout cancel function is + // called correctly. + for c.copyLogsTimeout(stdout, stderr, options) { + } +} - err := c.copyLogs(timeoutCtx, stdout, stderr, options) - switch { - case err == nil: - // No more logs available. - return nil - case c.logProductionCtx.Err() != nil: - // Log production was stopped or caller context is done. - return nil - case timeoutCtx.Err() != nil, errors.Is(err, net.ErrClosed): - // Timeout or client connection closed, retry. - default: - // Unexpected error, retry. - Logger.Printf("Unexpected error reading logs: %v", err) - } +// copyLogsTimeout copies logs from the container to stdout and stderr with a timeout. +// It returns true if the log production should be retried, false otherwise. +func (c *DockerContainer) copyLogsTimeout(stdout, stderr io.Writer, options *container.LogsOptions) bool { + timeoutCtx, cancel := context.WithTimeout(c.logProductionCtx, *c.logProductionTimeout) + defer cancel() - // Retry from the last log received. - now := time.Now() - options.Since = fmt.Sprintf("%d.%09d", now.Unix(), int64(now.Nanosecond())) + err := c.copyLogs(timeoutCtx, stdout, stderr, *options) + switch { + case err == nil: + // No more logs available. + return false + case c.logProductionCtx.Err() != nil: + // Log production was stopped or caller context is done. + return false + case timeoutCtx.Err() != nil, errors.Is(err, net.ErrClosed): + // Timeout or client connection closed, retry. + default: + // Unexpected error, retry. + Logger.Printf("Unexpected error reading logs: %v", err) } + + // Retry from the last log received. + now := time.Now() + options.Since = fmt.Sprintf("%d.%09d", now.Unix(), int64(now.Nanosecond())) + + return true } // copyLogs copies logs from the container to stdout and stderr. @@ -866,10 +880,12 @@ func (c *DockerContainer) GetLogProductionErrorChannel() <-chan error { } errCh := make(chan error, 1) - go func() { - <-c.logProductionCtx.Done() - errCh <- context.Cause(c.logProductionCtx) - }() + go func(ctx context.Context) { + <-ctx.Done() + errCh <- context.Cause(ctx) + close(errCh) + }(c.logProductionCtx) + return errCh } @@ -906,6 +922,7 @@ type DockerProvider struct { host string hostCache string config config.Config + mtx sync.Mutex } // Client gets the docker client used by the provider @@ -984,29 +1001,26 @@ func (p *DockerProvider) CreateContainer(ctx context.Context, req ContainerReque // defer the close of the Docker client connection the soonest defer p.Close() - // Make sure that bridge network exists - // In case it is disabled we will create reaper_default network - if p.DefaultNetwork == "" { - p.DefaultNetwork, err = p.getDefaultNetwork(ctx, p.client) - if err != nil { - return nil, err - } + var defaultNetwork string + defaultNetwork, err = p.ensureDefaultNetwork(ctx) + if err != nil { + return nil, fmt.Errorf("ensure default network: %w", err) } // 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 defaultNetwork != p.defaultBridgeNetworkName { isAttached := false for _, net := range req.Networks { - if net == p.DefaultNetwork { + if net == defaultNetwork { isAttached = true break } } if !isAttached { - req.Networks = append(req.Networks, p.DefaultNetwork) + req.Networks = append(req.Networks, defaultNetwork) } } @@ -1461,12 +1475,8 @@ func (p *DockerProvider) CreateNetwork(ctx context.Context, req NetworkRequest) // defer the close of the Docker client connection the soonest defer p.Close() - // Make sure that bridge network exists - // In case it is disabled we will create reaper_default network - if p.DefaultNetwork == "" { - if p.DefaultNetwork, err = p.getDefaultNetwork(ctx, p.client); err != nil { - return nil, err - } + if _, err = p.ensureDefaultNetwork(ctx); err != nil { + return nil, fmt.Errorf("ensure default network: %w", err) } if req.Labels == nil { @@ -1537,14 +1547,12 @@ func (p *DockerProvider) GetNetwork(ctx context.Context, req NetworkRequest) (ne func (p *DockerProvider) GetGatewayIP(ctx context.Context) (string, error) { // Use a default network as defined in the DockerProvider - if p.DefaultNetwork == "" { - var err error - p.DefaultNetwork, err = p.getDefaultNetwork(ctx, p.client) - if err != nil { - return "", err - } + defaultNetwork, err := p.ensureDefaultNetwork(ctx) + if err != nil { + return "", fmt.Errorf("ensure default network: %w", err) } - nw, err := p.GetNetwork(ctx, NetworkRequest{Name: p.DefaultNetwork}) + + nw, err := p.GetNetwork(ctx, NetworkRequest{Name: defaultNetwork}) if err != nil { return "", err } @@ -1563,43 +1571,50 @@ func (p *DockerProvider) GetGatewayIP(ctx context.Context) (string, error) { return ip, nil } -func (p *DockerProvider) getDefaultNetwork(ctx context.Context, cli client.APIClient) (string, error) { - // Get list of available networks - networkResources, err := cli.NetworkList(ctx, network.ListOptions{}) - if err != nil { - return "", err - } +// ensureDefaultNetwork ensures that defaultNetwork is set and creates +// it if it does not exist, returning its value. +// It is safe to call this method concurrently. +func (p *DockerProvider) ensureDefaultNetwork(ctx context.Context) (string, error) { + p.mtx.Lock() + defer p.mtx.Unlock() - reaperNetwork := ReaperDefault + if p.defaultNetwork != "" { + // Already set. + return p.defaultNetwork, nil + } - reaperNetworkExists := false + networkResources, err := p.client.NetworkList(ctx, network.ListOptions{}) + if err != nil { + return "", fmt.Errorf("network list: %w", err) + } for _, net := range networkResources { - if net.Name == p.defaultBridgeNetworkName { - return p.defaultBridgeNetworkName, nil - } - - if net.Name == reaperNetwork { - reaperNetworkExists = true + switch net.Name { + case p.defaultBridgeNetworkName: + p.defaultNetwork = p.defaultBridgeNetworkName + return p.defaultNetwork, nil + case ReaperDefault: + p.defaultNetwork = ReaperDefault + return p.defaultNetwork, nil } } - // Create a bridge network for the container communications - if !reaperNetworkExists { - _, err = cli.NetworkCreate(ctx, reaperNetwork, network.CreateOptions{ - Driver: Bridge, - Attachable: true, - Labels: GenericLabels(), - }) - // If the network already exists, we can ignore the error as that can - // happen if we are running multiple tests in parallel and we only - // need to ensure that the network exists. - if err != nil && !errdefs.IsConflict(err) { - return "", err - } + // Create a bridge network for the container communications. + _, err = p.client.NetworkCreate(ctx, ReaperDefault, network.CreateOptions{ + Driver: Bridge, + Attachable: true, + Labels: GenericLabels(), + }) + // If the network already exists, we can ignore the error as that can + // happen if we are running multiple tests in parallel and we only + // need to ensure that the network exists. + if err != nil && !errdefs.IsConflict(err) { + return "", fmt.Errorf("network create: %w", err) } - return reaperNetwork, nil + p.defaultNetwork = ReaperDefault + + return p.defaultNetwork, nil } // containerFromDockerResponse builds a Docker container struct from the response of the Docker API diff --git a/docker_test.go b/docker_test.go index a9fcbd03d6..4be29f8fcd 100644 --- a/docker_test.go +++ b/docker_test.go @@ -1790,11 +1790,14 @@ func TestGetGatewayIP(t *testing.T) { require.NoError(t, err) defer provider.Close() - ip, err := provider.(*DockerProvider).GetGatewayIP(context.Background()) - require.NoError(t, err) - if ip == "" { - t.Fatal("could not get gateway ip") + dockerProvider, ok := provider.(*DockerProvider) + if !ok { + t.Skip("provider is not a DockerProvider") } + + ip, err := dockerProvider.GetGatewayIP(context.Background()) + require.NoError(t, err) + require.NotEmpty(t, ip) } func TestNetworkModeWithContainerReference(t *testing.T) { diff --git a/network.go b/network.go index 9544bee129..5a145ac668 100644 --- a/network.go +++ b/network.go @@ -23,12 +23,12 @@ type DefaultNetwork string // Deprecated: will be removed in the future. func (n DefaultNetwork) ApplyGenericTo(opts *GenericProviderOptions) { - opts.DefaultNetwork = string(n) + opts.defaultNetwork = string(n) } // Deprecated: will be removed in the future. func (n DefaultNetwork) ApplyDockerTo(opts *DockerProviderOptions) { - opts.DefaultNetwork = string(n) + opts.defaultNetwork = string(n) } // Deprecated: will be removed in the future diff --git a/provider.go b/provider.go index b5e5ffa997..31714c0c14 100644 --- a/provider.go +++ b/provider.go @@ -25,7 +25,7 @@ type ( // GenericProviderOptions defines options applicable to all providers GenericProviderOptions struct { Logger Logging - DefaultNetwork string + defaultNetwork string } // GenericProviderOption defines a common interface to modify GenericProviderOptions diff --git a/reaper.go b/reaper.go index 8f2bde8ab6..650bfad0bd 100644 --- a/reaper.go +++ b/reaper.go @@ -402,7 +402,12 @@ func (r *reaperSpawner) newReaper(ctx context.Context, sessionID string, provide // Attach reaper container to a requested network if it is specified if p, ok := provider.(*DockerProvider); ok { - req.Networks = append(req.Networks, p.DefaultNetwork) + defaultNetwork, err := p.ensureDefaultNetwork(ctx) + if err != nil { + return nil, fmt.Errorf("ensure default network: %w", err) + } + + req.Networks = append(req.Networks, defaultNetwork) } c, err := provider.RunContainer(ctx, req)