tests: cover debug build missing mount result IDs
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
+131
@@ -0,0 +1,131 @@
|
|||||||
|
package tests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/containerd/continuity/fs/fstest"
|
||||||
|
"github.com/creack/pty"
|
||||||
|
"github.com/moby/buildkit/util/testutil/integration"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
var debugTests = []func(t *testing.T, sb integration.Sandbox){
|
||||||
|
testDebugBuildMissingBindMountSource,
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDebugBuildMissingBindMountSource(t *testing.T, sb integration.Sandbox) {
|
||||||
|
if !isExperimental() {
|
||||||
|
t.Skip("debug command is experimental")
|
||||||
|
}
|
||||||
|
if !isDockerWorker(sb) {
|
||||||
|
t.Skip("debug monitor test only needs a docker worker")
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerfile := []byte(`
|
||||||
|
FROM busybox:latest
|
||||||
|
RUN --mount=type=bind,source=missing,target=/src true
|
||||||
|
`)
|
||||||
|
dir := tmpdir(t,
|
||||||
|
fstest.CreateFile("Dockerfile", dockerfile, 0o600),
|
||||||
|
)
|
||||||
|
|
||||||
|
cmd := buildxCmd(sb, withArgs("debug", "--on=error", "build", "--progress=plain", "--output=type=cacheonly", dir))
|
||||||
|
f, err := pty.StartWithSize(cmd, &pty.Winsize{
|
||||||
|
Cols: 120,
|
||||||
|
Rows: 24,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var output debugOutput
|
||||||
|
copyDone := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
_, _ = io.Copy(&output, f)
|
||||||
|
close(copyDone)
|
||||||
|
}()
|
||||||
|
|
||||||
|
waitCh := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
waitCh <- cmd.Wait()
|
||||||
|
}()
|
||||||
|
|
||||||
|
exited, waitErr := waitForDebugPromptOrExit(t, &output, waitCh)
|
||||||
|
if !exited {
|
||||||
|
_, err = f.Write([]byte("exit\r"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
waitErr = waitForDebugCommandExit(t, cmd, waitCh, &output)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = f.Close()
|
||||||
|
select {
|
||||||
|
case <-copyDone:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
}
|
||||||
|
|
||||||
|
out := output.String()
|
||||||
|
require.Error(t, waitErr, out)
|
||||||
|
require.Contains(t, out, "failed to calculate checksum")
|
||||||
|
require.Contains(t, out, "failed to create container")
|
||||||
|
require.NotContains(t, out, "panic:")
|
||||||
|
require.NotContains(t, out, "index out of range")
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForDebugPromptOrExit(t *testing.T, output *debugOutput, waitCh <-chan error) (bool, error) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
timeout := time.NewTimer(time.Minute)
|
||||||
|
defer timeout.Stop()
|
||||||
|
ticker := time.NewTicker(100 * time.Millisecond)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case err := <-waitCh:
|
||||||
|
return true, err
|
||||||
|
case <-ticker.C:
|
||||||
|
if strings.Contains(output.String(), "(buildx) ") {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
case <-timeout.C:
|
||||||
|
require.FailNow(t, "timeout waiting for debug monitor", output.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForDebugCommandExit(t *testing.T, cmd *exec.Cmd, waitCh <-chan error, output *debugOutput) error {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err := <-waitCh:
|
||||||
|
return err
|
||||||
|
case <-time.After(30 * time.Second):
|
||||||
|
if cmd.Process != nil {
|
||||||
|
_ = cmd.Process.Kill()
|
||||||
|
}
|
||||||
|
require.FailNow(t, "timeout waiting for debug command to exit", output.String())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type debugOutput struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
buf bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *debugOutput) Write(p []byte) (int, error) {
|
||||||
|
b.mu.Lock()
|
||||||
|
defer b.mu.Unlock()
|
||||||
|
return b.buf.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *debugOutput) String() string {
|
||||||
|
b.mu.Lock()
|
||||||
|
defer b.mu.Unlock()
|
||||||
|
return b.buf.String()
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ func TestIntegration(t *testing.T) {
|
|||||||
var tests []func(t *testing.T, sb integration.Sandbox)
|
var tests []func(t *testing.T, sb integration.Sandbox)
|
||||||
tests = append(tests, commonTests...)
|
tests = append(tests, commonTests...)
|
||||||
tests = append(tests, buildTests...)
|
tests = append(tests, buildTests...)
|
||||||
|
tests = append(tests, debugTests...)
|
||||||
tests = append(tests, policyBuildTests...)
|
tests = append(tests, policyBuildTests...)
|
||||||
tests = append(tests, policyEvalTests...)
|
tests = append(tests, policyEvalTests...)
|
||||||
tests = append(tests, policyBakeTests...)
|
tests = append(tests, policyBakeTests...)
|
||||||
|
|||||||
Reference in New Issue
Block a user