Skip to content

Commit

Permalink
Move launcher tests to their own job to make it faster to re-run on f…
Browse files Browse the repository at this point in the history
…ailure (kolide#2002)
  • Loading branch information
RebeccaMahany authored Dec 16, 2024
1 parent 0c60d4c commit 338c676
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 24 deletions.
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

0 comments on commit 338c676

Please sign in to comment.