Skip to content

Commit

Permalink
fix: properly set the Docker socket on Windows (#1458)
Browse files Browse the repository at this point in the history
* fix: set Windows' USERPROFILE env var alongside Unix's HOME

* chore: skip Docker rootless tests on Windows

* chore: initialise Docker socket path on Windows properly

* docs: document socket paths

* chore: proper skip in tests

* chore: log Docekr socket path in the DockerServerInfo

* fix: the Docker client retrieves the socket path properly

* fix: explicitly skip subtests for rootless

* fix: initialise socketPath

* fix: use proper eval if windows

* revert: print docker host

* fix: print the resolved docker host, not the constant

* fix: wrong assignment to variable

* chore: simplify initialisation of socket path on Windows

* chore: do not build unix on windows

* fix: proper compilation

* fix: define docker socket mount path

* fix: compile

* fix: reverse logic to skip windows tests

* Revert "revert: print docker host"

This reverts commit c97d75f.

* revert: print Docker info

* fix: variable value

* Revert "revert: print Docker info"

This reverts commit 59f344c.

* revert: print log

* chore: do not hardcode schema in test expectations

* fix: resolve error while cleaning up test resources

"The process cannot access the file because it is being used by another process."

* fix: mount docker socket

* chore: negate build condition for windows

* Revert "chore: negate build condition for windows"

This reverts commit 1f1dd39.

* fix: priority in tests

* chore: rename windows job

* chore: bring back initial approach

* chore: add a docker host strategy for windows

* Revert "revert: print log"

This reverts commit 729ac05.

* fix: set the schema too

* fix: skip on windows

* fix: include schema

* chore: refine for windows socket path

* fix: skip test for Windows

* chore: print docker host and docker socket path

* fix: use filepath for building test paths

* revert: print networks after inspect

* fix: wrong replacement

* fix: close file before removing it

See golang/go#51442 (comment)

* chore: combine function into its test

* chore: skip test for windows

* chore: adjust log

* chore: increase timeout for listening to a port

Seems that windows needs more than 500ms

* chore: move testss for BindMounts and VolumeMounts to its test file

* chore: triple max timeout for the workflow run, which takes +10m

* Revert "chore: triple max timeout for the workflow run, which takes +10m"

This reverts commit 07811cb.

* fix: more filepaths

* chore: skip podman provider tests on windows

* chore: remove invalida comment

* chore: increase wait timeout forHTTP in test

* chore: get Docker host from the resolution strategy

* chore: increase wait timeout forHTTP in tests

* chore: keep get provider for podman as it was

* chore: remove log
  • Loading branch information
mdelapenya authored Aug 11, 2023
1 parent 2e85c30 commit 9013d9a
Show file tree
Hide file tree
Showing 19 changed files with 256 additions and 163 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
types: [windows-test-command]

jobs:
docker:
test-windows:
# At the moment, we are running a self-hosted runner on Windows 2022.
runs-on: [self-hosted, Windows, X64]
strategy:
Expand Down
1 change: 1 addition & 0 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func TestReadConfig(t *testing.T) {

t.Run("Config is read just once", func(t *testing.T) {
t.Setenv("HOME", "")
t.Setenv("USERPROFILE", "") // Windows support
t.Setenv("TESTCONTAINERS_RYUK_DISABLED", "true")

cfg := ReadConfig()
Expand Down
110 changes: 21 additions & 89 deletions container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"time"

"github.com/stretchr/testify/assert"
"github.com/testcontainers/testcontainers-go/internal/testcontainersdocker"
"github.com/testcontainers/testcontainers-go/wait"
)

Expand Down Expand Up @@ -326,99 +325,32 @@ func TestShouldStartContainersInParallel(t *testing.T) {
t.Cleanup(cancel)

for i := 0; i < 3; i++ {
i := i
t.Run(fmt.Sprintf("iteration_%d", i), func(t *testing.T) {
t.Parallel()
createTestContainer(t, ctx)
})
}
}

func createTestContainer(t *testing.T, ctx context.Context) int {
req := ContainerRequest{
Image: nginxAlpineImage,
ExposedPorts: []string{nginxDefaultPort},
WaitingFor: wait.ForHTTP("/"),
}
container, err := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
if err != nil {
t.Fatalf("could not start container: %v", err)
}
// mappedPort {
port, err := container.MappedPort(ctx, nginxDefaultPort)
// }
if err != nil {
t.Fatalf("could not get mapped port: %v", err)
}

terminateContainerOnEnd(t, ctx, container)

return port.Int()
}

func TestBindMount(t *testing.T) {
t.Parallel()

dockerSocket := testcontainersdocker.ExtractDockerSocket(context.Background())
req := ContainerRequest{
Image: nginxAlpineImage,
ExposedPorts: []string{nginxDefaultPort},
WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second),
}
container, err := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
if err != nil {
t.Fatalf("could not start container: %v", err)
}
// mappedPort {
port, err := container.MappedPort(ctx, nginxDefaultPort)
// }
if err != nil {
t.Fatalf("could not get mapped port: %v", err)
}

type args struct {
hostPath string
mountTarget ContainerMountTarget
}
tests := []struct {
name string
args args
want ContainerMount
}{
{
name: dockerSocket + ":" + dockerSocket,
args: args{hostPath: dockerSocket, mountTarget: "/var/run/docker.sock"},
want: ContainerMount{Source: GenericBindMountSource{HostPath: dockerSocket}, Target: "/var/run/docker.sock"},
},
{
name: "/var/lib/app/data:/data",
args: args{hostPath: "/var/lib/app/data", mountTarget: "/data"},
want: ContainerMount{Source: GenericBindMountSource{HostPath: "/var/lib/app/data"}, Target: "/data"},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
assert.Equalf(t, tt.want, BindMount(tt.args.hostPath, tt.args.mountTarget), "BindMount(%v, %v)", tt.args.hostPath, tt.args.mountTarget)
})
}
}
terminateContainerOnEnd(t, ctx, container)

func TestVolumeMount(t *testing.T) {
t.Parallel()
type args struct {
volumeName string
mountTarget ContainerMountTarget
}
tests := []struct {
name string
args args
want ContainerMount
}{
{
name: "sample-data:/data",
args: args{volumeName: "sample-data", mountTarget: "/data"},
want: ContainerMount{Source: GenericVolumeMountSource{Name: "sample-data"}, Target: "/data"},
},
{
name: "web:/var/nginx/html",
args: args{volumeName: "web", mountTarget: "/var/nginx/html"},
want: ContainerMount{Source: GenericVolumeMountSource{Name: "web"}, Target: "/var/nginx/html"},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
assert.Equalf(t, tt.want, VolumeMount(tt.args.volumeName, tt.args.mountTarget), "VolumeMount(%v, %v)", tt.args.volumeName, tt.args.mountTarget)
t.Logf("Parallel container [iteration_%d] listening on %d\n", i, port.Int())
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion docker_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ func removeImageFromLocalCache(t *testing.T, image string) {
PruneChildren: true,
})
if err != nil {
t.Logf("could not remove image %s: %v", image, err)
t.Logf("could not remove image %s: %v\n", image, err)
}
}

Expand Down
51 changes: 26 additions & 25 deletions docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ func TestContainerWithNetworkModeAndNetworkTogether(t *testing.T) {
nginx, err := GenericContainer(ctx, gcr)
if err != nil {
// Error when NetworkMode = host and Network = []string{"bridge"}
t.Logf("Can't use Network and NetworkMode together, %s", err)
t.Logf("Can't use Network and NetworkMode together, %s\n", err)
}
terminateContainerOnEnd(t, ctx, nginx)
}
Expand Down Expand Up @@ -658,7 +658,7 @@ func TestContainerTerminationRemovesDockerImage(t *testing.T) {

req := ContainerRequest{
FromDockerfile: FromDockerfile{
Context: "./testdata",
Context: filepath.Join(".", "testdata"),
},
ExposedPorts: []string{"6379/tcp"},
WaitingFor: wait.ForLog("Ready to accept connections"),
Expand Down Expand Up @@ -970,15 +970,14 @@ func TestContainerCreationTimesOut(t *testing.T) {
func TestContainerRespondsWithHttp200ForIndex(t *testing.T) {
ctx := context.Background()

// delayed-nginx will wait 2s before opening port
nginxC, err := GenericContainer(ctx, GenericContainerRequest{
ProviderType: providerType,
ContainerRequest: ContainerRequest{
Image: nginxAlpineImage,
ExposedPorts: []string{
nginxDefaultPort,
},
WaitingFor: wait.ForHTTP("/"),
WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second),
},
Started: true,
})
Expand Down Expand Up @@ -1075,7 +1074,7 @@ func Test_BuildContainerFromDockerfileWithBuildArgs(t *testing.T) {
t.Log("got ctx, creating container request")
req := ContainerRequest{
FromDockerfile: FromDockerfile{
Context: "./testdata",
Context: filepath.Join(".", "testdata"),
Dockerfile: "args.Dockerfile",
BuildArgs: map[string]*string{
"FOO": &ba,
Expand Down Expand Up @@ -1128,7 +1127,7 @@ func Test_BuildContainerFromDockerfileWithBuildLog(t *testing.T) {
// fromDockerfile {
req := ContainerRequest{
FromDockerfile: FromDockerfile{
Context: "./testdata",
Context: filepath.Join(".", "testdata"),
Dockerfile: "buildlog.Dockerfile",
PrintBuildLog: true,
},
Expand Down Expand Up @@ -1277,7 +1276,7 @@ func ExampleDockerProvider_CreateContainer() {
req := ContainerRequest{
Image: "docker.io/nginx:alpine",
ExposedPorts: []string{"80/tcp"},
WaitingFor: wait.ForHTTP("/"),
WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second),
}
nginxC, _ := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: req,
Expand All @@ -1295,7 +1294,7 @@ func ExampleContainer_Host() {
req := ContainerRequest{
Image: "docker.io/nginx:alpine",
ExposedPorts: []string{"80/tcp"},
WaitingFor: wait.ForHTTP("/"),
WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second),
}
nginxC, _ := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: req,
Expand All @@ -1317,7 +1316,7 @@ func ExampleContainer_Start() {
req := ContainerRequest{
Image: "docker.io/nginx:alpine",
ExposedPorts: []string{"80/tcp"},
WaitingFor: wait.ForHTTP("/"),
WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second),
}
nginxC, _ := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: req,
Expand All @@ -1335,7 +1334,7 @@ func ExampleContainer_Stop() {
req := ContainerRequest{
Image: "docker.io/nginx:alpine",
ExposedPorts: []string{"80/tcp"},
WaitingFor: wait.ForHTTP("/"),
WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second),
}
nginxC, _ := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: req,
Expand All @@ -1354,7 +1353,7 @@ func ExampleContainer_MappedPort() {
req := ContainerRequest{
Image: "docker.io/nginx:alpine",
ExposedPorts: []string{"80/tcp"},
WaitingFor: wait.ForHTTP("/"),
WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second),
}
nginxC, _ := GenericContainer(ctx, GenericContainerRequest{
ContainerRequest: req,
Expand All @@ -1373,7 +1372,7 @@ func ExampleContainer_MappedPort() {
}

func TestContainerCreationWithBindAndVolume(t *testing.T) {
absPath, err := filepath.Abs("./testdata/hello.sh")
absPath, err := filepath.Abs(filepath.Join(".", "testdata", "hello.sh"))
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -1605,7 +1604,7 @@ func TestDockerContainerCopyFileToContainer(t *testing.T) {
terminateContainerOnEnd(t, ctx, nginxC)

copiedFileName := "hello_copy.sh"
_ = nginxC.CopyFileToContainer(ctx, "./testdata/hello.sh", "/"+copiedFileName, 700)
_ = nginxC.CopyFileToContainer(ctx, filepath.Join(".", "testdata", "hello.sh"), "/"+copiedFileName, 700)
c, _, err := nginxC.Exec(ctx, []string{"bash", copiedFileName})
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -1646,7 +1645,7 @@ func TestDockerContainerCopyDirToContainer(t *testing.T) {

func TestDockerCreateContainerWithFiles(t *testing.T) {
ctx := context.Background()
hostFileName := "./testdata/hello.sh"
hostFileName := filepath.Join(".", "testdata", "hello.sh")
copiedFileName := "/hello_copy.sh"
tests := []struct {
name string
Expand All @@ -1673,9 +1672,7 @@ func TestDockerCreateContainerWithFiles(t *testing.T) {
},
},
errMsg: "can't copy " +
"./testdata/hello.sh123 to container: open " +
"./testdata/hello.sh123: no such file or directory: " +
"failed to create container",
hostFileName + "123 to container: open " + hostFileName + "123",
},
}

Expand Down Expand Up @@ -1738,7 +1735,7 @@ func TestDockerCreateContainerWithDirs(t *testing.T) {
{
name: "success copy directory",
dir: ContainerFile{
HostFilePath: filepath.Join("./", hostDirName),
HostFilePath: filepath.Join(".", hostDirName),
ContainerFilePath: "/tmp/" + hostDirName, // the parent dir must exist
FileMode: 700,
},
Expand All @@ -1747,16 +1744,16 @@ func TestDockerCreateContainerWithDirs(t *testing.T) {
{
name: "host dir not found",
dir: ContainerFile{
HostFilePath: "./testdata123", // does not exist
ContainerFilePath: "/tmp/" + hostDirName, // the parent dir must exist
HostFilePath: filepath.Join(".", "testdata123"), // does not exist
ContainerFilePath: "/tmp/" + hostDirName, // the parent dir must exist
FileMode: 700,
},
hasError: true,
},
{
name: "container dir not found",
dir: ContainerFile{
HostFilePath: "./" + hostDirName,
HostFilePath: filepath.Join(".", hostDirName),
ContainerFilePath: "/parent-does-not-exist/testdata123", // does not exist
FileMode: 700,
},
Expand Down Expand Up @@ -1805,7 +1802,7 @@ func TestDockerContainerCopyToContainer(t *testing.T) {

copiedFileName := "hello_copy.sh"

fileContent, err := os.ReadFile("./testdata/hello.sh")
fileContent, err := os.ReadFile(filepath.Join(".", "testdata", "hello.sh"))
if err != nil {
t.Fatal(err)
}
Expand All @@ -1820,7 +1817,7 @@ func TestDockerContainerCopyToContainer(t *testing.T) {
}

func TestDockerContainerCopyFileFromContainer(t *testing.T) {
fileContent, err := os.ReadFile("./testdata/hello.sh")
fileContent, err := os.ReadFile(filepath.Join(".", "testdata", "hello.sh"))
if err != nil {
t.Fatal(err)
}
Expand All @@ -1840,7 +1837,7 @@ func TestDockerContainerCopyFileFromContainer(t *testing.T) {
terminateContainerOnEnd(t, ctx, nginxC)

copiedFileName := "hello_copy.sh"
_ = nginxC.CopyFileToContainer(ctx, "./testdata/hello.sh", "/"+copiedFileName, 700)
_ = nginxC.CopyFileToContainer(ctx, filepath.Join(".", "testdata", "hello.sh"), "/"+copiedFileName, 700)
c, _, err := nginxC.Exec(ctx, []string{"bash", copiedFileName})
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -1879,7 +1876,7 @@ func TestDockerContainerCopyEmptyFileFromContainer(t *testing.T) {
terminateContainerOnEnd(t, ctx, nginxC)

copiedFileName := "hello_copy.sh"
_ = nginxC.CopyFileToContainer(ctx, "./testdata/empty.sh", "/"+copiedFileName, 700)
_ = nginxC.CopyFileToContainer(ctx, filepath.Join(".", "testdata", "empty.sh"), "/"+copiedFileName, 700)
c, _, err := nginxC.Exec(ctx, []string{"bash", copiedFileName})
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -1955,6 +1952,10 @@ func TestDockerContainerResources(t *testing.T) {
}

func TestContainerWithReaperNetwork(t *testing.T) {
if testcontainersdocker.IsWindows() {
t.Skip("Skip for Windows. See https://stackoverflow.com/questions/43784916/docker-for-windows-networking-container-with-multiple-network-interfaces")
}

ctx := context.Background()
networks := []string{
"test_network_" + randomString(),
Expand Down
2 changes: 1 addition & 1 deletion docs/features/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Path to Docker's socket. Used by Ryuk, Docker Compose, and a few other container

Example: `/var/run/docker-alt.sock`

3. If the Operative System retrieved by the Docker client is "Docker Desktop", return the default docker socket path for rootless docker.
3. If the Operative System retrieved by the Docker client is "Docker Desktop", and the host is running on Windows, it will return the `//var/run/docker.sock` UNC Path. Else return the default docker socket path for rootless docker.

4. Get the current Docker Host from the existing strategies: see [Docker host detection](#docker-host-detection).

Expand Down
3 changes: 2 additions & 1 deletion examples/nginx/nginx.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package nginx
import (
"context"
"fmt"
"time"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
Expand All @@ -17,7 +18,7 @@ func startContainer(ctx context.Context) (*nginxContainer, error) {
req := testcontainers.ContainerRequest{
Image: "nginx",
ExposedPorts: []string{"80/tcp"},
WaitingFor: wait.ForHTTP("/"),
WaitingFor: wait.ForHTTP("/").WithStartupTimeout(10 * time.Second),
}
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Expand Down
Loading

0 comments on commit 9013d9a

Please sign in to comment.