Repository navigation
test(testkit): add the testkit library for end-to-end suites - #4724
matthewgrossman wants to merge 18 commits into
Conversation
|
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. |
|
🌿 Preview your docs: https://nvidia-preview-pr-4724.docs.buildwithfern.com/openshell |
f595dd0 to
9c471d2
Compare
Rebuilds the runner on the rebuilt migration, the current #4724 head and the tmachine paths from main. The tree is the rebuilt runner; the extra parent keeps this branch a fast-forward of what was pushed before.
Add tests/testkit as its own Cargo workspace: testkit, testkit-macros, and testkit-spec. testkit reads a target file, connects to the gateway through openshell-sdk, creates and cleans up sandboxes, and runs the installed CLI. #[testkit::test] requires a stable ID and a doc comment and declares capability requirements. testkit-ready waits for a target's gateway and CLI before tests run. Nothing uses testkit yet. The lockfile is seeded from the root lockfile so shared crates resolve to the same versions. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Nothing else builds testkit, so check it in Branch Checks and the matching mise tasks to catch openshell-sdk changes that break it. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Cleanup shared one two-minute budget across all of a test's sandboxes, so a slow delete left the rest with no time and could leak them on a shared gateway. Delete them concurrently, each with the full timeout. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Nothing reads test IDs or capability requirements until a runner, waivers, or result history exist, so remove the id and requires arguments and the target file's capabilities section. Both can return as optional attribute arguments without changing existing tests. With them gone, testkit-spec only checked the function shape and read the doc comment, so fold it into testkit-macros. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Replace the target file (OPENSHELL_TEST_TARGET) with the CLI's own gateway selection: OPENSHELL_GATEWAY_ENDPOINT, then OPENSHELL_GATEWAY, then the active gateway. A registered gateway's endpoint, auth mode, and mTLS material come from its CLI config directory. cx.cli runs OPENSHELL_BIN against the same gateway and workspace as the SDK. Suites now run unchanged under e2e/with-docker-gateway.sh and e2e/with-podman-gateway.sh, and environments need no extra file. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
The policy path creates the sandbox through gRPC and dropped the spec's labels without an error. Pass them in the create request. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
When OPENSHELL_GATEWAY_ENDPOINT is set, the CLI takes credentials from the gateway named by OPENSHELL_GATEWAY, or else the registered gateway with that endpoint. testkit connected without a client certificate instead, so an mTLS endpoint such as the one e2e/rust/e2e-vm.sh exports worked for cx.cli but not for the SDK. Resolve it the way the CLI does, and pass both the name and the endpoint to cx.cli. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
OPENSHELL_GATEWAY_ENDPOINT takes precedence over OPENSHELL_GATEWAY. Also mention OPENSHELL_BIN. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
#[testkit::test] left attributes such as #[ignore] and #[cfg] on the nested body function, where they have no effect on the test. Move them to the generated test, and reject a second test attribute such as Signed-off-by: Matthew Grossman <mgrossman@nvidia.com> #[test] or #[tokio::test].
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
A testkit test panics on any failure, including an unreachable gateway or a failed cleanup, so #[should_panic] would let such a failure pass. Reject it and point to checking the expected failure in the body. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
6c1654e to
c8d4223
Compare
Suites built on testkit exercise gateway resolution, the CLI wrapper, polling, errors, and cleanup against a real gateway. Keep one unit test for the macro's compile errors, which a passing suite never reaches, and drop the test-only seams the other tests needed. Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
…tkit-spec `#[testkit::test]` takes two optional arguments. `id = "t-0123abcd"` gives a test a stable identity that survives renames and moves. `requires = [gpu]` names the capabilities the environment must provide, read from OPENSHELL_TEST_CAPABILITIES. A test with requirements fails instead of passing when the environment lacks them; a test without them never reads the variable. The attribute's parsing moves into a new testkit-spec crate, which the test runner's catalog also uses to list tests without compiling them. `#[should_panic]` stays rejected; the requirement tests call `testkit::run` directly. The testkit lockfile is also realigned with the root lockfile. Co-authored-by: Evan Lezar <elezar@nvidia.com> Signed-off-by: Matthew Grossman <mgrossman@nvidia.com>
|
Reviewed commit
The earlier attribute-forwarding issue is fixed: probes confirmed All 23 existing tests passed locally. No real-gateway E2E run was performed. |
|
Could we add mTLS configuration to the SDK and have testkit use
That would remove the duplicate channel construction and endpoint settings from testkit, keeping TLS behavior, connection timeouts, and keepalive settings consistent across SDK consumers. This seems worth a small prerequisite SDK change, followed by simplifying this PR to use it. The current comment also overstates the limitation: the SDK can use an mTLS channel via |
TL;DR
testkit, a small library for writing end-to-end tests against a running OpenShell gateway through the Rust SDK. A test is a documentedasync fnmarked#[testkit::test]that runs with plaincargo nextest.openshellCLI does, so they run unchanged undere2e/with-docker-gateway.shande2e/with-podman-gateway.shwith no extra config.cx.cli(...)runs the CLI against the same gateway and workspace as the SDK.idandrequires = [...]capabilities, parsed by a smalltestkit-speccrate that tools such as a test runner can reuse to list tests without compiling them.Stack
Part of a stack of three; each PR targets the one below it. The tmachine move (#4726) has merged, so the stack uses its
tests/tmachine/paths.SessionAPI, with a plan running a smoke test on CI.Still to come, on top of #4774: moving the release lanes onto plans and deleting the old suites, once the plan has run the ported suites green.
Summary
Adds
tests/testkit/, a support library for SDK-driven end-to-end suites, as its own Cargo workspace. This is a small first step to get the crate into main and checked in CI. Nothing uses it yet. The existing suites move onto it in one follow-up migration (#4774, stacked on this PR) that also deletes the old suites. Suites added after that arrive one at a time.The code comes from @elezar's draft #4629 (head
673928804). This PR takes the testkit portion, adapted to current main. It keeps #4629's optional test IDs, capability requirements, andtestkit-speccrate, and drops the target file (see "Deferred and follow-ups" below). The test runner in the next PR is their first consumer.Related Issue
Part of #3954
Changes
tests/testkit/: thetestkit,testkit-macros, andtestkit-speccrates, plus thetestkit-readybinary, taken from test(conformance): run conformance suites from test plans in tmachine environments #4629.async fnmarked#[testkit::test]with a required doc comment. Other attributes such as#[ignore]apply to the generated test.#[should_panic]is rejected, because a testkit test panics on any failure.openshellCLI does:OPENSHELL_GATEWAY_ENDPOINT, thenOPENSHELL_GATEWAY, then the active gateway. A registered gateway's endpoint and mTLS material come from its CLI config directory. Like the CLI, an endpoint takes its credentials fromOPENSHELL_GATEWAYor the registered gateway with that endpoint.cx.clirunsOPENSHELL_BINagainst the same gateway and workspace. Each test logs the gateway it used.id = "t-…"andrequires = [...]are optional arguments, so a test without them needs nothing. An ID gives a test an identity that survives renames.requiresnames capabilities (gpu,persistent_workspace,rootless,service_exposure) that the environment lists inOPENSHELL_TEST_CAPABILITIES; a test that requires one fails instead of passing untested when it is missing, and a test withoutrequiresnever reads the variable.testkit-specis the single parser the macro and a runner's catalog share.Cargo.lockis re-seeded from the root lockfile, because main'sopenshell-sdkhas more dependencies than when test(conformance): run conformance suites from test plans in tmachine environments #4629 was cut.rust:lint,rust:format,rust:format:check, andtest:rustmise tasks now run fmt, clippy, and nextest for the testkit workspace. This follows test(conformance): run conformance suites from test plans in tmachine environments #4629'scf72f1108, restricted to testkit.tests/testkit/README.mdcovers writing a test, whatContextprovides, and running against a gateway.TESTING.md,AGENTS.md, andCONTRIBUTING.mdpoint to it.Deferred and follow-ups
Dropped from #4629's testkit
What is left out:
OPENSHELL_TEST_TARGET). It held a copy of the CLI's registered gateway plus capabilities, so testkit now reads the CLI's gateway config directly. As a result, step 3 no longer needs test(conformance): run conformance suites from test plans in tmachine environments #4629'sopenshell_clientrole change or the runner code that writestarget.yaml. The runner only setsOPENSHELL_GATEWAY(orOPENSHELL_GATEWAY_ENDPOINT) andOPENSHELL_BIN.Rest of #4629, for later steps
Sessionlibrary, and the Ansible andconfig.nixchanges.e2e-suites.yml.a37ebe917). It matters once testkit is built into the Nix test archives. Until then,check-cargo-lockfiles.shalready validatestests/testkit/Cargo.lock.Follow-ups found while landing this
gateway.rsrepeats the CLI's lookup: the endpoint-to-registered-gateway match,metadata.jsonauth modes, and themtls/files. It also builds the mTLS channel itself, because the SDK leaves mTLS out. The copies can drift apart. When step 3 lands or tmachine needs the same lookup, move it intoopenshell-bootstrapor an SDK helper so the CLI, testkit, and tmachine share one implementation.mtls/path, as the CLI does. Gateway names with only letters, digits,.,-, and_are unaffected.cx.sandbox(...). Tests must delete anything else they create, such as providers. This is documented in the README. Extend the cleanup registry when suites create other resources often.tests/testkit/targetisn't covered by the Rust cache. This adds roughly 1–2 minutes to each Rust lint and test job. Caching it would add about 2 GB per platform cache. Revisit if suites make the build slower.supervisor_network_mode = "bridge".e2e/with-docker-gateway.shsets neither. Linux CI isn't affected. Consider setting bridge mode in the wrapper on macOS when the first testkit lane lands.Raised in review and left as is
Sandboxhelpers have no caller yet (for exampleconfig,draft_policy, andset_setting). They came from test(conformance): run conformance suites from test plans in tmachine environments #4629 for the suites in the next PR, so removing them now would only mean adding them back.Testing
cargo fmt --manifest-path tests/testkit/Cargo.toml --all -- --checkcargo clippy --locked --manifest-path tests/testkit/Cargo.toml --all-targets -- -D warningscargo nextest run --locked --config-file .config/nextest.toml --manifest-path tests/testkit/Cargo.toml(23 tests: the spec parser, capability parsing and requirement checks, and the macro's misuse checks. Gateway resolution, the CLI wrapper, and cleanup are exercised against a real gateway below and by the suites that adopt testkit.)tasks/scripts/check-cargo-lockfiles.shcoverstests/testkit/Cargo.lockmise run license:checkAgainst a real gateway
To check that testkit works end to end, I built a throwaway suite crate outside the repo. It depends on this branch's testkit and contains the six
sandbox_lifecycletests from #4629, plus a test that creates three sandboxes, checks thatcx.cli(["sandbox", "list"])shows them, and leaves them for cleanup. I ran it unchanged undere2e/with-docker-gateway.shon macOS with Docker Desktop. The wrapper's ownOPENSHELL_GATEWAYandOPENSHELL_BINwere the only configuration:e2e/with-docker-gateway.sh sh -c 'testkit-ready 120 && cargo nextest run --manifest-path <suite>/Cargo.toml --test-threads 1'testkit-readyresolved the wrapper's mTLS gateway, reported it healthy, and confirmed the CLI reaches it. All 7 tests passed in about 15s, andopenshell sandbox listshowed nothing left behind. Two#[ignore]tests, with the attribute above and below#[testkit::test], were skipped. With onlyOPENSHELL_GATEWAY_ENDPOINTset, ase2e/rust/e2e-vm.shdoes, testkit found the registered gateway's mTLS material, andtestkit-readyplus two tests passed.On Docker Desktop, sandboxes need either Docker Desktop's host networking turned on (Settings → Resources → Network) or
supervisor_network_mode = "bridge". Otherwise the supervisor cannot reach a gateway on the Mac's loopback. For this run I set bridge mode with a local, uncommitted change to the wrapper's gateway config.Checklist