Repository navigation
ci(e2e): add Gherkin behaviour tests with dummy runtime #1982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
13e3634
ci(e2e): add Gherkin behaviour tests with dummy runtime
ifireball 5b4a7b4
ci(e2e): enroll pool test-repos in mint during behaviour install
ifireball 8d2c52a
docs(e2e): document CI IAM for behaviour per-repo mint enroll
ifireball 89629a1
ci(e2e): use hosted mint project for behaviour mint enroll
ifireball 49dd246
ci(e2e): log GCP principal during behaviour mint enroll
ifireball fd17c07
ci(e2e): log WIF provider during behaviour mint enroll
ifireball be84139
fix(mint): discover Gen2 mint via Cloud Run for WIF CI
ifireball b85e28f
fix(mint): surface Cloud Run discovery errors from DiscoverMint
ifireball 200b7e4
ci(e2e): drop CI mint enroll from behaviour install driver
ifireball 34d53a8
ci(e2e): provision repo-scoped inference WIF in behaviour install
ifireball 591934a
ci(e2e): use dummy runtime config path in per-repo triage
ifireball 014ee98
merge: integrate main (PR #3000 per-repo config fix)
ifireball d2ec4dd
Signed-off-by: Barak Korren <bkorren@redhat.com>
ifireball 14fcc69
ci(e2e): fix ADR 0065 numbering and gofmt after main merge
ifireball 4c760fd
fix(runtime): treat dummy scripted op failures as exit code only
ifireball 95e3190
test: cover dummy Run op-failure exit path for codecov patch
ifireball c395ea9
test: cover fake workflow helpers for codecov patch
ifireball 69a35e0
test: expand dummy runtime and github setup coverage
ifireball 2dc14f6
ci(e2e): address behaviour PR review findings
ifireball 7e6d438
merge: integrate main
ifireball d51bfc8
merge: integrate main
ifireball 6dc0c32
ci(e2e): address maruiz93 review feedback
ifireball ddffbe5
ci(e2e): re-trigger CI after e2e flake
ifireball 5c4cd4f
ci(e2e): address Review Squad findings on behaviour suite
ifireball e967c12
merge: integrate main
ifireball 699beb8
ci(e2e): preserve CI behaviour artifacts for upload
ifireball 0b57325
docs(adr): renumber behaviour ADR to 0066
ifireball File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
docs/ADRs/0066-behaviour-tests-with-gherkin-and-drivers.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| --- | ||
| title: "66. Behaviour tests with Gherkin and pluggable drivers" | ||
| status: Accepted | ||
| relates_to: | ||
| - agent-infrastructure | ||
| - agent-architecture | ||
| topics: | ||
| - e2e | ||
| - testing | ||
| - behaviour-tests | ||
| --- | ||
|
|
||
| # 66. Behaviour tests with Gherkin and pluggable drivers | ||
|
|
||
| Date: 2026-06-07 | ||
|
|
||
| ## Status | ||
|
|
||
| Accepted | ||
|
|
||
| ## Context | ||
|
|
||
| Fullsend needs end-to-end tests that validate **deterministic platform behaviour** — dispatch routing, harness loading, schema validation, post-scripts, token scoping, sandbox policy, and SCM mutations — without depending on LLM output. This is distinct from admin install e2e ([ADR 0040](0040-org-pool-for-parallel-e2e-tests.md)) and from LLM/instruction testing ([testing-agents.md](../problems/testing-agents.md)). | ||
|
|
||
| Runtime selection is shared with production via `defaults.runtime` in org `config.yaml` ([runtimes.md](../runtimes.md)). Harness definitions remain as in [ADR 0024](0024-harness-definitions.md). Per-repo install mode ([ADR 0033](0033-per-repo-installation-mode.md)) is the behaviour v1 default; per-org install is deferred. | ||
|
|
||
| ## Decision | ||
|
|
||
| - Add **behaviour tests** under `e2e/behaviour/` using **godog** and portable Gherkin feature files. | ||
| - Exercise **real SCM + real CI** through **driver interfaces** (`scm.Driver`, `ci.Driver`, `install.Driver`); v1 implementations target GitHub and GitHub Actions. | ||
| - Substitute inference with a **dummy runtime** (`runtime: dummy` in per-repo config, or `defaults.runtime: dummy` for per-org) that executes scripted operations in the real OpenShell sandbox and emits `behaviour-results.json`. | ||
| - Select backends via **runner env** (`BEHAVIOUR_SCM`, `BEHAVIOUR_CI`, `BEHAVIOUR_INSTALL_MODE`); feature files stay install-mode agnostic. v1 runs **per-repo** against the halfsend org pool; the suite provisions fullsend via `fullsend github setup` rather than requiring pre-installed orgs. | ||
| - Use **compatibility tags** (`@skip:*`, `@requires:*`) to filter scenarios for future backends; tags do not select configuration. | ||
|
|
||
| ## Consequences | ||
|
|
||
| - Behaviour tests can pass while prompt quality regresses; LLM evals remain necessary for instruction coverage. | ||
| - Behaviour orgs are provisioned at suite start with `--runtime dummy`; production orgs must not use dummy unintentionally. | ||
| - Adding GitLab or Tekton requires new drivers and runner env values, not feature file rewrites. | ||
| - Dummy runtime op vocabulary stays minimal; new ops require runtime + docs updates when scenarios need them. | ||
| - Behaviour tests depend on live external infrastructure: GitHub API, GitHub Actions runners, GCP WIF/mint, and the shared halfsend org pool. Transient outages, API rate limits, or pool org state corruption can fail the suite; CI distinguishes infrastructure failures from regressions via workflow logs and artifact inspection, but there is no offline fallback. | ||
| - Behaviour tests share the halfsend org pool and lock mechanism with admin e2e tests (`e2e.yml` runs both jobs). Lock hold time scales with scenario count; pool size was doubled to absorb the additional load and can be increased again if contention appears. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # Behaviour test drivers | ||
|
|
||
| Behaviour tests isolate forge-specific code behind drivers so Gherkin scenarios stay portable. | ||
|
|
||
| ## Interfaces | ||
|
|
||
| | Interface | Package | Responsibility | | ||
| |-----------|---------|----------------| | ||
| | `scm.Driver` | `e2e/behaviour/drivers/scm` | Issues, comments, labels (via GetIssue), file commits | | ||
| | `ci.Driver` | `e2e/behaviour/drivers/ci` | Workflow polling, logs, artifact download | | ||
| | `install.Driver` | `e2e/behaviour/drivers/install` | Provision and tear down fullsend in the acquired pool org | | ||
| | `install.State` | `e2e/behaviour/drivers/install` | Post-install config paths (script commits, workflow polling) | | ||
|
|
||
| v1 reference implementations: | ||
|
|
||
| - `e2e/behaviour/drivers/scm/github/` | ||
| - `e2e/behaviour/drivers/ci/githubactions/` | ||
| - `e2e/behaviour/drivers/install/perrepo_github.go` (`BEHAVIOUR_INSTALL_MODE=per-repo`) | ||
|
|
||
| ## Runner configuration | ||
|
|
||
| Set when starting the suite (not in feature files): | ||
|
|
||
| ``` | ||
| BEHAVIOUR_SCM=github # future: gitlab, forgejo | ||
| BEHAVIOUR_CI=githubactions # future: tekton, gitlabci | ||
| BEHAVIOUR_INSTALL_MODE=per-repo # v1 default and only supported value | ||
| ``` | ||
|
|
||
| The suite in `e2e/behaviour/suite_test.go` acquires a pool org, runs pre-install cleanup, calls `install.Driver.Install`, then constructs SCM and CI drivers. Unsupported `BEHAVIOUR_INSTALL_MODE` values fail at suite startup. | ||
|
|
||
| ### Install driver (v1 per-repo) | ||
|
|
||
| Uses `fullsend inference provision <org>/test-repo` then `fullsend github setup <org>/test-repo --vendor --direct --skip-app-setup --runtime dummy` with the repo-scoped WIF provider from provision (`E2E_GCP_PROJECT_ID`). Pool orgs must already have shared GitHub Apps, org-level mint enrollment, and per-repo mint enrollment for `test-repo` (one-time GCP admin step on the hosted mint project). The driver does not run `fullsend admin install` or `fullsend mint enroll`. See [e2e-testing.md](e2e-testing.md#behaviour-tests-and-per-repo-mint-enrollment). | ||
|
|
||
| Teardown removes shim workflows, stale branches, and open fullsend PRs on `test-repo` via shared helpers in `e2e/admin/cleanup.go`. | ||
|
|
||
| ## Adding an SCM driver | ||
|
|
||
| 1. Implement `scm.Driver` in `e2e/behaviour/drivers/scm/<vendor>/`. | ||
| 2. Register the driver in `suite_test.go` when `BEHAVIOUR_SCM=<vendor>`. | ||
| 3. Document the env var value here. | ||
| 4. Add `@skip:<vendor>` tags on scenarios that cannot run until the driver is complete. | ||
|
|
||
| Use `forge.Client` for operations it already exposes; add REST helpers inside the driver package only when necessary (e.g. `GetIssue` with labels). | ||
|
|
||
| ## Adding a CI driver | ||
|
|
||
| 1. Implement `ci.Driver` — `WaitForWorkflow`, `AssertNoWorkflow`, `GetRunLogs`, `DownloadArtifacts`. | ||
| 2. Map forge `WorkflowRun` types to portable polling logic; reuse patterns from `e2e/admin/admin_test.go`. | ||
| 3. Register in suite init for the matching `BEHAVIOUR_CI` value. | ||
|
|
||
| ## Step definitions | ||
|
|
||
| Steps must **not** import `internal/forge/github` directly — only drivers. This keeps scenarios vendor-agnostic. | ||
|
|
||
| Steps use `world.Install` for config repo paths (`ConfigOwner`, `ConfigRepo`, `ConfigPathPrefix`) instead of hardcoding the per-org `.fullsend` config repo. | ||
|
|
||
| ## Testing drivers | ||
|
|
||
| Prefer unit tests with `httptest` for REST helpers. Optional smoke scenarios against live backends mirror admin e2e credentials (`GITHUB_TOKEN`, halfsend org pool). | ||
|
|
||
| ## Future backends checklist | ||
|
|
||
| - [ ] GitLab SCM driver + `@skip:gitlab` tag removal | ||
| - [ ] Tekton or GitLab CI driver | ||
| - [ ] Per-org install driver (`BEHAVIOUR_INSTALL_MODE=per-org`) | ||
| - [ ] Non-GitHub install backends |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| # Behaviour testing | ||
|
|
||
| End-to-end Gherkin tests under `e2e/behaviour/` validate **deterministic platform code** with inference removed. They are **orthogonal** to LLM and instruction testing in [testing-agents.md](../../problems/testing-agents.md) and to admin install e2e in `e2e/admin/`. | ||
|
|
||
| | | Behaviour tests | LLM evals | Admin e2e | Unit tests | | ||
| |---|-----------------|-----------|-----------|------------| | ||
| | **Target** | Platform workflows, sandbox, SCM | Prompts, models | Install/uninstall | Go functions | | ||
| | **Inference** | Dummy runtime | Real LLM | Real LLM | N/A | | ||
| | **Infrastructure** | Live GitHub + GHA | Varies | Live GitHub + GHA | None | | ||
|
|
||
| ## When to add a behaviour test | ||
|
|
||
| Add one when a **user-visible workflow** must be verified end-to-end (dispatch → workflow → post-script → SCM state) and the assertion is **binary**. Prefer unit tests for pure Go logic and admin e2e for install provisioning. | ||
|
|
||
| ## Layout | ||
|
|
||
| ``` | ||
| e2e/behaviour/ | ||
| features/ # Portable Gherkin scenarios | ||
| fixtures/ # Static content for write_fixture ops | ||
| steps/ # Step definitions | ||
| world/ # Scenario state | ||
| drivers/ # SCM, CI, env interfaces + v1 impls | ||
| suite_test.go # godog entry (build tag: behaviour) | ||
| ``` | ||
|
|
||
| ## Writing scenarios | ||
|
|
||
| Describe **user-visible behaviour** only. Do not encode SCM vendor, CI platform, or install mode in feature files. | ||
|
|
||
| ### Dummy agent tables | ||
|
|
||
| ```gherkin | ||
| Given a dummy agent that would: | ||
| | description | op | args | | ||
| | Emit triage JSON | write_fixture | output/agent-result.json, fixtures/triage/sufficient.json | | ||
| ``` | ||
|
|
||
| | Column | Meaning | | ||
| |--------|---------| | ||
| | `description` | Human label matched by assertion steps | | ||
| | `op` | `read_file`, `url_get`, `write_fixture` | | ||
| | `args` | Op-specific; see below | | ||
|
|
||
| **`write_fixture`:** `dest_path, fixtures/...` — content lives in `e2e/behaviour/fixtures/`, embedded in the committed scenario script at `.fullsend/behaviour/current-scenario.yaml`. | ||
|
|
||
| ### Assertion steps | ||
|
|
||
| Each assertion verifies immediately against workflow artifacts. If the triage workflow has not been waited on yet, the step waits for completion and downloads artifacts first (same as `Then the triage workflow completes successfully`). | ||
|
|
||
| ```gherkin | ||
| Then the agent will succeed to Emit triage JSON | ||
| And the agent will fail to Search for foo | ||
| And the agent will output issues.out with: | ||
| """ | ||
| expected content | ||
| """ | ||
| ``` | ||
|
|
||
| ### Compatibility tags | ||
|
|
||
| Use tags only for **exceptions** when a backend cannot run a scenario yet: `@skip:gitlab`, `@skip:per-org`, `@requires:per-repo`. Untagged scenarios run everywhere applicable. | ||
|
|
||
| ## Running locally | ||
|
|
||
| ```bash | ||
| # Local: gh auth login or export GH_TOKEN/GITHUB_TOKEN with access to halfsend org pool | ||
| make behaviour-test | ||
| ``` | ||
|
|
||
| In CI, the test runner mints cross-org `e2e` installation tokens via OIDC (same as admin e2e) for GitHub API operations. Triage workflows on the pool org's `test-repo` mint same-org `triage` tokens from vendored reusable workflows; those require per-repo mint enrollment (`PER_REPO_WIF_REPOS`) on the hosted mint project. Pool `test-repo` repos are enrolled once by a GCP admin — not during CI install. The install driver provisions repo-scoped inference WIF via `fullsend inference provision` before `github setup`. See [e2e-testing.md](e2e-testing.md#behaviour-tests-and-per-repo-mint-enrollment). | ||
|
|
||
| Runner env (defaults shown): | ||
|
|
||
| ``` | ||
| BEHAVIOUR_SCM=github | ||
| BEHAVIOUR_CI=githubactions | ||
| BEHAVIOUR_INSTALL_MODE=per-repo | ||
| E2E_GCP_PROJECT_ID=... # inference project; install runs inference provision per pool repo | ||
| E2E_GCP_WIF_PROVIDER=... # CI job GCP auth (not written to pool test-repo secrets) | ||
| ``` | ||
|
|
||
| Triage scenarios apply the `ready-for-triage` label (not `/fs-triage` comments) because the per-repo shim ignores `issue_comment` events from bot users and CI uses minted e2e installation tokens. | ||
|
|
||
| See [behaviour-drivers.md](behaviour-drivers.md) for driver configuration and [ADR 0066](../../ADRs/0066-behaviour-tests-with-gherkin-and-drivers.md) for the decision record. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.