From 37e3ccb103601a6f73e8739ea365978a89f5e77f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Tue, 7 Jan 2020 12:06:09 +0100 Subject: [PATCH 1/7] (#128) Throw an error when bash is not installed in the target container --- docker_test.go | 18 ++++++++++++++++++ wait/host_port.go | 2 ++ 2 files changed, 20 insertions(+) diff --git a/docker_test.go b/docker_test.go index 7e71059597..f570883432 100644 --- a/docker_test.go +++ b/docker_test.go @@ -746,6 +746,24 @@ func TestContainerCreationWaitsForLogAndPortContextTimeout(t *testing.T) { } +func TestContainerCreationWaitingForHostPortWithoutBashThrowsAnError(t *testing.T) { + ctx := context.Background() + req := ContainerRequest{ + Image: "nginx:1.17.6-alpine", + ExposedPorts: []string{"80/tcp"}, + WaitingFor: wait.ForListeningPort("80/tcp"), + } + _, err := GenericContainer(ctx, GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + + if err == nil { + t.Fatal(err) + } + +} + func TestContainerCreationWaitsForLogAndPort(t *testing.T) { ctx := context.Background() req := ContainerRequest{ diff --git a/wait/host_port.go b/wait/host_port.go index 3f61e4fbd3..4f84e47924 100644 --- a/wait/host_port.go +++ b/wait/host_port.go @@ -95,6 +95,8 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT if exitCode == 0 { break + } else if exitCode == 126 { + return errors.New("/bin/bash command not executable") } } From 8e056dec4677af9d702c65de945e6bf05bc993d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Tue, 7 Jan 2020 12:40:48 +0100 Subject: [PATCH 2/7] (#128) Use sh instead of bash --- docker_test.go | 20 ++++++++++++++++++-- wait/host_port.go | 6 +++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/docker_test.go b/docker_test.go index f570883432..ea71ac48a6 100644 --- a/docker_test.go +++ b/docker_test.go @@ -746,6 +746,23 @@ func TestContainerCreationWaitsForLogAndPortContextTimeout(t *testing.T) { } +func TestContainerCreationWaitingForHostPort(t *testing.T) { + ctx := context.Background() + req := ContainerRequest{ + Image: "nginx:1.17.6", + ExposedPorts: []string{"80/tcp"}, + WaitingFor: wait.ForListeningPort("80/tcp"), + } + _, err := GenericContainer(ctx, GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + + if err != nil { + t.Fatal(err) + } +} + func TestContainerCreationWaitingForHostPortWithoutBashThrowsAnError(t *testing.T) { ctx := context.Background() req := ContainerRequest{ @@ -758,10 +775,9 @@ func TestContainerCreationWaitingForHostPortWithoutBashThrowsAnError(t *testing. Started: true, }) - if err == nil { + if err != nil { t.Fatal(err) } - } func TestContainerCreationWaitsForLogAndPort(t *testing.T) { diff --git a/wait/host_port.go b/wait/host_port.go index 4f84e47924..c1f302b880 100644 --- a/wait/host_port.go +++ b/wait/host_port.go @@ -88,7 +88,7 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT //internal check command := buildInternalCheckCommand(hp.Port.Int()) for { - exitCode, err := target.Exec(ctx, []string{"/bin/bash", "-c", command}) + exitCode, err := target.Exec(ctx, []string{"/bin/sh", "-c", command}) if err != nil { return errors.Wrapf(err, "host port waiting failed") } @@ -96,7 +96,7 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT if exitCode == 0 { break } else if exitCode == 126 { - return errors.New("/bin/bash command not executable") + return errors.New("/bin/sh command not executable") } } @@ -107,7 +107,7 @@ func buildInternalCheckCommand(internalPort int) string { command := `( cat /proc/net/tcp{,6} | awk '{print $2}' | grep -i :%x || nc -vz -w 1 localhost %d || - /bin/bash -c ' Date: Mon, 20 Jan 2020 13:52:53 +0100 Subject: [PATCH 3/7] (#128) Defer termination of nginx containers in tests --- docker_test.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/docker_test.go b/docker_test.go index ea71ac48a6..00e4ce3b4d 100644 --- a/docker_test.go +++ b/docker_test.go @@ -753,11 +753,17 @@ func TestContainerCreationWaitingForHostPort(t *testing.T) { ExposedPorts: []string{"80/tcp"}, WaitingFor: wait.ForListeningPort("80/tcp"), } - _, err := GenericContainer(ctx, GenericContainerRequest{ + nginx, err := GenericContainer(ctx, GenericContainerRequest{ ContainerRequest: req, Started: true, }) - + defer func() { + err := nginx.Terminate(ctx) + if err != nil { + t.Fatal(err) + } + t.Log("terminated nginx container") + }() if err != nil { t.Fatal(err) } @@ -770,11 +776,17 @@ func TestContainerCreationWaitingForHostPortWithoutBashThrowsAnError(t *testing. ExposedPorts: []string{"80/tcp"}, WaitingFor: wait.ForListeningPort("80/tcp"), } - _, err := GenericContainer(ctx, GenericContainerRequest{ + nginx, err := GenericContainer(ctx, GenericContainerRequest{ ContainerRequest: req, Started: true, }) - + defer func() { + err := nginx.Terminate(ctx) + if err != nil { + t.Fatal(err) + } + t.Log("terminated nginx container") + }() if err != nil { t.Fatal(err) } From 77fdafa6ee64badc741922d314e5c71965ed794f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 5 Feb 2020 09:43:20 +0100 Subject: [PATCH 4/7] fix: add timeout for failing tests (#128) --- docker_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker_test.go b/docker_test.go index 39b69044f6..37c7f6e7b2 100644 --- a/docker_test.go +++ b/docker_test.go @@ -532,7 +532,7 @@ func TestContainerCreationAndWaitForListeningPortLongEnough(t *testing.T) { ExposedPorts: []string{ nginxPort, }, - WaitingFor: wait.ForListeningPort("80"), // default startupTimeout is 60s + WaitingFor: wait.ForListeningPort("80").WithStartupTimeout(120 * time.Second), }, Started: true, }) @@ -798,7 +798,7 @@ func TestContainerCreationWaitingForHostPort(t *testing.T) { req := ContainerRequest{ Image: "nginx:1.17.6", ExposedPorts: []string{"80/tcp"}, - WaitingFor: wait.ForListeningPort("80/tcp"), + WaitingFor: wait.ForListeningPort("80/tcp").WithStartupTimeout(120 * time.Second), } nginx, err := GenericContainer(ctx, GenericContainerRequest{ ContainerRequest: req, @@ -850,7 +850,7 @@ func TestContainerCreationWaitsForLogAndPort(t *testing.T) { }, WaitingFor: wait.ForAll( wait.ForLog("port: 3306 MySQL Community Server - GPL"), - wait.ForListeningPort("3306/tcp"), + wait.ForListeningPort("3306/tcp").WithStartupTimeout(120*time.Second), ), } From e7cea2da5360a17219055bf88105da5083bceec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 5 Feb 2020 11:57:27 +0100 Subject: [PATCH 5/7] Revert "fix: add timeout for failing tests (#128)" This reverts commit 77fdafa6ee64badc741922d314e5c71965ed794f. --- docker_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker_test.go b/docker_test.go index 37c7f6e7b2..39b69044f6 100644 --- a/docker_test.go +++ b/docker_test.go @@ -532,7 +532,7 @@ func TestContainerCreationAndWaitForListeningPortLongEnough(t *testing.T) { ExposedPorts: []string{ nginxPort, }, - WaitingFor: wait.ForListeningPort("80").WithStartupTimeout(120 * time.Second), + WaitingFor: wait.ForListeningPort("80"), // default startupTimeout is 60s }, Started: true, }) @@ -798,7 +798,7 @@ func TestContainerCreationWaitingForHostPort(t *testing.T) { req := ContainerRequest{ Image: "nginx:1.17.6", ExposedPorts: []string{"80/tcp"}, - WaitingFor: wait.ForListeningPort("80/tcp").WithStartupTimeout(120 * time.Second), + WaitingFor: wait.ForListeningPort("80/tcp"), } nginx, err := GenericContainer(ctx, GenericContainerRequest{ ContainerRequest: req, @@ -850,7 +850,7 @@ func TestContainerCreationWaitsForLogAndPort(t *testing.T) { }, WaitingFor: wait.ForAll( wait.ForLog("port: 3306 MySQL Community Server - GPL"), - wait.ForListeningPort("3306/tcp").WithStartupTimeout(120*time.Second), + wait.ForListeningPort("3306/tcp"), ), } From 4f128b8f9b2b5898da312beb70b3679f642813ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Thu, 6 Feb 2020 23:50:49 +0100 Subject: [PATCH 6/7] fix: Use 4 digits for hex port As described in https://www.kernel.org/doc/Documentation/networking/proc_net_tcp.txt the format of /proc/net/tcp is using 4 digits for the hex port: 46: 010310AC:9C4C 030310AC:1770 01 | | | | | |--> connection state | | | | |------> remote TCP port number | | | |-------------> remote IPv4 address | | |--------------------> local TCP port number | |---------------------------> local IPv4 address |----------------------------------> number of entry So this string pattern is more accurate --- wait/host_port.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wait/host_port.go b/wait/host_port.go index b1ecf25c2f..8a09097cb5 100644 --- a/wait/host_port.go +++ b/wait/host_port.go @@ -109,7 +109,7 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT func buildInternalCheckCommand(internalPort int) string { command := `( - cat /proc/net/tcp{,6} | awk '{print $2}' | grep -i :%x || + cat /proc/net/tcp{,6} | awk '{print $2}' | grep -i :%04x || nc -vz -w 1 localhost %d || /bin/sh -c ' Date: Fri, 7 Feb 2020 00:19:30 +0100 Subject: [PATCH 7/7] fix: Use same approach than in Java when reading from /proc/net/tcp files https://github.com/testcontainers/testcontainers-java/commit/23e9718a56eeac3ca2ec87c8a2525fa8e4bf76df --- wait/host_port.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wait/host_port.go b/wait/host_port.go index 8a09097cb5..2f453a99b9 100644 --- a/wait/host_port.go +++ b/wait/host_port.go @@ -109,7 +109,7 @@ func (hp *HostPortStrategy) WaitUntilReady(ctx context.Context, target StrategyT func buildInternalCheckCommand(internalPort int) string { command := `( - cat /proc/net/tcp{,6} | awk '{print $2}' | grep -i :%04x || + cat /proc/net/tcp* | awk '{print $2}' | grep -i :%04x || nc -vz -w 1 localhost %d || /bin/sh -c '