From 6f0780508a8d0d041b941b50cbb222db95924f93 Mon Sep 17 00:00:00 2001 From: Anthony Nandaa <profnandaa@gmail.com> Date: Sun, 17 Nov 2024 21:05:56 -0800 Subject: [PATCH] tests: frontend/dockerfile: update integration tests for windows/wcow This is a continuation for the integration tests work #4485 We had some tests that we marked as Revit during our first pass through the tests. This commit addresses the following tests in `frontend/dockerfile`: - [x] `testNamedOCILayoutContext` - [x] `testArgDefaultExpansion` - [x] `testTargetStageNameArg` - [x] `testContextChangeDirToFile` (once reported flaky, fixes #5384 ) - [x] `testGlobalArgErrors` - [x] `testCopyThroughSymlinkMultiStage` - [x] `testTarContextExternalDockerfile` - [x] `testTarContext` - [x] `testOutlineArgs` Count: 8 (+1) Signed-off-by: Anthony Nandaa <profnandaa@gmail.com> --- .../dockerfile/dockerfile_outline_test.go | 45 ++++-- frontend/dockerfile/dockerfile_test.go | 132 ++++++++++++------ 2 files changed, 127 insertions(+), 50 deletions(-) diff --git a/frontend/dockerfile/dockerfile_outline_test.go b/frontend/dockerfile/dockerfile_outline_test.go index d646acc4853c..79afed412b44 100644 --- a/frontend/dockerfile/dockerfile_outline_test.go +++ b/frontend/dockerfile/dockerfile_outline_test.go @@ -26,14 +26,15 @@ var outlineTests = integration.TestFuncs( ) func testOutlineArgs(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") workers.CheckFeatureCompat(t, sb, workers.FeatureFrontendOutline) f := getFrontend(t, sb) if _, ok := f.(*clientFrontend); !ok { t.Skip("only test with client frontend") } - dockerfile := []byte(`ARG inherited=box + dockerfile := []byte(integration.UnixOrWindows( + ` +ARG inherited=box ARG inherited2=box2 ARG unused=abc${inherited2} # sfx is a suffix @@ -58,7 +59,35 @@ FROM third AS target COPY --from=first /etc/passwd / FROM second -`) +`, + ` +ARG inherited=server +ARG inherited2=server2 +ARG unused=abc${inherited2} +# sfx is a suffix +ARG sfx="ano${inherited}" + +FROM n${sfx} AS first +# this is not assigned to anything +ARG FOO=123 +# BAR is a number +ARG BAR=456 +RUN exit 0 + +FROM nanoserver${unused} AS second +ARG BAZ +RUN exit 0 + +FROM nanoserver AS third +ARG ABC=a + +# target defines build target +FROM third AS target +COPY --from=first /License.txt /license + +FROM second +`, + )) dir := integration.Tmpdir( t, @@ -99,22 +128,22 @@ FROM second arg := outline.Args[0] require.Equal(t, "inherited", arg.Name) - require.Equal(t, "box", arg.Value) + require.Equal(t, integration.UnixOrWindows("box", "server"), arg.Value) require.Equal(t, "", arg.Description) require.Equal(t, int32(0), arg.Location.SourceIndex) - require.Equal(t, int32(1), arg.Location.Ranges[0].Start.Line) + require.Equal(t, int32(2), arg.Location.Ranges[0].Start.Line) arg = outline.Args[1] require.Equal(t, "sfx", arg.Name) - require.Equal(t, "usybox", arg.Value) + require.Equal(t, integration.UnixOrWindows("usybox", "anoserver"), arg.Value) require.Equal(t, "is a suffix", arg.Description) - require.Equal(t, int32(5), arg.Location.Ranges[0].Start.Line) + require.Equal(t, int32(6), arg.Location.Ranges[0].Start.Line) arg = outline.Args[2] require.Equal(t, "FOO", arg.Name) require.Equal(t, "123", arg.Value) require.Equal(t, "", arg.Description) - require.Equal(t, int32(9), arg.Location.Ranges[0].Start.Line) + require.Equal(t, int32(10), arg.Location.Ranges[0].Start.Line) arg = outline.Args[3] require.Equal(t, "BAR", arg.Name) diff --git a/frontend/dockerfile/dockerfile_test.go b/frontend/dockerfile/dockerfile_test.go index 2e7eba86715b..c27ca7a64933 100644 --- a/frontend/dockerfile/dockerfile_test.go +++ b/frontend/dockerfile/dockerfile_test.go @@ -1422,16 +1422,24 @@ COPY link/foo . } func testCopyThroughSymlinkMultiStage(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") f := getFrontend(t, sb) - dockerfile := []byte(` + dockerfile := []byte(integration.UnixOrWindows( + ` FROM busybox AS build RUN mkdir -p /out/sub && ln -s /out/sub /sub && ln -s out/sub /sub2 && echo -n "data" > /sub/foo FROM scratch COPY --from=build /sub/foo . COPY --from=build /sub2/foo bar -`) +`, + ` +FROM nanoserver AS build +RUN mkdir out\sub && mklink /D sub out\sub && mklink /D sub2 out\sub && echo data> sub\foo +FROM nanoserver +COPY --from=build /sub/foo . +COPY --from=build /sub2/foo bar +`, + )) dir := integration.Tmpdir( t, @@ -1460,7 +1468,8 @@ COPY --from=build /sub2/foo bar dt, err := os.ReadFile(filepath.Join(destDir, "foo")) require.NoError(t, err) - require.Equal(t, "data", string(dt)) + lineEnd := integration.UnixOrWindows("", "\r\n") + require.Equal(t, fmt.Sprintf("data%s", lineEnd), string(dt)) } func testCopySocket(t *testing.T, sb integration.Sandbox) { @@ -1599,13 +1608,13 @@ COPY --from=build /out . } func testGlobalArgErrors(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") f := getFrontend(t, sb) - dockerfile := []byte(` + imgName := integration.UnixOrWindows("busybox", "nanoserver") + dockerfile := []byte(fmt.Sprintf(` ARG FOO=${FOO:?"custom error"} -FROM busybox -`) +FROM %s +`, imgName)) dir := integration.Tmpdir( t, @@ -1639,14 +1648,13 @@ FROM busybox } func testArgDefaultExpansion(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") f := getFrontend(t, sb) - dockerfile := []byte(` -FROM scratch + dockerfile := []byte(fmt.Sprintf(` +FROM %s ARG FOO ARG BAR=${FOO:?"foo missing"} -`) +`, integration.UnixOrWindows("scratch", "nanoserver"))) dir := integration.Tmpdir( t, @@ -1837,10 +1845,10 @@ COPY Dockerfile . } func testTargetStageNameArg(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") f := getFrontend(t, sb) - dockerfile := []byte(` + dockerfile := []byte(integration.UnixOrWindows( + ` FROM alpine AS base WORKDIR /out RUN echo -n "value:$TARGETSTAGE" > /out/first @@ -1852,7 +1860,21 @@ COPY --from=base /out/ / FROM scratch COPY --from=base /out/ / -`) +`, + ` +FROM nanoserver AS base +WORKDIR /out +RUN echo value:%TARGETSTAGE%> /out/first +ARG TARGETSTAGE +RUN echo value:%TARGETSTAGE%> /out/second + +FROM nanoserver AS foo +COPY --from=base /out/ / + +FROM nanoserver +COPY --from=base /out/ / +`, + )) dir := integration.Tmpdir( t, @@ -1884,11 +1906,13 @@ COPY --from=base /out/ / dt, err := os.ReadFile(filepath.Join(destDir, "first")) require.NoError(t, err) - require.Equal(t, "value:", string(dt)) + valueStr := integration.UnixOrWindows("value:", "value:%TARGETSTAGE%\r\n") + require.Equal(t, valueStr, string(dt)) dt, err = os.ReadFile(filepath.Join(destDir, "second")) require.NoError(t, err) - require.Equal(t, "value:foo", string(dt)) + lineEnd := integration.UnixOrWindows("", "\r\n") + require.Equal(t, fmt.Sprintf("value:foo%s", lineEnd), string(dt)) destDir = t.TempDir() @@ -1908,18 +1932,19 @@ COPY --from=base /out/ / dt, err = os.ReadFile(filepath.Join(destDir, "first")) require.NoError(t, err) - require.Equal(t, "value:", string(dt)) + require.Equal(t, valueStr, string(dt)) dt, err = os.ReadFile(filepath.Join(destDir, "second")) require.NoError(t, err) - require.Equal(t, "value:default", string(dt)) + require.Equal(t, fmt.Sprintf("value:default%s", lineEnd), string(dt)) // stage name defined in Dockerfile but not passed in request - dockerfile = append(dockerfile, []byte(` + imgName := integration.UnixOrWindows("scratch", "nanoserver") + dockerfile = append(dockerfile, []byte(fmt.Sprintf(` - FROM scratch AS final + FROM %s AS final COPY --from=base /out/ / - `)...) + `, imgName))...) dir = integration.Tmpdir( t, @@ -1944,11 +1969,11 @@ COPY --from=base /out/ / dt, err = os.ReadFile(filepath.Join(destDir, "first")) require.NoError(t, err) - require.Equal(t, "value:", string(dt)) + require.Equal(t, valueStr, string(dt)) dt, err = os.ReadFile(filepath.Join(destDir, "second")) require.NoError(t, err) - require.Equal(t, "value:final", string(dt)) + require.Equal(t, fmt.Sprintf("value:final%s", lineEnd), string(dt)) } func testPowershellInDefaultPathOnWindows(t *testing.T, sb integration.Sandbox) { @@ -2132,8 +2157,6 @@ COPY arch-$TARGETARCH whoami // tonistiigi/fsutil#46 func testContextChangeDirToFile(t *testing.T, sb integration.Sandbox) { - // TODO(profnandaa): investigating flakyness on Windows CI - integration.SkipOnPlatform(t, "windows") f := getFrontend(t, sb) dockerfile := []byte(integration.UnixOrWindows( @@ -6429,12 +6452,12 @@ COPY --from=build out / } func testTarContext(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") f := getFrontend(t, sb) - dockerfile := []byte(` -FROM scratch -COPY foo /`) + imgName := integration.UnixOrWindows("scratch", "nanoserver") + dockerfile := []byte(fmt.Sprintf(` +FROM %s +COPY foo /`, imgName)) foo := []byte("contents") @@ -6478,7 +6501,6 @@ COPY foo /`) } func testTarContextExternalDockerfile(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") f := getFrontend(t, sb) foo := []byte("contents") @@ -6497,10 +6519,11 @@ func testTarContextExternalDockerfile(t *testing.T, sb integration.Sandbox) { err = tw.Close() require.NoError(t, err) - dockerfile := []byte(` -FROM scratch + imgName := integration.UnixOrWindows("scratch", "nanoserver") + dockerfile := []byte(fmt.Sprintf(` +FROM %s COPY foo bar -`) +`, imgName)) dir := integration.Tmpdir( t, fstest.CreateFile("Dockerfile", dockerfile, 0600), @@ -7664,7 +7687,6 @@ COPY --from=base /another /out2 } func testNamedOCILayoutContext(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") workers.CheckFeatureCompat(t, sb, workers.FeatureOCIExporter, workers.FeatureOCILayout) // how this test works: // 1- we use a regular builder with a dockerfile to create an image two files: "out" with content "first", "out2" with content "second" @@ -7680,13 +7702,22 @@ func testNamedOCILayoutContext(t *testing.T, sb integration.Sandbox) { // create a tempdir where we will store the OCI layout ocidir := t.TempDir() - ociDockerfile := []byte(` + ociDockerfile := []byte(integration.UnixOrWindows( + ` FROM busybox:latest WORKDIR /test RUN sh -c "echo -n first > out" RUN sh -c "echo -n second > out2" ENV foo=bar - `) + `, + ` + FROM nanoserver + WORKDIR /test + RUN echo first> out" + RUN echo second> out2" + ENV foo=bar + `, + )) inDir := integration.Tmpdir( t, fstest.CreateFile("Dockerfile", ociDockerfile, 0600), @@ -7744,7 +7775,8 @@ func testNamedOCILayoutContext(t *testing.T, sb integration.Sandbox) { // 2. we override the context for `foo` to be our local OCI store, which has an `ENV foo=bar` override. // As such, the `RUN echo $foo` step should have `$foo` set to `"bar"`, and so // when we `COPY --from=imported`, it should have the content of `/outfoo` as `"bar"` - dockerfile := []byte(` + dockerfile := []byte(integration.UnixOrWindows( + ` FROM busybox AS base RUN cat /etc/alpine-release > out @@ -7754,7 +7786,20 @@ RUN echo -n $foo > outfoo FROM scratch COPY --from=base /test/o* / COPY --from=imported /test/outfoo / -`) +`, + ` +FROM nanoserver AS base +USER ContainerAdministrator +RUN ver > out + +FROM foo AS imported +RUN echo %foo%> outfoo + +FROM nanoserver +COPY --from=base /test/o* / +COPY --from=imported /test/outfoo / +`, + )) dir := integration.Tmpdir( t, @@ -7784,20 +7829,23 @@ COPY --from=imported /test/outfoo / }, nil) require.NoError(t, err) + // echo for Windows adds a \n + newLine := integration.UnixOrWindows("", "\r\n") + dt, err := os.ReadFile(filepath.Join(destDir, "out")) require.NoError(t, err) require.Greater(t, len(dt), 0) - require.Equal(t, []byte("first"), dt) + require.Equal(t, []byte("first"+newLine), dt) dt, err = os.ReadFile(filepath.Join(destDir, "out2")) require.NoError(t, err) require.Greater(t, len(dt), 0) - require.Equal(t, []byte("second"), dt) + require.Equal(t, []byte("second"+newLine), dt) dt, err = os.ReadFile(filepath.Join(destDir, "outfoo")) require.NoError(t, err) require.Greater(t, len(dt), 0) - require.Equal(t, []byte("bar"), dt) + require.Equal(t, []byte("bar"+newLine), dt) } func testNamedOCILayoutContextExport(t *testing.T, sb integration.Sandbox) {