Testing Conventions
SkillDev toolsUse before running or interpreting NPA tests, lint checks, or validation reports.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Testing Conventions skill
What this skill tells your AI
The instructions your AI receives, as published by nebius/nebius-physical-ai in skills/atomic/testing-conventions/SKILL.md and read by ahel’s review.
Use the repository virtualenv. Never use bare python; use npa/.venv/bin/python.
Correct command from repo root:
npa/.venv/bin/python -m pytest npa/tests/ --ignore=npa/tests/e2e --timeout=120 -q
Correct command from inside npa/:
cd npa
.venv/bin/python -m pytest tests/ --ignore=tests/e2e --timeout=120 -q
Run it in parallel. The suite is xdist-safe (pytest-xdist is in the dev
extra); -n auto takes ~6 min down to ~2 min on 8 cores with an identical pass
count, which is the difference between running the whole suite each iteration and
only running a slice:
.venv/bin/python -m pytest tests/ -q -n auto
Use the serial form when a failure needs a readable, ordered traceback. CI still runs serially with coverage, so treat a parallel pass as the fast signal, not as a replacement for the gate.
Docs drift is a required gate and is slow to re-run blind. scripts/build_docs.sh
memoizes and prefetches its npa --help walk (~1 min, was ~5), but it still costs a
minute — so change CLI options first, then regenerate once, rather than checking
after each edit. Per-subcommand options do not change the generated pages; a new
top-level command adds docs/cli/<name>.md plus a README index line.
ruff is available in the venv:
npa/.venv/bin/python -m ruff check <files>
Existing Failures And Gates
- Known pre-existing failure:
tests/smoke/test_cosmos_serverless_smoke.pyhas 5 tests gated byNPA_COSMOS_SERVERLESS_SMOKE=1; they fail withUnable to list Nebius VPC networks for project project-smoke: unsupported. - E2E tests are gated by
NPA_INTEGRATION_E2E=1and excluded from standard runs with--ignore=npa/tests/e2e. - Pipeline E2E tests use the
e2e_pipelinepytest marker. - Live Nebius Token Factory tests use the
token_factory_e2emarker (innpa/tests/e2e/test_token_factory_e2e.py). They self-skip without a realNEBIUS_TOKEN_FACTORY_KEY; the marker is in conftest_LIVE_MARKERSso the key is not scrubbed. Run withNEBIUS_TOKEN_FACTORY_KEY=... pytest npa/tests/e2e/test_token_factory_e2e.py.
The gate for make test is 0 failures. Most recent measurement:
10836 passed, 37 skipped, 12 deselected, 1 xpassed, ~14 min serial (2026-08-18 at
1b89b3ba).
Treat that pass count as a floor, never as an equality. It is stale by
construction — it rises whenever tests land, and it was previously recorded as a
closed total that went wrong at the next merge. A higher number is normal; only a
count that has fallen indicates tests stopped being collected, and the reliable
comparison is against your own merge base. Two things move it legitimately: a few
tests self-skip without node, tmux, or docker, and make test deselects the
live/GPU markers so it collects a different tree from test.yml.
The suite is hermetic: it needs no kubectl, no cluster, and no venv at a
particular path. A failure that names a missing binary or ModuleNotFoundError: No module named 'npa' is a bug in the test or the script it drives, not a
missing prerequisite — three of those were fixed in 516396ec.
A hermeticity fix needs a test that fails without it in any environment. CI
pip-installs the package, so a fix that only matters when the npa console script
is absent from PATH cannot regress-fail there: prune PATH inside the test, or
assert on the helper directly, rather than relying on the ambient environment.
Failures that appear only on an operator/dev VM are usually an ambient env var
the conftest does not scrub, not a real regression. tests/conftest.py scrubs
credential and infra-targeting variables for every non-live test precisely
because CI runs with them unset and a working machine does not. When a test
asserts on argv or rendered output, check that every env var the product reads to
build it is in that scrub list: NPA_NEBIUS_PROFILE / NEBIUS_PROFILE were
missing, and because product code prepends --profile <name> whenever either is
set, ten mk8s argv assertions failed on any machine where an operator had
selected a profile. Add the variable to the conftest tuple rather than working
around it in the test; the tests that exercise the variable's own behavior set it
with monkeypatch.setenv after the scrub runs.
Use evidence-based convergence: report numeric pass counts and exact failure messages, not subjective assessment.
Unit Test Rules
Tests must not hit real infrastructure. Mock SSH, S3, Nebius APIs, GPUs, and network calls at the call site. CLI tests use typer.testing.CliRunner against npa.cli.main:app.
When testing a later runtime failure, isolate successful prerequisite setup and assert that execution reached the intended failing boundary. For example, a Cosmos inference-denial test must mock the separately tested guardrail tokenizer preparation before its mocked inference subprocess. Otherwise a missing optional dependency or empty host cache masks the denial and privacy assertions. Preserve those assertions; never prime a real cache or download vendor data to make a hermetic test pass.
Live-Infra Testing Is A Priority (not optional)
Smoke + mocked-unit tests are necessary but not sufficient. Any change to an
npa.workflow spec, a workbench tool / toolRef, or the agent/deploy
(Terraform / provisioner) path MUST also land committed live-infra coverage
— do not stop at smoke. Definition of done: the change is wired into a live path
and you report numeric results from running it.
- New/changed npa.workflow spec: register it in
SUBMIT_LIVE_MATRIX(npa/src/npa/orchestration/npa_workflow/submit_matrix.py) with the right tier (cpu|gpu|multi). If it has a dynamic gate/loop, also add it toDYNAMIC_SPECSinnpa/tests/e2e/npa_workflow_live_helpers.pyso the runner supplies--assume-decision; if it actually executes (non-plan-only), seed inputs inseed_live_workflow_inputs. Useplan_only=Trueonly when stages are stubs or a real run would burn a GPU on a stub (the repo convention: "do not burn GPUs on stubs"). Keeptest_submit_live_matrix.pygreen. Run it:NPA_E2E_NPA_WORKFLOW_SUBMIT_TIERS=<cpu|gpu|multi> \ NPA_E2E_NPA_WORKFLOW_SUBMIT_SPECS=<spec>.yaml \ ./scripts/npa-workflow-submit-live-e2e.sh # plan-only preflight (no job launch): NPA_E2E_NPA_WORKFLOW_SUBMIT_PLAN_ONLY=1 ./scripts/npa-workflow-submit-live-e2e.sh - Live workflow render/infra:
NPA_INTEGRATION_E2E=1 npa/.venv/bin/python -m pytest \ npa/tests/e2e/test_npa_workflow_live_e2e.py \ npa/tests/e2e/test_npa_workflow_live_infra.py -q - Token Factory-backed stages: the
token_factory_e2elive tests must pass with a realNEBIUS_TOKEN_FACTORY_KEY. - Agent/deploy changes: validate a real
npa agent destroy+deploy(and, for credential-path changes, that it is reproducible). Known trap: a stale ambientNEBIUS_IAM_TOKENshadows the freshvar.iam_tokenin the Nebius Terraform provider (PermissionDenied/Unauthenticatedeven though the CLI works);provisioner._runscrubs it, but when reproducing by handunset NEBIUS_IAM_TOKEN NPA_NEBIUS_IAM_TOKENfirst. - If a full live run is genuinely infeasible in the environment, say so
explicitly and still commit the
plan_onlylive-matrix entry — never silently ship smoke-only.
Signals
- GitHub stars
- 28
- Forks
- 15
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
testing-conventions-nebius- Source
- github.com/nebius/nebius-physical-ai