Skip to main content

Running in CI

A petri suite needs only go test: no service containers and no setup step. Three things need attention: the build cache, memory, and timeouts.

Cache the build​

The first build of a package that imports petri compiles kube-apiserver and the controllers. That takes a few minutes on a CI runner. Later builds come from Go's build cache, so keep that cache between runs. actions/setup-go does this by default, keyed on go.sum.

.github/workflows/test.yml
name: Test
on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod # caches the module and build caches
- run: go test -race -p 2 -timeout 20m ./...

Memory and -race​

Each package that starts a control plane holds one in memory: about 300 MiB, or 1 to 1.5 GiB under -race. Linking a test binary under -race takes about 3 GiB. Resource usage has the measurements and explains why.

go test ./... builds and runs as many packages at once as there are CPUs, which can run a small runner out of memory. To lower the load:

  • run fewer packages at once with -p 2 or -p 1;
  • run fewer tests at once within a package with -parallel N;
  • use -race where it pays off. Keep it for packages with your own concurrent code, and consider dropping it for packages that only call the API.

If a job is killed without a test failure, or the log shows signal: killed, the cause is almost always memory.

Timeouts​

Go's default test timeout is 10 minutes per package. Compile time does not count against it, but a large package of end-to-end tests under -race can still get close. Set -timeout explicitly, as above.

petri's waits time out after 30 seconds by default. On a slow runner, give the waits that need it a longer timeout with petri.WithTimeout, rather than retrying whole tests.