Skip to content

Commit 6d029e9

Browse files
milantracygvisor-bot
authored andcommitted
Deflake docker in gVisor docker tests.
The docker client uses in the tests can catch the docker errors for commands on the host's docker. However, when we start docker daemon inside a docker container, the client can't catch the failure from the nested error message from the docker daemon running inside. To deflake the test, we always retry until we can get expected output from execution logs in the command or timeout. PiperOrigin-RevId: 827815816
1 parent 7e39a96 commit 6d029e9

File tree

2 files changed

+34
-23
lines changed

2 files changed

+34
-23
lines changed

test/image/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ go_test(
2929
deps = [
3030
"//pkg/test/dockerutil",
3131
"//pkg/test/testutil",
32+
"@com_github_cenkalti_backoff//:go_default_library",
3233
"@com_github_docker_docker//api/types/mount:go_default_library",
3334
"@in_gopkg_yaml_v3//:go_default_library",
3435
],

test/image/image_test.go

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"testing"
3434
"time"
3535

36+
"github.com/cenkalti/backoff"
3637
"github.com/docker/docker/api/types/mount"
3738
yaml "gopkg.in/yaml.v3"
3839
"gvisor.dev/gvisor/pkg/test/dockerutil"
@@ -499,6 +500,18 @@ func testDockerMatrix(ctx context.Context, t *testing.T, d *dockerutil.Container
499500
}
500501
name := strings.Join(nameParts, "_")
501502
t.Run(name, func(t *testing.T) {
503+
if err := backoff.Retry(func() error {
504+
output, err := dockerInGvisorExecOutput(ctx, d, []string{"docker", "info"})
505+
if err != nil {
506+
return fmt.Errorf("docker exec failed: %v", err)
507+
}
508+
if !strings.Contains(output, "Cannot connect to the Docker daemon") {
509+
return nil
510+
}
511+
return fmt.Errorf("docker daemon not ready")
512+
}, backoff.WithMaxRetries(backoff.NewConstantBackOff(100*time.Millisecond), 10)); err != nil {
513+
t.Fatalf("failed to run docker test %q: %v", name, err)
514+
}
502515
def.testFunc(ctx, t, d, opts)
503516
})
504517
}
@@ -599,6 +612,18 @@ func removeDockerImage(ctx context.Context, imageName string, d *dockerutil.Cont
599612
return nil
600613
}
601614

615+
func dockerInGvisorExecOutput(ctx context.Context, d *dockerutil.Container, cmd []string) (string, error) {
616+
execProc, err := d.ExecProcess(ctx, dockerutil.ExecOpts{}, cmd...)
617+
if err != nil {
618+
return "", fmt.Errorf("docker exec failed: %v", err)
619+
}
620+
output, err := execProc.Logs()
621+
if err != nil {
622+
return "", fmt.Errorf("docker logs failed: %v", err)
623+
}
624+
return output, nil
625+
}
626+
602627
func testDockerRun(ctx context.Context, t *testing.T, d *dockerutil.Container, opts dockerCommandOptions) {
603628
cmd := []string{"docker", "run", "--rm"}
604629
if opts.hostNetwork {
@@ -608,15 +633,12 @@ func testDockerRun(ctx context.Context, t *testing.T, d *dockerutil.Container, o
608633
cmd = append(cmd, "--privileged")
609634
}
610635
cmd = append(cmd, testAlpineImage, "sh", "-c", "apk add curl && apk info -d curl")
611-
execProc, err := d.ExecProcess(ctx, dockerutil.ExecOpts{}, cmd...)
636+
637+
expectedOutput := "URL retrival utility and library"
638+
output, err := dockerInGvisorExecOutput(ctx, d, cmd)
612639
if err != nil {
613640
t.Fatalf("docker exec failed: %v", err)
614641
}
615-
output, err := execProc.Logs()
616-
if err != nil {
617-
t.Fatalf("docker logs failed: %v", err)
618-
}
619-
expectedOutput := "URL retrival utility and library"
620642
if !strings.Contains(output, expectedOutput) {
621643
t.Fatalf("docker didn't get output expected: %q, got: %q", expectedOutput, output)
622644
}
@@ -630,14 +652,10 @@ func testDockerBuild(ctx context.Context, t *testing.T, d *dockerutil.Container,
630652
imageName := strings.ToLower(strings.ReplaceAll(testutil.RandomID("test_docker_build"), "/", "-"))
631653
parts = append(parts, "-t", imageName, "-f", "-", ".")
632654
cmd := strings.Join(parts, " ")
633-
dockerBuildProc, err := d.ExecProcess(ctx, dockerutil.ExecOpts{}, "/bin/sh", "-c", cmd)
655+
_, err := dockerInGvisorExecOutput(ctx, d, []string{"/bin/sh", "-c", cmd})
634656
if err != nil {
635657
t.Fatalf("docker exec failed: %v", err)
636658
}
637-
_, err = dockerBuildProc.Logs()
638-
if err != nil {
639-
t.Fatalf("docker logs failed: %v", err)
640-
}
641659
defer removeDockerImage(ctx, imageName, d)
642660
if err := checkDockerImage(ctx, imageName, d); err != nil {
643661
t.Fatalf("failed to find docker image: %v", err)
@@ -662,13 +680,9 @@ func testDockerExec(ctx context.Context, t *testing.T, d *dockerutil.Container,
662680
}()
663681

664682
for i := 0; i < 10; i++ {
665-
inspectProc, err := d.ExecProcess(ctx, dockerutil.ExecOpts{}, []string{"docker", "container", "inspect", containerName}...)
666-
if err != nil {
667-
t.Fatalf("docker container inspect failed: %v", err)
668-
}
669-
inspectOutput, err := inspectProc.Logs()
683+
inspectOutput, err := dockerInGvisorExecOutput(ctx, d, []string{"docker", "container", "inspect", containerName})
670684
if err != nil {
671-
t.Fatalf("docker logs failed: %v", err)
685+
t.Fatalf("docker exec failed: %v", err)
672686
}
673687
if strings.Contains(inspectOutput, "\"Status\": \"running\"") {
674688
break
@@ -682,14 +696,10 @@ func testDockerExec(ctx context.Context, t *testing.T, d *dockerutil.Container,
682696
}
683697
// Execute echo command in the container.
684698
execCmd = append(execCmd, containerName, "echo", "exec in "+containerName)
685-
execProc, err := d.ExecProcess(ctx, dockerutil.ExecOpts{}, execCmd...)
686-
if err != nil {
687-
t.Fatalf("docker exec failed: %v", err)
688-
}
689699

690-
output, err := execProc.Logs()
700+
output, err := dockerInGvisorExecOutput(ctx, d, execCmd)
691701
if err != nil {
692-
t.Fatalf("docker logs failed: %v", err)
702+
t.Fatalf("docker exec failed: %v", err)
693703
}
694704
expectedOutput := "exec in " + containerName
695705
if !strings.Contains(output, expectedOutput) {

0 commit comments

Comments
 (0)