Skip to content

Writing Test Plans ​

Test plans are Markdown documents under tests/plans/ designed for execution by both humans and AI agents.

Structure ​

A test plan has three layers:

  1. Main plan (tests/plans/<name>.md) — the test scenario with phases and assertions.
  2. Common steps (tests/plans/common/*.md) — reusable procedures shared across plans (Keycloak setup, namespace creation, cleanup).
  3. Environment variables — all configurable values declared upfront so the same plan works across versions and clusters.

Phases, not scripts ​

Organize tests into numbered phases that run sequentially. Each phase groups related assertions. This makes it easy to skip phases, resume after failure, or run a subset.

text
Phase 0: Manual prerequisites
Phase 1: Environment setup
Phase 2-N: Test scenarios
Phase N+1: Cleanup

Every step must be verifiable ​

Each step needs: a command, an expected outcome, and a PASS/FAIL assertion. Avoid steps that only run a command without checking the result.

bash
# Bad — runs but doesn't verify
oc apply -f my-resource.yaml

# Good — verifies the outcome
oc apply -f my-resource.yaml
oc wait myresource/name --for=condition=Ready --timeout=120s -n "${NAMESPACE}"

Prefer polling over sleeping ​

Use oc wait, oc rollout status, or a polling loop instead of fixed sleep calls. Clusters vary in speed — a 10s sleep that works locally may fail in CI and waste time on fast clusters.

bash
# Bad
sleep 15
oc get deployment foo

# Good — deterministic wait
oc wait --for=condition=Available deployment/foo --timeout=120s -n "${NAMESPACE}"

# Good — polling for deletion
while oc get deployment foo -n "${NAMESPACE}" > /dev/null 2>&1; do
  sleep 3
done

Parametrize images and versions ​

Never hard-code image tags. Define environment variables with sensible defaults so the same plan can test different releases.

bash
export MY_IMAGE="${MY_IMAGE:-quay.io/org/component:latest}"

Then use ${MY_IMAGE} in CR specs and image assertions.

Extract reusable steps into common docs ​

If a procedure appears in more than one plan (or is likely to), move it to tests/plans/common/. The common doc should:

  • List its prerequisites and required environment variables.
  • Document output variables it sets for subsequent steps.
  • Be self-contained — runnable without reading the main plan.

Reference common docs from the main plan with a link and a brief note on what variables must be set before and after:

markdown
Follow [common/keycloak-setup.md](common/keycloak-setup.md). After completion,
`KEYCLOAK_URL` and `WANAKU_OIDC_SECRET` must be set.

Keep the main plan lean ​

The main plan should only contain logic unique to that test scenario. If a step duplicates a common doc, replace it with a reference. This prevents drift between documents.

Use the Wanaku CLI, not raw API clients ​

Test plans must use the Wanaku CLI for all interactions with the router and Keycloak. Use either a native binary installed on the system or — preferably — the CLI jar file built from the codebase (java -jar apps/wanaku-cli/target/quarkus-app/quarkus-run.jar).

Do not use curl, wget, httpie, or other HTTP clients to call Wanaku or Keycloak APIs unless the test is specifically oriented to verify HTTP-level behavior (e.g., checking raw HTTP status codes on health endpoints, testing SSE streaming headers, or verifying endpoint reachability before the CLI can connect).

bash
# Bad — uses curl to list tools
curl -s "${WANAKU_ROUTER_URL}/api/v1/tools" | jq '.data[].name'

# Good — uses the CLI
wanaku tools list --host "${WANAKU_ROUTER_URL}" --plain

# Acceptable — specifically testing HTTP endpoint reachability
curl -s -o /dev/null -w "%{http_code}" "${WANAKU_ROUTER_URL}/q/health/ready"

Shell compatibility ​

Use POSIX-compatible constructs. Avoid bash-only features like ${!VAR} (indirect expansion) since the executor may use zsh or sh. If bash is required, wrap the block in bash -c '...'.

Include negative tests ​

Verify that invalid inputs are rejected gracefully — missing required fields, references to non-existent resources, malformed data. These often catch real bugs.

Re-augmentation for local test plans ​

Test plans that run locally (not on OpenShift) must re-augment the router before starting it. The router ships with OIDC authentication enabled, and without a Keycloak instance it will fail to start. Re-augmentation disables OIDC at Quarkus build time so the router can run unauthenticated.

After unzipping the router distribution, run:

bash
java -Dquarkus.launch.rebuild=true \
     -Dquarkus.log.level=WARNING \
     -Dquarkus.oidc.enabled=false \
     -Dquarkus.oidc-proxy.enabled=false \
     -jar quarkus-run.jar

Then start the router with WANAKU_HTTP_AUTH=none and -Dquarkus.profile=local. This is not needed for OpenShift-based test plans, where Keycloak is deployed as part of the environment setup.

Cleanup must be idempotent ​

Use --ignore-not-found=true on all delete commands and 2>/dev/null || true on wait commands. A cleanup phase that fails on missing resources makes re-runs painful.

Checklist for new plans ​

  • [ ] All configurable values are environment variables with defaults
  • [ ] Common procedures reference shared docs, not inline copies
  • [ ] Every step has a PASS/FAIL assertion
  • [ ] No fixed sleep — use oc wait, oc rollout status, or polling
  • [ ] Uses the Wanaku CLI — no curl/wget/httpie against Wanaku or Keycloak unless specifically testing HTTP behavior
  • [ ] Negative tests are included
  • [ ] Cleanup is idempotent
  • [ ] Shell constructs are POSIX-compatible

Feature Matrix ​

  • OpenShift/Kubernetes
    • Does not support noauth (i.e.: running the router and capabilities without authentication, due to the need of re-augmentation).