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

Move launcher tests to their own job to make it faster to re-run on failure #2002

Merged
merged 13 commits into from
Dec 16, 2024
Merged
80 changes: 66 additions & 14 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:


jobs:
build_and_test:
build:
name: launcher
runs-on: ${{ matrix.os }}
strategy:
Expand Down Expand Up @@ -79,31 +79,20 @@ jobs:
run: make github-launcherapp
if: ${{ contains(matrix.os, 'macos') }}

- name: Test
run: make test

- name: Cache build output
uses: actions/cache@v4
with:
path: ./build
key: ${{ runner.os }}-${{ github.run_id }}
enableCrossOsArchive: true

# upload coverage here, because we don't cache it with the build
- name: Upload coverage
uses: actions/upload-artifact@v4
with:
name: ${{ runner.os }}-coverage.out
path: ./coverage.out
if-no-files-found: error

# this job captures the version of launcher on one of the runners then that version is
# compared to the version of all other runners during exec testing. This is to ensure
# that the version of launcher is the same across all runners.
version_baseline:
name: Version Baseline
runs-on: ubuntu-20.04
needs: build_and_test
needs: build
outputs:
version: ${{ steps.version.outputs.version }}
steps:
Expand All @@ -120,6 +109,68 @@ jobs:
shell: bash
run: ./launcher --version 2>/dev/null | awk '/version /{print "version="$4}' >> "$GITHUB_OUTPUT"

launcher_test:
name: test
needs: build # a desktop runner test requires a build to exist
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-20.04
- macos-13
- windows-latest
steps:
- name: Check out code
id: checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # need a full checkout for `git describe`

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: './go.mod'
check-latest: true
cache: false

- name: cache restore - build
uses: actions/cache/restore@v4
with:
path: ./build
key: ${{ runner.os }}-${{ github.run_id }}
enableCrossOsArchive: true

- id: go-cache-paths
shell: bash
run: |
echo "go-build=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
echo "go-mod=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"

- name: cache restore - GOCACHE
uses: actions/cache/restore@v4
with:
path: ${{ steps.go-cache-paths.outputs.go-build }}
key: ${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }}
enableCrossOsArchive: true

- name: cache restore - GOMODCACHE
uses: actions/cache/restore@v4
with:
path: ${{ steps.go-cache-paths.outputs.go-mod }}
key: ${{ runner.os }}-go-mod-${{ hashFiles('**/go.sum') }}
enableCrossOsArchive: true

- name: Test
run: make test

- name: Upload coverage
uses: actions/upload-artifact@v4
with:
name: ${{ runner.os }}-coverage.out
path: ./coverage.out
if-no-files-found: error

exec_testing:
name: Exec Test
runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -270,6 +321,7 @@ jobs:
steps:
- run: true
needs:
- build_and_test
- build
- launcher_test
- package_builder_test
- exec_testing
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ proto:
@echo "Generated code from proto definitions."

test: generate
go test -cover -coverprofile=coverage.out -race $(shell go list ./... | grep -v /vendor/)
go test -cover -coverprofile=coverage.out -race ./...

##
## Lint
Expand Down
77 changes: 68 additions & 9 deletions ee/desktop/runner/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,25 @@ func TestDesktopUserProcessRunner_Execute(t *testing.T) {
}

// due to flakey tests we are tracking the time it takes to build and attempting emit a meaningful error if we time out
timeout := time.Second * 60
timeout := time.Minute * 2
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()

cmd := exec.CommandContext(ctx, "go", "build", "-o", executablePath, "../../../cmd/launcher") //nolint:forbidigo // Fine to use exec.CommandContext in test
buildStartTime := time.Now()
out, err := cmd.CombinedOutput()
if err != nil {
err = fmt.Errorf("building launcher binary for desktop testing: %w", err)
// We may already have a built binary available -- check for that first
if err := symlinkPreexistingBinary(ctx, executablePath); err != nil {
// No binary available -- build one instead
cmd := exec.CommandContext(ctx, "go", "build", "-o", executablePath, "../../../cmd/launcher") //nolint:forbidigo // Fine to use exec.CommandContext in test
buildStartTime := time.Now()
out, err := cmd.CombinedOutput()
if err != nil {
err = fmt.Errorf("building launcher binary for desktop testing: %w", err)

if time.Since(buildStartTime) >= timeout {
err = fmt.Errorf("timeout (%v) met: %w", timeout, err)
if time.Since(buildStartTime) >= timeout {
err = fmt.Errorf("timeout (%v) met: %w", timeout, err)
}
}
require.NoError(t, err, string(out))
}
require.NoError(t, err, string(out))

tests := []struct {
name string
Expand Down Expand Up @@ -238,6 +242,61 @@ func TestDesktopUserProcessRunner_Execute(t *testing.T) {
}
}

func symlinkPreexistingBinary(ctx context.Context, executablePath string) error {
builtBinaryPath := filepath.Join("..", "..", "..", "build", "launcher")
if runtime.GOOS == "windows" {
builtBinaryPath += "launcher.exe"
}
absPath, err := filepath.Abs(builtBinaryPath)
if err != nil {
return fmt.Errorf("getting absolute path for %s: %w", builtBinaryPath, err)
}
builtBinaryPath = filepath.Clean(absPath)

// See if file exists
if _, err := os.Stat(builtBinaryPath); os.IsNotExist(err) {
return fmt.Errorf("no preexisting binary at %s", builtBinaryPath)
}

// Get our current version
gitCmd := exec.CommandContext(ctx, "git", "describe", "--tags", "--always", "--dirty") //nolint:forbidigo // Fine to use exec.CommandContext in test
versionOut, err := gitCmd.CombinedOutput()
if err != nil {
return fmt.Errorf("getting current version: %w", err)
}
currentVersion := strings.TrimPrefix(strings.TrimSpace(string(versionOut)), "v")

// Binary exists -- see if the version is a match
cmd := exec.CommandContext(ctx, builtBinaryPath, "-version") //nolint:forbidigo // Fine to use exec.CommandContext in test
cmd.Env = append(cmd.Environ(), "LAUNCHER_SKIP_UPDATES=TRUE")
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("checking version: %w", err)
}

lines := strings.Split(string(out), "\n")
binaryVersion := ""
for _, line := range lines {
if !strings.HasPrefix(line, "launcher - version") {
continue
}

// We found the version
binaryVersion = strings.TrimSpace(strings.TrimPrefix(line, "launcher - version"))
break
}

if binaryVersion != currentVersion {
return fmt.Errorf("built version %s does not match current version %s", binaryVersion, currentVersion)
}

if err := os.MkdirAll(filepath.Dir(executablePath), 0755); err != nil {
return fmt.Errorf("making test dir: %w", err)
}

return os.Symlink(builtBinaryPath, executablePath)
}

func launcherRootDir(t *testing.T) string {
safeTestName := fmt.Sprintf("%s_%s", "launcher_desktop_test", ulid.New())

Expand Down
Loading