# K8s Integration Tests

LLMS index: [llms.txt](/llms.txt) | Full content: [llms-full.txt](/llms-full.txt)

---

Smoke tests that verify tools container images work in a real Kubernetes
cluster. Each test creates short-lived pods, checks expected behavior, and
cleans up. Tests run automatically on every MR via the Konflux
[K8s test pipeline](https://hummingbird-project.io/l/k8s-test-pipeline-design).

## Test Runner

Tests are executed by [`ci/run_tests_k8s.sh`](../ci/run_tests_k8s.sh). For
each component it:

1. Reads `{component}/tests-k8s.yml`
2. Parses each test entry (YAML -> JSON via Python)
3. Runs the `command` block with `kubectl` wired to the target cluster
4. Cleans up labeled resources (`hum-k8s-test=<run-id>`) after each test

## Running Locally

Test against a local cluster (kind, minikube, or remote):

```bash
# Single component with a published image
IMAGE_URL=quay.io/hummingbird-ci/gitlab-ci:latest \
IMAGE_NAME=gitlab-ci--tools \
  ci/run_tests_k8s.sh --context kind-kind gitlab-ci--tools

# Single component with a locally-built image
podman build -t localhost/hummingbird-dashboard:dev hummingbird-dashboard/
kind load docker-image localhost/hummingbird-dashboard:dev
IMAGE_URL=localhost/hummingbird-dashboard:dev \
IMAGE_NAME=hummingbird-dashboard--tools \
  ci/run_tests_k8s.sh --context kind-kind hummingbird-dashboard--tools
```

## CI Integration

In Konflux, the `tools-k8s-test`
[IntegrationTestScenario](https://hummingbird-project.io/l/k8s-test-pipeline-design)
triggers on every MR. The pipeline:

1. Checks whether `tests-k8s.yml` exists for the changed component
2. Provisions an ephemeral
   [EaaS namespace](https://hummingbird-project.io/l/k8s-test-eaas)
3. Runs `ci/run_tests_k8s.sh` with the built image

Components without `tests-k8s.yml` skip the test (the pipeline exits early
after the check step).

When an MR touches multiple components in one PR-group snapshot, Konflux
runs a single group PipelineRun instead of one per component, invoking the
script once with `--group-component-name` (repeated) and per-component
`IMAGE_URL_<COMPONENT>` env vars instead of the single-component
`IMAGE_URL`/`IMAGE_NAME` pair. `--group-component-name` is handled
identically to `--component-name`.

## Adding Tests for a New Component

1. Create `{component}/tests-k8s.yml` with one or more named tests:

   ```yaml
   ---
   smoke-test:
     command: |
       name="${TEST_GROUP}-smoke-${TEST_RUN_ID}"
       kubectl run "${name}" --image="${TEST_IMAGE:?}" --restart=Never \
         --labels="${TEST_RUN_LABEL}" \
         --command -- echo "hello"
       kubectl wait --for=jsonpath='{.status.phase}'=Succeeded \
         "pod/${name}" --timeout=120s || test_fail "Pod did not succeed"
       kubectl logs "${name}"
   ```

2. Use `${TEST_IMAGE}` for the image under test, `${TEST_RUN_ID}` and
   `${TEST_RUN_LABEL}` for unique naming and cleanup.

3. Call `test_fail "message"` to fail a test with a clear message.

4. Keep tests fast (under 2 minutes) — these are smoke tests, not
   integration suites.

### Common pitfalls

- All lines in `command: |` block scalars must be indented relative to the
  `command` key. Unindented lines break YAML parsing.
- Use `command -v` instead of `which` to check for commands — `which` is not
  available in all container images.
- For multi-statement Python one-liners, use semicolons on a single line:
  `python3 -c 'import foo; import bar; print("ok")'`

## Debugging Failures

See the [EaaS and Debugging](https://hummingbird-project.io/l/k8s-test-eaas)
guide for accessing ephemeral namespaces and using Kubearchive for historical
PipelineRun data.
