Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions .github/workflows/server-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
branches: ["main"]
workflow_dispatch:

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

jobs:
build-headful:
uses: ./.github/workflows/chromium-headful-image.yaml
Expand All @@ -16,7 +20,27 @@ jobs:
uses: ./.github/workflows/chromium-headless-image.yaml
secrets: inherit

test:
test-server-unit:
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: "server/go.mod"
cache: true
cache-dependency-path: server/go.sum

- name: Run server unit tests
run: make test-unit
working-directory: server

test-server-e2e:
runs-on: ubuntu-latest
needs: [build-headful, build-headless]
permissions:
Expand All @@ -39,11 +63,21 @@ jobs:
with:
version: 10

- name: Add pnpm to PATH
run: |
echo "$PNPM_HOME" >> "$GITHUB_PATH"
export PATH="$PNPM_HOME:$PATH"
pnpm --version

- name: Install Playwright e2e dependencies
run: pnpm install --frozen-lockfile
working-directory: server/e2e/playwright

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: "server/go.mod"
cache: true
cache: false

- name: Compute short SHA for images
id: vars
Expand All @@ -56,8 +90,8 @@ jobs:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Run server Makefile tests
run: make test
- name: Run server e2e tests
run: make test-e2e
working-directory: server
env:
E2E_CHROMIUM_HEADFUL_IMAGE: onkernel/chromium-headful:${{ steps.vars.outputs.short_sha }}
Expand Down
2 changes: 1 addition & 1 deletion server/e2e/backend_docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func (c *dockerBackend) Stop(ctx context.Context) error {
if c.ctr == nil {
return nil
}
return testcontainers.TerminateContainer(c.ctr)
return testcontainers.TerminateContainer(c.ctr, testcontainers.StopTimeout(0))
}

// APIBaseURL returns the URL for the container's API server.
Expand Down
46 changes: 41 additions & 5 deletions server/e2e/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"strings"
"testing"
"time"

instanceoapi "github.com/kernel/kernel-images/server/lib/oapi"
)
Expand Down Expand Up @@ -44,15 +45,23 @@ func NewTestContainer(tb testing.TB, image string) *TestContainer {
// from the runner's loopback that a remote instance cannot reach. This keeps the
// hypeman CI job green while preserving coverage on the Docker backend.
func (c *TestContainer) Start(ctx context.Context, cfg ContainerConfig) error {
c.tb.Helper()
start := time.Now()
if cfg.HostAccess && !c.backend.SupportsHostAccess() {
c.tb.Skipf("skipping host-access test: %s backend has no host-loopback bridge for the instance", backendKindFromEnv())
}
return c.backend.Start(ctx, cfg)
err := c.backend.Start(ctx, cfg)
c.logTiming("start", start, err)
return err
}

// Stop stops and removes the instance.
func (c *TestContainer) Stop(ctx context.Context) error {
return c.backend.Stop(ctx)
c.tb.Helper()
start := time.Now()
err := c.backend.Stop(ctx)
c.logTiming("stop", start, err)
return err
}

// APIBaseURL returns the URL for the instance's API server.
Expand Down Expand Up @@ -112,18 +121,30 @@ func (c *TestContainer) APIClientNoKeepAlive() (*instanceoapi.ClientWithResponse

// WaitReady waits for the instance's API to become ready.
func (c *TestContainer) WaitReady(ctx context.Context) error {
return c.backend.WaitReady(ctx)
c.tb.Helper()
start := time.Now()
err := c.backend.WaitReady(ctx)
c.logTiming("wait_ready", start, err)
return err
}

// WaitDevTools waits for the CDP WebSocket endpoint to be ready.
func (c *TestContainer) WaitDevTools(ctx context.Context) error {
return c.backend.WaitDevTools(ctx)
c.tb.Helper()
start := time.Now()
err := c.backend.WaitDevTools(ctx)
c.logTiming("wait_devtools", start, err)
return err
}

// WaitChromeDriver waits for the ChromeDriver proxy (and upstream ChromeDriver)
// to be ready.
func (c *TestContainer) WaitChromeDriver(ctx context.Context) error {
return c.backend.WaitChromeDriver(ctx)
c.tb.Helper()
start := time.Now()
err := c.backend.WaitChromeDriver(ctx)
c.logTiming("wait_chromedriver", start, err)
return err
}

// Exec executes a command inside the instance and returns the exit code and
Expand All @@ -136,3 +157,18 @@ func (c *TestContainer) Exec(ctx context.Context, cmd []string) (int, string, er
func (c *TestContainer) ExitCh() <-chan error {
return c.backend.ExitCh()
}

func (c *TestContainer) logTiming(phase string, start time.Time, err error) {
status := "ok"
if err != nil {
status = "error"
}
c.tb.Logf("[e2e-timing] test=%q phase=%s backend=%s image=%s duration=%s status=%s",
c.tb.Name(),
phase,
backendKindFromEnv(),
c.Image,
time.Since(start).Truncate(time.Millisecond),
status,
)
}
2 changes: 2 additions & 0 deletions server/e2e/e2e_chromium_configure_powerset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const (
// TestChromiumConfigureMultipartPowerset runs a representative matrix by default.
// Set E2E_CHROMIUM_CONFIGURE_POWERSET=1 to run every non-empty combination.
func TestChromiumConfigureMultipartPowerset(t *testing.T) {
t.Parallel()

if _, err := exec.LookPath("docker"); err != nil {
t.Skipf("docker not available: %v", err)
Expand All @@ -57,6 +58,7 @@ func TestChromiumConfigureMultipartPowerset(t *testing.T) {
for _, bits := range matrix {
bits := bits
t.Run(chromiumConfigurePowersetLabel(bits), func(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithTimeout(context.Background(), 6*time.Minute)
defer cancel()
Expand Down
5 changes: 5 additions & 0 deletions server/e2e/e2e_chromium_restart_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ func doChromiumRestart(ctx context.Context, client *instanceoapi.ClientWithRespo
// Useful for quick iteration without the full benchmark harness.
// Run with: go test -v -run TestChromiumRestartTiming ./e2e/...
func TestChromiumRestartTiming(t *testing.T) {
t.Parallel()

if _, err := exec.LookPath("docker"); err != nil {
t.Skip("docker not available")
}
Expand All @@ -284,7 +286,10 @@ func TestChromiumRestartTiming(t *testing.T) {
const iterations = 3

for _, img := range images {
img := img
t.Run(img.name, func(t *testing.T) {
t.Parallel()

c := NewTestContainer(t, img.image)

env := map[string]string{
Expand Down
Loading
Loading