From f08116b9a3518ea68dae9f17c1b4ff7175db16e6 Mon Sep 17 00:00:00 2001 From: lifubang Date: Mon, 14 Oct 2024 17:31:25 +0800 Subject: [PATCH] ci: fix a race in TestExecIn and TestExecInTTY Fixes: #4437 We can use a chan to wait the output from init process. After we received the content, it means that the init process has started. Then we can exec into this container to use ps command to check the init process and the exec process are both exist. Signed-off-by: lifubang --- libcontainer/integration/execin_test.go | 65 +++++++++++++++++++------ libcontainer/integration/utils_test.go | 22 +++++++++ 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/libcontainer/integration/execin_test.go b/libcontainer/integration/execin_test.go index b9683b76442..fdc7c1fabd0 100644 --- a/libcontainer/integration/execin_test.go +++ b/libcontainer/integration/execin_test.go @@ -30,16 +30,37 @@ func TestExecIn(t *testing.T) { // Execute a first process in the container stdinR, stdinW, err := os.Pipe() ok(t, err) + defer func() { + _ = stdinR.Close() + _ = stdinW.Close() + }() + stdoutR, stdoutW, err := os.Pipe() + ok(t, err) + defer func() { + _ = stdoutR.Close() + _ = stdoutW.Close() + }() + + ch := waitStdOut(stdoutR) process := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - Init: true, + Cwd: "/", + Args: []string{"cat", "/proc/self/cmdline", "-"}, + Env: standardEnvironment, + Stdin: stdinR, + Stdout: stdoutW, + Init: true, } err = container.Run(process) - _ = stdinR.Close() - defer stdinW.Close() //nolint: errcheck + defer func() { + _, _ = stdinW.Write([]byte("hello")) + _ = stdinW.Close() + if _, err := process.Wait(); err != nil { + t.Log(err) + } + }() + ok(t, err) + + err = <-ch ok(t, err) buffers := newStdBuffers() @@ -55,8 +76,6 @@ func TestExecIn(t *testing.T) { err = container.Run(ps) ok(t, err) waitProcess(ps, t) - _ = stdinW.Close() - waitProcess(process, t) out := buffers.Stdout.String() if !strings.Contains(out, "cat") || !strings.Contains(out, "ps") { @@ -242,16 +261,29 @@ func TestExecInTTY(t *testing.T) { // Execute a first process in the container stdinR, stdinW, err := os.Pipe() ok(t, err) + defer func() { + _ = stdinR.Close() + _ = stdinW.Close() + }() + stdoutR, stdoutW, err := os.Pipe() + ok(t, err) + defer func() { + _ = stdoutR.Close() + _ = stdoutW.Close() + }() + + ch := waitStdOut(stdoutR) process := &libcontainer.Process{ - Cwd: "/", - Args: []string{"cat"}, - Env: standardEnvironment, - Stdin: stdinR, - Init: true, + Cwd: "/", + Args: []string{"cat", "/proc/self/cmdline", "-"}, + Env: standardEnvironment, + Stdin: stdinR, + Stdout: stdoutW, + Init: true, } err = container.Run(process) - _ = stdinR.Close() defer func() { + _, _ = stdinW.Write([]byte("hello")) _ = stdinW.Close() if _, err := process.Wait(); err != nil { t.Log(err) @@ -259,6 +291,9 @@ func TestExecInTTY(t *testing.T) { }() ok(t, err) + err = <-ch + ok(t, err) + ps := &libcontainer.Process{ Cwd: "/", Args: []string{"ps"}, diff --git a/libcontainer/integration/utils_test.go b/libcontainer/integration/utils_test.go index 780288ad02b..4bbec30c9cf 100644 --- a/libcontainer/integration/utils_test.go +++ b/libcontainer/integration/utils_test.go @@ -231,3 +231,25 @@ func runContainerOk(t *testing.T, config *configs.Config, args ...string) *stdBu func destroyContainer(container *libcontainer.Container) { _ = container.Destroy() } + +func waitStdOut(stdout *os.File) chan error { + ch := make(chan error, 1) + buf := make([]byte, 1) + go func() { + defer close(ch) + + for { + n, err := stdout.Read(buf) + if err != nil { + ch <- err + return + } + + if n >= 0 { + ch <- nil + return + } + } + }() + return ch +}