Skip to content

Collect co-located unit tests in CI, and correct the unit-test docs - #383

Draft
JohnYanxinLiu wants to merge 5 commits into
developfrom
johnliu/unit-test-docs-cleanup
Draft

Collect co-located unit tests in CI, and correct the unit-test docs#383
JohnYanxinLiu wants to merge 5 commits into
developfrom
johnliu/unit-test-docs-cleanup

Conversation

@JohnYanxinLiu

@JohnYanxinLiu JohnYanxinLiu commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

What features did you add and/or bugs did you address?

  • Which GitHub issue does this address?

None.

  • Additional description if not fully described in the GitHub issue

CI was running zero unit tests, and had been for as long as the co-located layout has
existed.

Unit-test source lives outside tests/ (in <package>/test/, listed in
colcon_unit_test_packages.yaml), so pytest never reaches it by recursion —
conftest.pytest_configure appends those files to the collection args. That injection was
gated on args_source != "ARGS", and pytest sets ARGS for any positional path,
including tests/. The intent was that pytest tests/system/foo.py should not drag in
155 unrelated tests, but the guard could not tell narrowing from naming the whole suite.

system-tests.yml runs pytest tests/. So did nearly every documented command. Result:

$ pytest tests/ -m unit
no tests collected (97 deselected)   # exit 5

The Python unit tests for natnet_ros2, lidar_point_cloud_filter and
optitrack.natnet.emulator ran nowhere in CI. natnet_ros2's 14 are the sharpest case —
its CMakeLists.txt registers ament_add_gtest but no ament_add_pytest_test, so the
root harness was their only possible runner.

This PR fixes the guard, adds contract tests so it cannot regress silently, and corrects
the documentation and agent skills that described the pre-co-location layout.

  • Please add videos and images

Not applicable — test-infrastructure and documentation change.

How did you implement it?

The guard. Decide on the paths rather than on "was a path given". A positional is
broad when it names tests/ itself or an ancestor of it, narrow otherwise
(harness/discovery.py):

def collection_is_broad(args, invocation_dir, tests_root=None) -> bool:
    root = Path(tests_root or TESTS_DIR).resolve()
    invocation_dir = Path(invocation_dir).resolve()
    return any(
        root.is_relative_to(_arg_path(a, invocation_dir))
        for a in args
        if not str(a).startswith("-")
    )

Three details carry the weight, and are the ones worth a reviewer's eye:

  • The direction of is_relative_to. It is root.is_relative_to(arg) — is the tests
    root inside the argument? Inverting it makes pytest tests/system broad and
    pytest tests/ narrow, i.e. the original bug with extra steps.
  • split("::") — positionals may be node ids (test_x.py::TestY::test_z); only the
    part before :: addresses the filesystem.
  • any, not allpytest_configure then appends the co-located files (narrow,
    absolute) to config.args, so all would flip the answer for anything re-deriving it
    after that mutation. The decision is also stashed on config so nothing has to.

Scope of the behaviour change. Only pytest <path-containing-tests/> changes. Bare
pytest from tests/ (what airstack test runs) took the TESTPATHS branch before and
still does.

Documentation. The repo still carried scaffolding from the mirror-directory-and-proxy
scheme that co-location replaced: six per-layer stub READMEs under tests/robot/ telling
authors to add tests where tests no longer live, and tests/sim/motive_emulator/README.md
proposing an emulator that was built at
simulation/isaac-sim/extensions/optitrack.natnet.emulator/ instead. Several files also
pointed at tests/sim/optitrack_natnet_emulator/, a directory that was never committed —
following those instructions collected zero tests. Removed, with the two tree READMEs
rewritten as signposts.

The add-unit-tests and run-system-tests skills — what a future agent reads to work
here — were wrong on four counts, now corrected:

Was Is
The mark "Always decorate with @pytest.mark.unit" pytest_itemcollected applies it by file location; writing it is redundant and warns under colcon test. This instruction is where the redundant declarations came from
pytest_args "-m not linter" [] — forwarded via PYTEST_ADDOPTS, where ament's pytest runner ignores -m, so a marker expression there silently does nothing
colcon coverage "Yes, colcon runs these too" Only what the package registers; depends on build type (below)
Sim tests tests/sim/ simulation/**/<ext>/test/

Why C++ and Python take different runners — documented, since it was previously stated
as a bare fact. A gtest is a binary: it must be compiled against the package's headers and
rclcpp, so it only runs where the ROS toolchain is (colcon test in the robot container,
which CI reaches via build_packages after building with -DBUILD_TESTING=ON). Python
unit tests are deliberately hermetic — they stub ROS at the import boundary and touch no
ROS runtime — so they need neither a build nor a container, which is what keeps the suite
under a second. The invariant that follows is now written down: a Python test needing a
live ROS node belongs in tests/integration/ or tests/system/, not a package test/
dir.

Test Runner In CI via
C++ gtest colcon test in the robot container build_packages mark
Python, ament_python package root harness and colcon test pytest tests/ and build_packages
Python, ament_cmake package root harness only pytest tests/

How do you run and use it?

No runtime behaviour changes. To see the fix:

export AIRSTACK_ROOT=$(pwd)

# The command CI runs. On develop: "no tests collected (97 deselected)", exit 5.
pytest tests/ -m unit -v

# Unchanged by this PR — the path that already worked:
airstack test -m unit -v

# Narrowing must still narrow (no unit tests dragged in):
pytest tests/system/test_liveliness.py --collect-only -q

Testing with PyTest

  • What pytests did you add?

tests/meta/test_collection_contract.py — 15 tests in three groups:

  1. A table over collection_is_broad — seven broad invocations (pytest tests/,
    pytest ., absolute paths, the testpaths form) and six narrow ones (a subdirectory,
    a file, a node id, a co-located file). Pure function, microseconds, no subprocess.
  2. The CI command is broad — reads system-tests.yml, extracts the actual
    pytest <path> positional, and asserts it classifies as broad. This is the test that
    would have caught the original bug
    , and it survives someone "fixing" CI by hand.
  3. The injection produced items — every file unit_test_files() discovered
    contributed at least one collected item. Catches breakage below the guard: YAML
    drift, a glob change, an import error that turns a module into a collection error.
    Skips on a narrowed run, where having none is correct.

These live under tests/ deliberately. Co-located, they would stop being collected at the
same moment they stopped guarding anything; under tests/ plain recursion finds them, so
a broken guard makes them run and fail. They also carry the only hand-written
@pytest.mark.unit in the repo — not being co-located, the path-based marker does not
reach them — commented as the exception.

  • Exact command
airstack test -m unit -v
  • Expected results

170 passed, 97 deselected — 155 co-located unit tests plus the 15 contract tests.
On develop the same command via pytest tests/ -m unit collects nothing and exits 5.

Measured on this branch:

Invocation Before After
pytest tests/ -m unit (CI) 0 collected, exit 5 170 passed
cd tests && pytest -m unit 155 passed 170 passed
pytest tests/system/test_liveliness.py 16 collected 16 collected

Documentation

  • Was mkdocs.yml updated? (y/n)

n — no new pages. Existing pages corrected: unit_testing.md, testing/index.md,
ci_cd.md. None of the deleted READMEs were in nav, so the build is unaffected.

  • Sufficient scope?

Yes. The docs and both agent skills now state which runner each language uses and why,
when each edit takes effect, and the hermetic-Python invariant that keeps the fast path
fast.

  • Sufficient visual media?

Not applicable.

Versioning

  • Version bumped?

Yes0.19.0-alpha.17.


Reviewer notes

155 tests will run on the self-hosted runner for the first time. They pass locally and
every pxr import is importorskip-guarded (usd-core is in tests/requirements.txt),
so there is no collection-error risk. The residual exposure is a handful of emulator tests
that bind ephemeral UDP loopback sockets. Worth one /pytest -m unit on this PR before
merge.

system-tests.yml triggers are unchanged and intentionally so — PR open, /pytest,
workflow_dispatch. Unit tests ride along with that workflow rather than getting a
separate always-on job, because the same run also drives the GPU system tests.

Untracked __pycache__ residue from the deleted proxy modules may still exist locally at
tests/sim/optitrack_natnet_emulator/ and tests/robot/**/<pkg>/. Never tracked; not part
of this diff.

JohnYanxinLiu and others added 4 commits August 17, 2026 16:13
Unit test source moved into <package>/test/ and is collected from
colcon_unit_test_packages.yaml, but the surrounding documentation still described
the mirror-directory-and-proxy scheme that replaced. Six per-layer stubs under
tests/robot/ told authors to add tests in directories tests no longer live in, and
tests/sim/motive_emulator/README.md proposed a NatNet emulator that was built at
simulation/isaac-sim/extensions/optitrack.natnet.emulator/ instead. Remove them and
rewrite the two tree READMEs as signposts.

Correct the add-unit-tests and run-system-tests skills, which future agents read to
work in this area, on four points they had wrong:

- Running them. `pytest tests/` does not collect co-located unit tests — the
  injection in conftest.pytest_configure is skipped whenever a path is given on the
  command line. It reports "no tests collected" and exits 5, which reads as a
  failure but means nothing ran. `airstack test -m unit` and `cd tests && pytest -m
  unit` are the working forms; verified 155 passed vs exit 5.
- CI. No workflow runs unit tests. system-tests.yml invokes `pytest tests/`, and
  fires only on PR-open, /pytest, or workflow_dispatch.
- The mark. pytest_itemcollected applies @pytest.mark.unit by file location, so
  test sources should not declare it. The skill previously said "always decorate",
  which is where the redundant declarations came from.
- colcon. It runs only what a package's CMakeLists registers. natnet_ros2 has
  ament_add_gtest but no ament_add_pytest_test, so its Python tests run only under
  the root harness.

Also fixes a pytest_args example that would silently do nothing (`-m not linter`;
ament's pytest runner ignores -m via PYTEST_ADDOPTS, and the real value is []), and
the same stale layout claim in the testing docs and the emulator README.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
C++ gtests run under colcon test, which CI executes inside the robot container via
the build_packages mark (test_build_packages.py::test_colcon_test_robot). Python unit
tests run under the root harness, which no workflow invokes.

Whether colcon test also picks up a package's Python tests depends on its build type:
lidar_point_cloud_filter is ament_python and exposes them via setup.cfg
(testpaths = test), so they run in both places; natnet_ros2 is ament_cmake and
registers only ament_add_gtest, so its Python tests run nowhere in CI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Unit-test source lives outside tests/, so pytest_configure appends it to the
collection args. That injection was gated on args_source != ARGS, which pytest sets
for any positional path — including `tests/`. The intent was that
`pytest tests/system/foo.py` should not drag in 155 unrelated tests, but the guard
could not tell narrowing from naming the whole suite, so CI's `pytest tests/`
collected 97 of 252 items and the Python unit tests ran nowhere.

Decide on the paths instead: a positional is broad when it names tests/ itself or an
ancestor, narrow otherwise. `pytest tests/` and `pytest .` inject; `pytest tests/system`,
a single file, and a node id do not. Node ids are split on `::` first, since only the
part before it addresses the filesystem.

`any` rather than `all` is deliberate — pytest_configure appends the co-located files
(narrow, absolute) to config.args, so `all` would flip the answer for anything
re-deriving it after that mutation. The decision is also stashed on config for the
contract test to read.

tests/meta/test_collection_contract.py pins the behaviour: a table over broad/narrow
invocations, a check that the command in system-tests.yml is classified broad (the
test that would have caught this), and a check that every discovered file produced
collected items. It lives under tests/ on purpose — co-located, it would stop being
collected at the same moment it stopped guarding anything.

Verified: `pytest tests/ -m unit` 0 -> 170 passed; `cd tests && pytest -m unit`
unchanged at 170; `pytest tests/system/test_liveliness.py` still collects 16.

Unit tests now run with every system-tests.yml invocation. That workflow's triggers
are unchanged and intentional — PR open, /pytest, workflow_dispatch — since the same
run drives the GPU system tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The split was documented as a fact without its reason. A gtest is a binary compiled
against the package's headers and rclcpp, so it can only run where the ROS toolchain
is — colcon test inside the robot container, which build_packages reaches after
building with -DBUILD_TESTING=ON. Python unit tests stub ROS at the import boundary
and touch no ROS runtime, so they need neither a build nor a container, which is what
keeps the suite under a second.

State the invariant that follows: a Python test needing a live ROS node belongs in
tests/integration/ or tests/system/, not in a package test/ dir.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Test Metrics — 22c311ff9bc9a327408683149f5ce483e13b4239

Pass rates

Test Pass Fail Skip Rate
isaac-sim.extensions.PegasusSimulator.extensions.pegasus.simulator.pegasus.simulator.tests.test_hello_world 0 1 0 0%
isaac-sim.standalone_examples.replicator.pose_generation.pose_tests.test_utils 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.benchmark.services.test_no_rendering 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.core.api.test_articulation_determinism 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.core.api.test_articulation_root 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.core.api.test_delete_in_contact 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.core.api.test_rendering 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.core.api.test_save_stage 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.core.api.test_time_stepping 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.cortex.framework.cortex_bringup_test 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.ros1.bridge.test_carter_lidar 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.ros2.bridge.test_carter_camera_multi_robot_nav 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.ros2.bridge.test_people_sim 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.sensors.physics.contact_sensor_test 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.sensors.rtx.rtx_lidar_test 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.sensors.rtx.rtx_radar_test 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_createstage_config 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_extension_count 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_external 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_extra_args 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_fabric_frame_delay 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_fetch_results 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_frame_delay 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_ogn 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_ovd 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_syntheticdata 0 1 0 0%
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_unsaved_on_exit 0 1 0 0%
isaac-sim.standalone_examples.testing.omni.isaac.dynamic_control.test_zero_step 0 1 0 0%
isaac-sim.standalone_examples.testing.omni.replicator.agent.test_scripting 0 1 0 0%
isaac-sim.standalone_examples.testing.omni.syntheticdata.test_basic 0 1 0 0%
ros_packages.gui.rviz.rviz_behavior_tree_panel.scripts.test_behavior_tree_publisher 0 1 0 0%
ros_packages.logging.bag_recorder_pid.test.test_copyright 0 1 0 0%
ros_packages.logging.bag_recorder_pid.test.test_flake8 0 1 0 0%
ros_packages.logging.bag_recorder_pid.test.test_pep257 0 1 0 0%
ros_ws.src.local.planners.takeoff_landing_planner.test.scripts.test_takeoff_landing_planner 0 1 0 0%
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Baseline.DPVO.Pangolin.components.pango_python.pybind11.tests 0 1 0 0%
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_circular_buffer 0 1 0 0%
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_config_loadable 0 1 0 0%
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_config_macvo 0 1 0 0%
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_config_modules 0 1 0 0%
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_config_sequence 0 1 0 0%
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_config_tartanvo 0 1 0 0%
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_frontend 0 1 0 0%
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_matching 0 1 0 0%
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_performance_macvo 0 1 0 0%
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_stereo_depth 0 1 0 0%
ros_ws.src.ros2tak_tools.test.test_copyright 0 1 0 0%
ros_ws.src.ros2tak_tools.test.test_flake8 0 1 0 0%
ros_ws.src.ros2tak_tools.test.test_pep257 0 1 0 0%
ros_ws.src.sensors.camera_param_server.test.test_copyright 0 1 0 0%
ros_ws.src.sensors.camera_param_server.test.test_flake8 0 1 0 0%
ros_ws.src.sensors.camera_param_server.test.test_pep257 0 1 0 0%
ros_ws.src.sensors.gimbal_stabilizer.test.test_copyright 0 1 0 0%
ros_ws.src.sensors.gimbal_stabilizer.test.test_flake8 0 1 0 0%
ros_ws.src.sensors.gimbal_stabilizer.test.test_pep257 0 1 0 0%

Metrics

Test Metric Value
ros_packages.gui.rviz.rviz_behavior_tree_panel.scripts.test_behavior_tree_publisher duration_s 0s
ros_packages.logging.bag_recorder_pid.test.test_copyright duration_s 0s
ros_packages.logging.bag_recorder_pid.test.test_flake8 duration_s 0s
ros_packages.logging.bag_recorder_pid.test.test_pep257 duration_s 0s
ros_ws.src.ros2tak_tools.test.test_copyright duration_s 0s
ros_ws.src.ros2tak_tools.test.test_flake8 duration_s 0s
ros_ws.src.ros2tak_tools.test.test_pep257 duration_s 0s
ros_ws.src.local.planners.takeoff_landing_planner.test.scripts.test_takeoff_landing_planner duration_s 0s
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Baseline.DPVO.Pangolin.components.pango_python.pybind11.tests duration_s 0s
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_circular_buffer duration_s 0s
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_config_loadable duration_s 0s
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_config_macvo duration_s 0s
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_config_modules duration_s 0s
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_config_sequence duration_s 0s
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_config_tartanvo duration_s 0s
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_frontend duration_s 0s
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_matching duration_s 0s
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_performance_macvo duration_s 0s
ros_ws.src.perception.macvo_ros2.macvo_ros2.macvo.Scripts.UnitTest.test_stereo_depth duration_s 0s
ros_ws.src.sensors.camera_param_server.test.test_copyright duration_s 0s
ros_ws.src.sensors.camera_param_server.test.test_flake8 duration_s 0s
ros_ws.src.sensors.camera_param_server.test.test_pep257 duration_s 0s
ros_ws.src.sensors.gimbal_stabilizer.test.test_copyright duration_s 0s
ros_ws.src.sensors.gimbal_stabilizer.test.test_flake8 duration_s 0s
ros_ws.src.sensors.gimbal_stabilizer.test.test_pep257 duration_s 0s
isaac-sim.extensions.PegasusSimulator.extensions.pegasus.simulator.pegasus.simulator.tests.test_hello_world duration_s 0s
isaac-sim.standalone_examples.replicator.pose_generation.pose_tests.test_utils duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.benchmark.services.test_no_rendering duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.core.api.test_articulation_determinism duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.core.api.test_articulation_root duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.core.api.test_delete_in_contact duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.core.api.test_rendering duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.core.api.test_save_stage duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.core.api.test_time_stepping duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.cortex.framework.cortex_bringup_test duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.ros1.bridge.test_carter_lidar duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.ros2.bridge.test_carter_camera_multi_robot_nav duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.ros2.bridge.test_people_sim duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.sensors.physics.contact_sensor_test duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.sensors.rtx.rtx_lidar_test duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.sensors.rtx.rtx_radar_test duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_createstage_config duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_extension_count duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_external duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_extra_args duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_fabric_frame_delay duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_fetch_results duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_frame_delay duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_ogn duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_ovd duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_syntheticdata duration_s 0s
isaac-sim.standalone_examples.testing.isaacsim.simulation_app.test_unsaved_on_exit duration_s 0s
isaac-sim.standalone_examples.testing.omni.isaac.dynamic_control.test_zero_step duration_s 0s
isaac-sim.standalone_examples.testing.omni.replicator.agent.test_scripting duration_s 0s
isaac-sim.standalone_examples.testing.omni.syntheticdata.test_basic duration_s 0s

@JohnYanxinLiu JohnYanxinLiu changed the title docs(tests): align unit-test docs with the co-located layout Collect co-located unit tests in CI, and correct the unit-test docs Aug 18, 2026
They are hermetic and they guard the collection of everything above them, so
running them after the GPU sim suites is backwards — a hung flight test would mean
they never execute. Rank them in _MODULE_ORDER right after the co-located unit
tests, ahead of system.test_build_docker.

Also drop the `from conftest import repo_path` in favour of harness.discovery,
which the module already imports from — one less thing between the test and the
function it needs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant