Skip to content

test(suites): port the conformance suites onto testkit and run conformance-integration on the runner - #4774

Merged
elezar merged 10 commits into
mainfrom
test/3954-migrate-suites-to-testkit/matthewgrossman
Nov 2, 2026
Merged

elezar merged 10 commits into
mainfrom
test/3954-migrate-suites-to-testkit/matthewgrossman

Conversation

@matthewgrossman

@matthewgrossman matthewgrossman commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Summary

The required conformance-integration job moves from the old tmachine conformance path to the new test runner, and the conformance tests it runs move onto testkit.

Old state New state (this PR)
Tests The old conformance/cli Cargo suite (crates/openshell-conformance scenarios), built as a nextest archive. The same coverage rewritten on testkit in tests/suites/conformance/sandbox: cli, lifecycle, file-transfer, persistent-workspace and policy-advisor, next to smoke.
How conformance-integration runs them Through the tmachine conformance testsuite (an Ansible playbook) via integration-runner.yml. Through openshell-test-runner, via e2e-suites.yml. Same job ID, still required.
Environments Docker/deb, Podman rootful and rootless/rpm, k3s, HA k3s. The same five.
Testsuites in tmachine conformance and policy-advisor. Deleted, along with their playbooks and the old conformance test archive.
Branch E2E A separate e2e-suites job running the smoke row and #4891's Keycloak row. That job keeps running, but only the features family (the Keycloak row). The conformance rows run in conformance-integration, so neither run duplicates the other.
k3s failure evidence The playbook saved k3s and controller diagnostics. The runner saves the same diagnostics, and checks the Agent Sandbox controller after the guest boots.

What does not change in this PR: the old CLI suite (tests/suites/conformance/cli, e2e/support/conformance.sh) still runs in the Docker, Podman, Kubernetes and VM host lanes and mise run e2e:rust:push. It moves in the next PR (PR 5b). Nor do crates/openshell-conformance, the features and drivers suites, or e2e/rust.

The lifecycle, persistent-workspace, file-transfer and policy-advisor ports start from @elezar's draft #4629.

Context

Builds on the runner merged in #4773 and on #4891 (the features pattern, with the Keycloak example), which is now merged; this PR is based on main with it.

Related Issue

Part of #3954

Changes

  • testkit: cx.track and cx.adopt, for sandboxes a test creates through the CLI.
  • Suites: tests/suites/conformance/sandbox gains lifecycle, cli, persistent_workspace, file_transfer and policy_advisor next to smoke. persistent_workspace_survives_stop_start stays in conformance: every conformant driver keeps the workspace across stop and start. TESTING.md says what a conformance test may assert.
  • tmachine: Git in every test environment (test-tools.yaml), for the .gitignore filtering test; an Agent Sandbox readiness check in the k3s installers (k3s-controller-ready.yaml, moved out of the old conformance playbook), so tests don't wait for the controller. The runner repeats the check after it boots the guest (wait-k3s-controller.sh), because a booted guest restarts k3s and the controller; a failure there is an environment error, not a test failure.
  • e2e-suites.yml: a select job holds six rows: the five conformance rows (Docker deb, Podman rootful and rootless rpm, k3s and k3s HA, running the sandbox package) and test(features): run feature tests against environment services, starting with Keycloak #4891's Keycloak row (features, keycloak-provider-refresh). A gateway column says which gateway each installer registers (tmachine for the k3s installers, openshell for the others). A family input filters the rows, so each caller gets only its own rows and never a run where every row is skipped. The disk cache uses test(features): run feature tests against environment services, starting with Keycloak #4891's key (environment, installer and the tmachine setup inputs, no restore-keys fallback); the k3s environment still skips it, as integration-runner.yml does (its history doesn't say why, so that is still to find out).
  • Required lane: conformance-integration (same job ID; Branch E2E, Release Dev and Release Qualification depend on it) now runs the conformance rows through the runner (family: conformance) and passes CACHIX_AUTH_TOKEN. Branch E2E keeps test(features): run feature tests against environment services, starting with Keycloak #4891's e2e-suites job and its core-e2e-result entry, now with family: features.
  • Deleted: the tmachine conformance and policy-advisor testsuites, their playbooks and the old conformance test archive. The integration-runner and integration-test defaults no longer name conformance.
  • Parity, k3s diagnostics: on k3s and HA k3s, after a failed run the runner runs the old playbook's collect-k3s.sh (carried over unchanged except for its output handling) and saves diagnostics/k3s.txt; the systemd gateway journal is still saved for every run. Without it the newly required k3s rows would fail with no gateway logs. The script runs under a time limit in the guest, and what it wrote is copied out even when it ran out of time. A failure to collect never changes the test result. It has not yet run on a real k3s failure.
  • Docs: CI.md, the policy-advisor README and the watch-github-actions skill point at the runner and its e2e-results-* artifacts.

Old test to new test

Old New Notes
smoke (scenario: status, create, get Ready, list, exec, delete, list empty) cli.rs::cli_create_exec_list_delete Same CLI steps. smoke.rs::create_exec_delete is the SDK variant (in #4773).
sandbox_lifecycle stop_start_preserves_workspace persistent_workspace.rs::persistent_workspace_survives_stop_start (SDK) and cli.rs::cli_stop_start_delete (CLI) Also lifecycle.rs::restart_stopped_sandbox.
sandbox_lifecycle stopped_can_be_deleted lifecycle.rs::stopped_sandbox_can_be_deleted Also at the end of cli_stop_start_delete.
file_transfer::round_trip file_transfer.rs::upload_download_round_trip
file_transfer::git_filtering file_transfer.rs::upload_respects_gitignore Needs git where the tests run.
file_transfer::path_safety file_transfer.rs::download_stays_inside_workspace
policy_local policy_advisor.rs::policy_local_accepts_proposals
mechanistic_proposal policy_advisor.rs::denied_address_produces_draft_rule
new_hostname_proposal policy_advisor.rs::denied_hostname_produces_draft_rule

New with no old counterpart (from #4629): lifecycle.rs::long_running_exec_delete, run_to_completion_exit_delete, default_command_sandbox_is_listed_ready.

Not here

  • The old CLI suite (tests/suites/conformance/cli, e2e/support/conformance.sh) stays until the host lanes move to the new tests in the next PR (PR 5b). The required Docker, Podman, Kubernetes and VM lanes and mise run e2e:* still use it.
  • features and drivers (oci-image, Podman userns, e2e-podman) and deleting crates/openshell-conformance: later.
  • arm64: needs an arm64 KVM runner and arm64 build inputs.

Testing

  • Checks appropriate to the affected code and behavior pass
    • Locally: fmt (runner, tmachine, testkit), clippy -D warnings, runner and tmachine tests, lockfile alignment, license headers, and Nix evaluation of the runner, tmachine config and test archives.
    • On CI: Branch E2E run 40932543672 on an earlier head (4e6a9c4d8) passed: all five conformance-integration rows ran in tmachine VMs (Docker/deb, Podman rootful and rootless/rpm, k3s, HA k3s), along with the Select E2E suites and result jobs.
    • The k3s diagnostics, the post-boot controller wait and the persistent-workspace poll were added after that run. Branch E2E run 41098411898 on an earlier head (363f08150) passed.
    • Flake stress test: with the build artifacts from that run, e2e-suites.yml ran with family: conformance five times in parallel (run 41114006500, concurrency limit removed on a throwaway branch only). All 25 row-runs passed, 5 of 5 for each of Docker/deb, Podman rootful/rpm, Podman rootless/rpm, k3s and HA k3s. Counting the earlier green run, each row has passed 6 times. This includes the controller wait, the diagnostics code and the poll. Not covered: the k3s diagnostics only run after a failure, so they haven't run on a real failure, and five runs can't show a flake rarer than about 1 in 5.
    • This head (6726561d3) is rebased onto main after test(features): run feature tests against environment services, starting with Keycloak #4891 and fix(test): drop IPv6 loopback redirect from the Keycloak fixture realm #5089 merged. Branch E2E run 41387833584 and Branch Checks run 41387833616 passed on it: all five conformance-integration rows and the Keycloak e2e-suites row.
  • Unit tests added/updated
  • E2E tests added/updated

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated (TESTING.md, CI.md)

@copy-pr-bot

copy-pr-bot Bot commented Oct 20, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@github-actions

Copy link
Copy Markdown

@matthewgrossman
matthewgrossman force-pushed the test/3954-first-testkit-lane/matthewgrossman branch from 0b87fa4 to 0025ee3 Compare October 21, 2026 04:40
@copy-pr-bot

copy-pr-bot Bot commented Oct 21, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@matthewgrossman
matthewgrossman force-pushed the test/3954-migrate-suites-to-testkit/matthewgrossman branch 2 times, most recently from 6d64703 to e3d9f01 Compare October 21, 2026 20:40
@matthewgrossman
matthewgrossman force-pushed the test/3954-first-testkit-lane/matthewgrossman branch 2 times, most recently from e06a0eb to a23e140 Compare October 21, 2026 20:41
@matthewgrossman
matthewgrossman force-pushed the test/3954-migrate-suites-to-testkit/matthewgrossman branch from e3d9f01 to 5e2cbc5 Compare October 21, 2026 20:49
@matthewgrossman
matthewgrossman force-pushed the test/3954-migrate-suites-to-testkit/matthewgrossman branch from 5e2cbc5 to cda205f Compare October 21, 2026 23:45
@matthewgrossman
matthewgrossman force-pushed the test/3954-first-testkit-lane/matthewgrossman branch from 936e1fd to be4af48 Compare October 21, 2026 23:45
@matthewgrossman
matthewgrossman force-pushed the test/3954-migrate-suites-to-testkit/matthewgrossman branch from cda205f to 7c75fbf Compare October 22, 2026 04:51
@matthewgrossman
matthewgrossman force-pushed the test/3954-first-testkit-lane/matthewgrossman branch from be4af48 to 63f4141 Compare October 22, 2026 04:51
@matthewgrossman
matthewgrossman removed this pull request from stack #4776 October 22, 2026 04:51
@matthewgrossman
matthewgrossman force-pushed the test/3954-first-testkit-lane/matthewgrossman branch from 63f4141 to df44e02 Compare October 22, 2026 05:03
@matthewgrossman
matthewgrossman force-pushed the test/3954-migrate-suites-to-testkit/matthewgrossman branch from 7c75fbf to bb39723 Compare October 22, 2026 05:29
@matthewgrossman matthewgrossman changed the title test(suites): move the conformance, oci-image, provider-refresh and podman suites to testkit test(suites): port the old suites onto testkit and run them from the plan Oct 22, 2026
@matthewgrossman
matthewgrossman removed this pull request from stack #4824 October 22, 2026 05:29
@matthewgrossman
matthewgrossman removed this pull request from stack #4825 October 22, 2026 16:01
@matthewgrossman
matthewgrossman force-pushed the test/3954-first-testkit-lane/matthewgrossman branch from df44e02 to 4d19336 Compare October 22, 2026 16:01
@matthewgrossman
matthewgrossman force-pushed the test/3954-migrate-suites-to-testkit/matthewgrossman branch from bb39723 to 1cb1dc8 Compare October 22, 2026 16:01
@matthewgrossman
matthewgrossman force-pushed the test/3954-migrate-suites-to-testkit/matthewgrossman branch from 1cb1dc8 to fbcd389 Compare October 22, 2026 16:37
@matthewgrossman

Copy link
Copy Markdown
Member Author

/ok to test 4e6a9c4

@matthewgrossman
matthewgrossman force-pushed the test/3954-migrate-suites-to-testkit/matthewgrossman branch from fca661d to 363f081 Compare October 30, 2026 17:23
@matthewgrossman

Copy link
Copy Markdown
Member Author

/ok to test 363f081

matthewgrossman and others added 10 commits November 1, 2026 20:10
Add cx.track and cx.adopt, so a test that creates a sandbox through the CLI
still cleans it up after a failure: track the name before the command, adopt it
afterwards for an SDK handle.

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
…ent-workspace suites to testkit

Add the lifecycle, cli, persistent_workspace and file_transfer test files to the
sandbox crate. The lifecycle, persistent-workspace and file-transfer tests are
adapted from #4629. persistent_workspace_survives_stop_start
stays in conformance: every conformant driver keeps the workspace across stop
and start, and the one that can't yet (MXC) isn't conformant until it can.

The policy-advisor tests are ported in the next commit but one. The OCI image,
Keycloak and Podman userns suites are ported separately, in the features and
drivers families. The old conformance/cli crate stays until the host lanes move
off it.

Co-authored-by: Evan Lezar <elezar@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
The file-transfer suite builds a Git repository on the machine that runs the tests, and the old conformance playbook installed Git itself.

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
The k3s installer now waits until the Agent Sandbox controller reconciles a
gated probe Sandbox, so a test that starts right after boot doesn't race it.
The check moves out of the old conformance playbook into
tests/tmachine/ansible/playbooks/k3s-controller-ready.yaml, which the installer
and the old playbook both include. Tests themselves don't wait for the controller.

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Port the old suite's policy.local, denied-address and denied-hostname
scenarios as the policy-advisor suite, so they survive the deletion of
the old CLI suite. Adapted from #4629.

Co-authored-by: Evan Lezar <elezar@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Add a row for each conformance environment (Docker, Podman rootful and
rootless, k3s and HA k3s) next to the Docker and Keycloak rows. Each row
names the gateway its installer registers (`openshell`, or `tmachine` for
k3s) and the runner passes it with --gateway. A `family` input runs the
rows of one family, so a caller can run the conformance rows alone.

The disk cache is keyed per environment, and k3s skips it as
integration-runner.yml does.

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Switch the required conformance-integration job in Branch E2E, Release Dev
and Release Qualification from the tmachine conformance testsuite to the E2E
Suites workflow, selecting the conformance family. The job ID is unchanged.

Delete the tmachine conformance and policy-advisor testsuites, their
playbooks and the old conformance test archive: the sandbox package covers
the same tests, including the ported policy-advisor ones. The Branch E2E
E2E Suites job now runs the features family only, so conformance does not
run twice. Point the integration runner defaults and the docs at what
remains.

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
The tmachine conformance playbook saved a bounded set of k3s diagnostics when
a k3s lane failed: the k3s service state and journal, routing rules, version,
API readiness, nodes, the Agent Sandbox controller's deployment, Pods, leases,
events and logs, Sandbox reconciliation status, the gateway's Pods, Services,
EndpointSlices, events and current and previous logs, the test client's
gateway registrations and status, and memory and disk use. The runner only
saved the systemd gateway journal, which is empty on k3s, so a failed k3s or
HA k3s row lost that evidence.

After a failed run, when the guest has /usr/local/bin/k3s, run the old script
(collect-k3s.sh, carried over with only its output handling changed: it prints
to stdout and the runner writes diagnostics/k3s.txt). The commands, timeouts,
size caps and redaction are unchanged. deb and rpm guests keep the gateway
journal only. A failure to collect is reported and never changes the test
result.

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
…boots

The k3s installers check that the Agent Sandbox controller reconciles a gated
probe Sandbox, but the runner then boots a fresh VM from the installed disk,
which restarts k3s and the controller. The runner only waited for the gateway,
so the first sandbox create on the k3s and k3s-ha rows could race the
controller's leader election again. The old conformance playbook ran the
probe after boot, before the tests.

After the gateway is ready on a guest with /usr/local/bin/k3s, run the same
probe (wait-k3s-controller.sh): create a scheduling-gated Sandbox, wait for the
controller-owned gated Pod, and delete it. A failure is an environment error,
not a test failure.

Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
@matthewgrossman
matthewgrossman force-pushed the test/3954-migrate-suites-to-testkit/matthewgrossman branch from 363f081 to 6726561 Compare November 2, 2026 04:19
@matthewgrossman

Copy link
Copy Markdown
Member Author

/ok to test 6726561

@elezar elezar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking this over @matthewgrossman. LGTM.

@elezar
elezar added this pull request to the merge queue Nov 2, 2026

@elezar elezar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking suggestion for the testkit tracking API.

/// Track a sandbox the test is about to create through the CLI, so cleanup
/// deletes it even if the test fails after the gateway accepted the create.
/// Call this before the CLI command; use [`Context::adopt`] afterwards.
pub fn track(&self, name: &str) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could track return a tracked handle, with adopt(self) on that handle, rather than requiring callers to repeat the name across two independent context methods?

let pending = cx.track(&name);
cx.cli(["sandbox", "create", "--name", &name, "--detach"])
    .await?
    .success()?;
let sandbox = pending.adopt().await?;

track would still register cleanup immediately, before the CLI can partially succeed. The handle would carry the name and context needed for adoption, and adopt(self) would consume it to return the Sandbox. Cleanup would remain owned by Context, so a CLI failure, failed adoption, or an unused handle would still leave the sandbox registered for cleanup; no async Drop is needed. This makes the sequencing explicit and prevents tracking one name and accidentally adopting another. Non-blocking API suggestion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test:e2e Requires end-to-end coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants