Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add merge GitHub Actions workflow to run tests on Windows and macOS runners #9863

Merged
merged 9 commits into from
Sep 21, 2022
71 changes: 71 additions & 0 deletions .github/workflows/merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: merge

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

on:
push:
branches:
- 'v2'
tags:
- 'v*'
workflow_dispatch:

jobs:
e2e:
name: Build and test
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
os: [desktop-windows, desktop-macos, desktop-m1]
# mode: [plugin, standalone]
mode: [plugin]
env:
GO111MODULE: "on"
steps:
- uses: actions/checkout@v3

- uses: actions/setup-go@v3
with:
go-version-file: go.mod
cache: true
check-latest: true

- name: List Docker resources on machine
run: |
docker ps --all
docker volume ls
docker network ls
docker image ls
- name: Remove Docker resources on machine
continue-on-error: true
run: |
docker kill $(docker ps -q)
docker rm -f $(docker ps -aq)
docker volume rm -f $(docker volume ls -q)
docker ps --all

- name: Unit tests
run: make test

- name: Build binaries
run: |
make
- name: Check arch of go compose binary
run: |
file ./bin/build/docker-compose
if: ${{ !contains(matrix.os, 'desktop-windows') }}
-
name: Test plugin mode
if: ${{ matrix.mode == 'plugin' }}
run: |
make e2e-compose
-
name: Test standalone mode
if: ${{ matrix.mode == 'standalone' }}
run: |
make e2e-compose-standalone

19 changes: 0 additions & 19 deletions .github/workflows/rebase.yml

This file was deleted.

15 changes: 11 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,20 @@ VERSION ?= $(shell git describe --match 'v[0-9]*' --dirty='.m' --always --tags)
GO_LDFLAGS ?= -s -w -X ${PKG}/internal.Version=${VERSION}
GO_BUILDTAGS ?= e2e,kube

UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running $(shell uname -s) on Windows breaks, so we only do it if we're not on Windows

ifeq ($(OS),Windows_NT)
DETECTED_OS = Windows
else
DETECTED_OS = $(shell uname -s)
endif
ifeq ($(DETECTED_OS),Linux)
MOBY_DOCKER=/usr/bin/docker
endif
ifeq ($(UNAME_S),Darwin)
ifeq ($(DETECTED_OS),Darwin)
MOBY_DOCKER=/Applications/Docker.app/Contents/Resources/bin/docker
endif
ifeq ($(DETECTED_OS),Windows)
BINARY_EXT=.exe
endif
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make was previously not adding .exe to the docker-compose binary built on Windows 😅 (thanks for looking at that @milas)


TEST_FLAGS?=
E2E_TEST?=
Expand All @@ -40,7 +47,7 @@ all: build

.PHONY: build ## Build the compose cli-plugin
build:
CGO_ENABLED=0 GO111MODULE=on go build -trimpath -tags "$(GO_BUILDTAGS)" -ldflags "$(GO_LDFLAGS)" -o "$(DESTDIR)/docker-compose" ./cmd
CGO_ENABLED=0 GO111MODULE=on go build -trimpath -tags "$(GO_BUILDTAGS)" -ldflags "$(GO_LDFLAGS)" -o "$(DESTDIR)/docker-compose$(BINARY_EXT)" ./cmd

.PHONY: binary
binary:
Expand Down
2 changes: 1 addition & 1 deletion pkg/e2e/buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (l *lockedBuffer) RequireEventuallyContains(t testing.TB, v string) {
"Error: %v", err)
}
return strings.Contains(bufContents.String(), v)
}, 2*time.Second, 20*time.Millisecond,
}, 5*time.Second, 20*time.Millisecond,
"Buffer did not contain %q\n============\n%s\n============",
v, &bufContents)
}
90 changes: 52 additions & 38 deletions pkg/e2e/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package e2e

import (
"net/http"
"runtime"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -85,6 +86,51 @@ func TestLocalComposeBuild(t *testing.T) {
res.Assert(t, icmd.Expected{Out: `"RESULT": "SUCCESS"`})
})

t.Run("build as part of up", func(t *testing.T) {
c.RunDockerOrExitError(t, "rmi", "build-test-nginx")
c.RunDockerOrExitError(t, "rmi", "custom-nginx")

res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d")
t.Cleanup(func() {
c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "down")
})

res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"})
res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"})

output := HTTPGetWithRetry(t, "http://localhost:8070", http.StatusOK, 2*time.Second, 20*time.Second)
assert.Assert(t, strings.Contains(output, "Hello from Nginx container"))

c.RunDockerCmd(t, "image", "inspect", "build-test-nginx")
c.RunDockerCmd(t, "image", "inspect", "custom-nginx")
})

t.Run("no rebuild when up again", func(t *testing.T) {
res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d")

assert.Assert(t, !strings.Contains(res.Stdout(), "COPY static"), res.Stdout())
})

t.Run("rebuild when up --build", func(t *testing.T) {
res := c.RunDockerComposeCmd(t, "--workdir", "fixtures/build-test", "up", "-d", "--build")

res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"})
res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"})
})

t.Run("cleanup build project", func(t *testing.T) {
c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "down")
c.RunDockerCmd(t, "rmi", "build-test-nginx")
c.RunDockerCmd(t, "rmi", "custom-nginx")
})
}

func TestBuildSSH(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Running on Windows. Skipping...")
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I split out the SSH tests out so I could disable them on Windows -- they were failing with:

Invalid empty ssh agent socket: Windows OpenSSH agent not available at \\.\pipe\openssh-ssh-agent. Enable the SSH agent service or set SSH_AUTH_SOCK.

We can take a look at that later, maybe set up an SSH agent on the Windows runner and re-enable these

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Windows does have a built-in OpenSSH Agent nowadays, so it's fairly straightforward to enable in services.msc if we want

c := NewParallelCLI(t)

t.Run("build failed with ssh default value", func(t *testing.T) {
res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test", "build", "--ssh", "")
res.Assert(t, icmd.Expected{
Expand Down Expand Up @@ -130,47 +176,12 @@ func TestLocalComposeBuild(t *testing.T) {
})
c.RunDockerCmd(t, "image", "inspect", "build-test-ssh")
})

t.Run("build as part of up", func(t *testing.T) {
c.RunDockerOrExitError(t, "rmi", "build-test-nginx")
c.RunDockerOrExitError(t, "rmi", "custom-nginx")

res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d")
t.Cleanup(func() {
c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "down")
})

res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"})
res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"})

output := HTTPGetWithRetry(t, "http://localhost:8070", http.StatusOK, 2*time.Second, 20*time.Second)
assert.Assert(t, strings.Contains(output, "Hello from Nginx container"))

c.RunDockerCmd(t, "image", "inspect", "build-test-nginx")
c.RunDockerCmd(t, "image", "inspect", "custom-nginx")
})

t.Run("no rebuild when up again", func(t *testing.T) {
res := c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "up", "-d")

assert.Assert(t, !strings.Contains(res.Stdout(), "COPY static"), res.Stdout())
})

t.Run("rebuild when up --build", func(t *testing.T) {
res := c.RunDockerComposeCmd(t, "--workdir", "fixtures/build-test", "up", "-d", "--build")

res.Assert(t, icmd.Expected{Out: "COPY static /usr/share/nginx/html"})
res.Assert(t, icmd.Expected{Out: "COPY static2 /usr/share/nginx/html"})
})

t.Run("cleanup build project", func(t *testing.T) {
c.RunDockerComposeCmd(t, "--project-directory", "fixtures/build-test", "down")
c.RunDockerCmd(t, "rmi", "build-test-nginx")
c.RunDockerCmd(t, "rmi", "custom-nginx")
})
}

func TestBuildSecrets(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping test on windows")
}
Comment on lines 181 to +184
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm slightly surprised this test is failing on Windows! Should be a fun one to investigate 🙈

c := NewParallelCLI(t)

t.Run("build with secrets", func(t *testing.T) {
Expand Down Expand Up @@ -259,6 +270,9 @@ func TestBuildImageDependencies(t *testing.T) {
}

func TestBuildPlatformsWithCorrectBuildxConfig(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Running on Windows. Skipping...")
}
c := NewParallelCLI(t)

// declare builder
Expand Down
5 changes: 4 additions & 1 deletion pkg/e2e/compose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ func TestDownComposefileInParentFolder(t *testing.T) {
}

func TestAttachRestart(t *testing.T) {
if _, ok := os.LookupEnv("CI"); ok {
t.Skip("Skipping test on CI... flaky")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for this test, and same regarding always passing on the M1 mac but being flaky on the Intel mac/Windows runner.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oof yeah I've been 👀 this test for a while, might take a look tomorrow to see if I can figure out where the race is

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(To be clear though, I'm in favor of merging this with the Skip() and deal with cleanup after!)

}
c := NewParallelCLI(t)

cmd := c.NewDockerComposeCmd(t, "--ansi=never", "--project-directory", "./fixtures/attach-restart", "up")
Expand All @@ -146,7 +149,7 @@ func TestAttachRestart(t *testing.T) {
return strings.Count(res.Stdout(),
"failing-1 exited with code 1") == 3, fmt.Sprintf("'failing-1 exited with code 1' not found 3 times in : \n%s\n",
debug)
}, 2*time.Minute, 2*time.Second)
}, 4*time.Minute, 2*time.Second)

assert.Equal(t, strings.Count(res.Stdout(), "failing-1 | world"), 3, res.Combined())
}
Expand Down
8 changes: 6 additions & 2 deletions pkg/e2e/pause_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"net"
"net/http"
"os"
"testing"
"time"

Expand All @@ -29,6 +30,9 @@ import (
)

func TestPause(t *testing.T) {
if _, ok := os.LookupEnv("CI"); ok {
t.Skip("Skipping test on CI... flaky")
Copy link
Member Author

@laurazard laurazard Sep 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test was really flaky on CI, so I think it's best to just skip it there for now until we can harden it. Fwiw, it seems to be a performance issue, as it always passes on the M1 mac, but is flaky on the Intel mac and on the Windows runners.

}
cli := NewParallelCLI(t, WithEnv(
"COMPOSE_PROJECT_NAME=e2e-pause",
"COMPOSE_FILE=./fixtures/pause/compose.yaml"))
Expand All @@ -46,7 +50,7 @@ func TestPause(t *testing.T) {
"b": urlForService(t, cli, "b", 80),
}
for _, url := range urls {
HTTPGetWithRetry(t, url, http.StatusOK, 50*time.Millisecond, 5*time.Second)
HTTPGetWithRetry(t, url, http.StatusOK, 50*time.Millisecond, 20*time.Second)
}

// pause a and verify that it can no longer be hit but b still can
Expand Down Expand Up @@ -98,7 +102,7 @@ func TestPauseServiceAlreadyPaused(t *testing.T) {

// launch a and wait for it to come up
cli.RunDockerComposeCmd(t, "up", "-d", "a")
HTTPGetWithRetry(t, urlForService(t, cli, "a", 80), http.StatusOK, 50*time.Millisecond, 5*time.Second)
HTTPGetWithRetry(t, urlForService(t, cli, "a", 80), http.StatusOK, 50*time.Millisecond, 10*time.Second)

// pause a twice - first time should pass, second time fail
cli.RunDockerComposeCmd(t, "pause", "a")
Expand Down
3 changes: 3 additions & 0 deletions pkg/e2e/up_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build !windows
// +build !windows
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test does not compile on Windows due to:

cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

and surrounding logic

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah, we've dealt with this same thing before in Tilt 🙃

What we can do is make a func SetProcessPgid(cmd *exec.Cmd) in proc_windows.go that's a no-op and proc_unix.go that does the code ⬆️ and then call the helper. Annoying but 🤷

(IIRC Windows always has the desired behavior re: killing process groups)


/*
Copyright 2022 Docker Compose CLI authors

Expand Down
4 changes: 4 additions & 0 deletions pkg/e2e/volumes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"net/http"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -99,6 +100,9 @@ func TestProjectVolumeBind(t *testing.T) {
const projectName = "compose-e2e-project-volume-bind"

t.Run("up on project volume with bind specification", func(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Running on Windows. Skipping...")
}
tmpDir, err := os.MkdirTemp("", projectName)
assert.NilError(t, err)
defer os.RemoveAll(tmpDir) //nolint
Expand Down