Skip to content

Commit

Permalink
test: enabling integration tests on windows
Browse files Browse the repository at this point in the history
Starting off with this one as a POC on the approach, before we
proceed to complete the rest under `/frontend/dockerfile`.

Tests covered so far:

- [x] `/frontend/dockerfile: testEnvEmptyFormatting`
- [x] `/frontend/dockerfile: testDockerignoreOverride`
- [x] `/frontend/dockerfile: caseEmptyDestDir`

Starts addressing moby#4485

Signed-off-by: Anthony Nandaa <profnandaa@gmail.com>
  • Loading branch information
profnandaa committed Jul 10, 2024
1 parent 62ba6fe commit b741501
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 43 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test-os.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jobs:
needs:
- build
env:
TESTFLAGS: "-v --parallel=6 --timeout=30m"
TESTFLAGS: "-v --parallel=6 --timeout=60m"
GOTESTSUM_FORMAT: "standard-verbose"
strategy:
fail-fast: false
Expand All @@ -102,7 +102,7 @@ jobs:
echo "TEST_REPORT_NAME=${{ github.job }}-$(echo "${{ matrix.pkg }}-${{ matrix.skip-integration-tests }}-${{ matrix.worker }}" | tr -dc '[:alnum:]-\n\r' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
testFlags="${{ env.TESTFLAGS }}"
if [ -n "${{ matrix.worker }}" ]; then
testFlags="${testFlags} --run=//worker=${{ matrix.worker }}$"
testFlags="${testFlags} --run=TestIntegration/.*/worker=${{ matrix.worker }}"
fi
echo "TESTFLAGS=${testFlags}" >> $GITHUB_ENV
shell: bash
Expand Down
1 change: 1 addition & 0 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10568,6 +10568,7 @@ func testLayerLimitOnMounts(t *testing.T, sb integration.Sandbox) {
}

func testClientCustomGRPCOpts(t *testing.T, sb integration.Sandbox) {
integration.SkipOnPlatform(t, "windows")
var interceptedMethods []string
intercept := func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
interceptedMethods = append(interceptedMethods, method)
Expand Down
80 changes: 58 additions & 22 deletions frontend/dockerfile/dockerfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,11 @@ type frontend interface {
func init() {
frontends := map[string]interface{}{}

images := integration.UnixOrWindows([2][]string{
{"busybox:latest", "alpine:latest"},
{"nanoserver:latest"}})
opts = []integration.TestOpt{
integration.WithMirroredImages(integration.OfficialImages("busybox:latest", "alpine:latest")),
integration.WithMirroredImages(integration.OfficialImages(images...)),
integration.WithMatrix("frontend", frontends),
}

Expand All @@ -252,27 +255,34 @@ func init() {
func TestIntegration(t *testing.T) {
integration.Run(t, allTests, opts...)

integration.Run(t, securityTests, append(append(opts, securityOpts...),
integration.WithMatrix("security.insecure", map[string]interface{}{
"granted": securityInsecureGranted,
"denied": securityInsecureDenied,
}))...)
integration.Run(t, networkTests, append(opts,
integration.WithMatrix("network.host", map[string]interface{}{
"granted": networkHostGranted,
"denied": networkHostDenied,
}))...)
integration.Run(t, lintTests, opts...)
integration.Run(t, heredocTests, opts...)
integration.Run(t, outlineTests, opts...)
integration.Run(t, targetsTests, opts...)

runLinuxOnlyTests(t)
}

func runLinuxOnlyTests(t *testing.T) {
integration.SkipOnPlatform(t, "windows")
integration.Run(t, reproTests, append(opts,
// Only use the amd64 digest, regardless to the host platform
integration.WithMirroredImages(map[string]string{
"amd64/bullseye-20230109-slim:latest": "docker.io/amd64/debian:bullseye-20230109-slim@sha256:1acb06a0c31fb467eb8327ad361f1091ab265e0bf26d452dea45dcb0c0ea5e75",
}),
)...)

integration.Run(t, securityTests, append(append(opts, securityOpts...),
integration.WithMatrix("security.insecure", map[string]interface{}{
"granted": securityInsecureGranted,
"denied": securityInsecureDenied,
}))...)

integration.Run(t, networkTests, append(opts,
integration.WithMatrix("network.host", map[string]interface{}{
"granted": networkHostGranted,
"denied": networkHostDenied,
}))...)
}

func testEmptyStringArgInEnv(t *testing.T, sb integration.Sandbox) {
Expand Down Expand Up @@ -385,14 +395,20 @@ echo -n $my_arg $* > /out
}

func testEnvEmptyFormatting(t *testing.T, sb integration.Sandbox) {
integration.SkipOnPlatform(t, "windows")
f := getFrontend(t, sb)

dockerfile := []byte(`
dockerfile := []byte(integration.UnixOrWindows([2]string{
`
FROM busybox AS build
ENV myenv foo%sbar
RUN [ "$myenv" = 'foo%sbar' ]
`)
`,
`
FROM nanoserver AS build
ENV myenv foo%sbar
RUN if %myenv% NEQ foo%sbar (exit 1)
`,
}))

dir := integration.Tmpdir(
t,
Expand Down Expand Up @@ -421,23 +437,36 @@ RUN [ "$myenv" = 'foo%sbar' ]
}

func testDockerignoreOverride(t *testing.T, sb integration.Sandbox) {
integration.SkipOnPlatform(t, "windows")
f := getFrontend(t, sb)
dockerfile := []byte(`
dockerfile := []byte(integration.UnixOrWindows([2]string{
`
FROM busybox
COPY . .
RUN [ -f foo ] && [ ! -f bar ]
`)
`,
`
FROM nanoserver
COPY . .
RUN if exist foo (if not exist bar (exit 0) else (exit 1))
`,
}))

ignore := []byte(`
bar
`)

dockerfile2 := []byte(`
dockerfile2 := []byte(integration.UnixOrWindows([2]string{
`
FROM busybox
COPY . .
RUN [ ! -f foo ] && [ -f bar ]
`)
`,
`
FROM nanoserver
COPY . .
RUN if not exist foo (if exist bar (exit 0) else (exit 1))
`,
}))

ignore2 := []byte(`
foo
Expand Down Expand Up @@ -478,15 +507,22 @@ foo
}

func testEmptyDestDir(t *testing.T, sb integration.Sandbox) {
integration.SkipOnPlatform(t, "windows")
f := getFrontend(t, sb)

dockerfile := []byte(`
dockerfile := []byte(integration.UnixOrWindows([2]string{
`
FROM busybox
ENV empty=""
COPY testfile $empty
RUN [ "$(cat testfile)" == "contents0" ]
`)
`,
`
FROM nanoserver
COPY testfile ''
RUN cmd /V:on /C "set /p tfcontent=<testfile \
& if !tfcontent! NEQ contents0 (exit 1)"
`,
}))

dir := integration.Tmpdir(
t,
Expand Down
3 changes: 3 additions & 0 deletions util/testutil/integration/pins.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build !windows
// +build !windows

package integration

var pins = map[string]map[string]string{
Expand Down
29 changes: 12 additions & 17 deletions util/testutil/integration/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,23 +273,7 @@ func copyImagesLocal(t *testing.T, host string, images map[string]string) error
}

func OfficialImages(names ...string) map[string]string {
ns := runtime.GOARCH
if ns == "arm64" {
ns = "arm64v8"
} else if ns != "amd64" {
ns = "library"
}
m := map[string]string{}
for _, name := range names {
ref := "docker.io/" + ns + "/" + name
if pns, ok := pins[name]; ok {
if dgst, ok := pns[ns]; ok {
ref += "@" + dgst
}
}
m["library/"+name] = ref
}
return m
return officialImages(names...)
}

func withMirrorConfig(mirror string) ConfigUpdater {
Expand Down Expand Up @@ -445,3 +429,14 @@ func SkipOnPlatform(t *testing.T, goos string) {
t.Skipf("Skipped on %s", goos)
}
}

// Selects a test case from a slice. Works with only two cases:
// slice[0] for Unix or slice[1] for Windows.
// You can provide a slice of two items of any type.
// Choosing this approach to simplify the inlined calls.
func UnixOrWindows[T any](tc [2]T) T {
if runtime.GOOS == "windows" {
return tc[1]
}
return tc[0]
}
26 changes: 26 additions & 0 deletions util/testutil/integration/run_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//go:build !windows
// +build !windows

package integration

import "runtime"

func officialImages(names ...string) map[string]string {
ns := runtime.GOARCH
if ns == "arm64" {
ns = "arm64v8"
} else if ns != "amd64" {
ns = "library"
}
m := map[string]string{}
for _, name := range names {
ref := "docker.io/" + ns + "/" + name
if pns, ok := pins[name]; ok {
if dgst, ok := pns[ns]; ok {
ref += "@" + dgst
}
}
m["library/"+name] = ref
}
return m
}
13 changes: 13 additions & 0 deletions util/testutil/integration/run_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package integration

func officialImages(names ...string) map[string]string {
m := map[string]string{}
for _, name := range names {
// select available refs from the mirror map
// so that we mirror only those needed for the tests
if ref, ok := windowsImagesMirrorMap[name]; ok {
m["library/"+name] = ref
}
}
return m
}
6 changes: 4 additions & 2 deletions util/testutil/integration/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,10 @@ func StartCmd(cmd *exec.Cmd, logs map[string]*bytes.Buffer) (func() error, error
case <-ctx.Done():
case <-stopped:
case <-stop:
fmt.Fprintf(cmd.Stderr, "> sending sigterm %v\n", time.Now())
cmd.Process.Signal(syscall.SIGTERM)
signal := UnixOrWindows([2]syscall.Signal{syscall.SIGTERM, syscall.SIGKILL})
signalStr := UnixOrWindows([2]string{"SIGTERM", "SIGKILL"})
fmt.Fprintf(cmd.Stderr, "> sending %s %v\n", signalStr, time.Now())
cmd.Process.Signal(signal)
go func() {
select {
case <-stopped:
Expand Down
6 changes: 6 additions & 0 deletions util/testutil/integration/util_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import (

var socketScheme = "npipe://"

var windowsImagesMirrorMap = map[string]string{
"nanoserver:latest": "mcr.microsoft.com/windows/nanoserver:ltsc2022",
"servercore:latest": "mcr.microsoft.com/windows/servercore:ltsc2022",
"busybox:latest": "registry.k8s.io/e2e-test-images/busybox:1.29-2",
}

// abstracted function to handle pipe dialing on windows.
// some simplification has been made to discard timeout param.
func dialPipe(address string) (net.Conn, error) {
Expand Down

0 comments on commit b741501

Please sign in to comment.