Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1d54751
Document asset test redesign
AntoineRichard Aug 21, 2026
735be0f
Plan asset test redesign
AntoineRichard Aug 21, 2026
ff6308b
Allow OV CPU GPU reuse
AntoineRichard Aug 21, 2026
7b9a867
Refactor shared asset contract tests
AntoineRichard Aug 21, 2026
86a91f4
Fix shared asset contract coverage
AntoineRichard Aug 21, 2026
0fe0965
Fix write contract capability selectors
AntoineRichard Aug 21, 2026
30dcb80
Focus wrench composer tests
AntoineRichard Aug 21, 2026
3e6c1e3
Strengthen wrench composer coverage
AntoineRichard Aug 21, 2026
6089a7e
Cover inactive wrench merge guard
AntoineRichard Aug 21, 2026
a73f00c
Focus Newton rigid asset tests
AntoineRichard Aug 21, 2026
27dc5c2
Strengthen Newton rigid test seams
AntoineRichard Aug 21, 2026
1d3f10d
Cover runtime AppLauncher guard
AntoineRichard Aug 21, 2026
0f5c90e
Focus Newton articulation asset tests
AntoineRichard Aug 21, 2026
2867052
Restore Newton controller bridge coverage
AntoineRichard Aug 21, 2026
ca61466
Classify Newton controller tests as integration
AntoineRichard Aug 21, 2026
ce495a2
Focus PhysX asset tests
AntoineRichard Aug 21, 2026
724fc3f
Close PhysX asset test coverage gaps
AntoineRichard Aug 21, 2026
92c2f30
Harden PhysX test import isolation
AntoineRichard Aug 21, 2026
188b6e6
Split OVPhysX asset tests by scope
AntoineRichard Aug 21, 2026
86a8cba
Cover OVPhysX integration boundaries
AntoineRichard Aug 21, 2026
d1794ae
Publish asset test redesign results
AntoineRichard Aug 21, 2026
8327f7c
Remove internal asset test plans
AntoineRichard Aug 21, 2026
56dc2d1
Strengthen asset test contracts
AntoineRichard Aug 21, 2026
a4de71e
Consolidate articulation integration scenes
AntoineRichard Aug 24, 2026
a3d7711
Preserve focused rigid state assertions
AntoineRichard Aug 24, 2026
e828d86
Test articulation backends with two envs
AntoineRichard Aug 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Empty file.
146 changes: 146 additions & 0 deletions source/isaaclab/test/actuators/test_physx_actuator_runtime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

"""Focused unit tests for the shared host-side PhysX actuator runtime."""

from types import SimpleNamespace
from unittest.mock import Mock, call

import pytest
import warp as wp

from isaaclab.actuators.newton.physx_runtime import PhysxActuatorRuntime


def _runtime() -> PhysxActuatorRuntime:
return PhysxActuatorRuntime(SimpleNamespace(device="cuda:0"), logger=Mock())


def test_graph_capture_builds_two_graphs_and_restores_adapter_state(monkeypatch: pytest.MonkeyPatch) -> None:
"""Capture both alternating state graphs without leaking the capture-time state swap."""
graphs = [object(), object()]

class _Capture:
def __init__(self, *args, **kwargs):
self.graph = graphs.pop(0)

def __enter__(self):
return self

def __exit__(self, exc_type, exc_value, traceback):
return False

state_a, state_b = object(), object()
runtime = _runtime()
runtime.adapter = SimpleNamespace(_states_a=state_a, _states_b=state_b)
monkeypatch.setattr(wp, "ScopedCapture", _Capture)
monkeypatch.setattr(runtime, "_run_native_actuator_kernels", Mock())

runtime._capture_native_actuator_graphs(SimpleNamespace(), 0.01)

assert len(runtime.native_actuator_graphs) == 2
assert runtime.adapter._states_a is state_a
assert runtime.adapter._states_b is state_b
assert runtime._native_actuator_graph_index == 0


def test_graph_capture_failure_falls_back_to_eager(monkeypatch: pytest.MonkeyPatch) -> None:
"""A partial capture failure must restore adapter state before eager execution."""

class _FailingCapture:
capture_count = 0

def __init__(self, *args, **kwargs):
self.capture_index = self.capture_count
type(self).capture_count += 1
self.graph = object()

def __enter__(self):
if self.capture_index == 1:
raise RuntimeError("second capture unavailable")
return self

def __exit__(self, exc_type, exc_value, traceback):
return False

state_a, state_b = object(), object()
runtime = _runtime()
runtime.adapter = SimpleNamespace(_states_a=state_a, _states_b=state_b)

def _swap_adapter_state(*args, **kwargs) -> None:
runtime.adapter._states_a, runtime.adapter._states_b = runtime.adapter._states_b, runtime.adapter._states_a

monkeypatch.setattr(wp, "ScopedCapture", _FailingCapture)
monkeypatch.setattr(runtime, "_run_native_actuator_kernels", _swap_adapter_state)

runtime._capture_native_actuator_graphs(SimpleNamespace(), 0.01)

assert runtime.native_actuator_graphs == ()
assert runtime.adapter._states_a is state_a
assert runtime.adapter._states_b is state_b
runtime._logger.warning.assert_called_once()


def test_compute_falls_back_to_eager_after_graph_capture_failure(monkeypatch: pytest.MonkeyPatch) -> None:
"""A failed host capture during compute must execute the current command eagerly."""

class _FailingCapture:
def __init__(self, *args, **kwargs):
pass

def __enter__(self):
raise RuntimeError("capture unavailable")

def __exit__(self, exc_type, exc_value, traceback):
return False

runtime = _runtime()
runtime.adapter = SimpleNamespace(
is_stateful=False,
is_all_graphable=True,
_states_a=object(),
_states_b=object(),
)
eager_compute = Mock()
monkeypatch.setattr(wp, "get_device", lambda device: SimpleNamespace(is_cuda=True, is_capturing=False))
monkeypatch.setattr(wp, "ScopedCapture", _FailingCapture)
monkeypatch.setattr(runtime, "_run_native_actuator_kernels", eager_compute)
collection = SimpleNamespace()

runtime.compute(collection, 0.01)

eager_compute.assert_called_once_with(collection, 0.01)


def test_compute_launches_alternating_graphs_and_swaps_state(monkeypatch: pytest.MonkeyPatch) -> None:
"""Successive graphable computes must ping-pong graphs and adapter state exactly once."""
graph_a, graph_b = object(), object()
swap_state = Mock()
runtime = _runtime()
runtime.adapter = SimpleNamespace(is_stateful=True, is_all_graphable=True, _swap_state_buffers=swap_state)
runtime.native_actuator_graphs = (graph_a, graph_b)
eager_compute = Mock()
launch_graph = Mock()
monkeypatch.setattr(wp, "get_device", lambda device: SimpleNamespace(is_cuda=True, is_capturing=False))
monkeypatch.setattr(wp, "capture_launch", launch_graph)
monkeypatch.setattr(runtime, "_run_native_actuator_kernels", eager_compute)

runtime.compute(SimpleNamespace(), 0.01)
runtime.compute(SimpleNamespace(), 0.01)

assert launch_graph.call_args_list == [call(graph_a), call(graph_b)]
assert swap_state.call_count == 2
assert runtime._native_actuator_graph_index == 0
eager_compute.assert_not_called()


def test_stateful_actuator_rejects_outer_cuda_capture(monkeypatch: pytest.MonkeyPatch) -> None:
"""Stateful adapters cannot safely mutate their buffers inside an outer CUDA capture."""
runtime = _runtime()
runtime.adapter = SimpleNamespace(is_stateful=True)
monkeypatch.setattr(wp, "get_device", lambda device: SimpleNamespace(is_cuda=True, is_capturing=True))

with pytest.raises(RuntimeError, match="stateful Newton actuators cannot run inside an outer CUDA graph capture"):
runtime.compute(SimpleNamespace(), 0.01)
31 changes: 0 additions & 31 deletions source/isaaclab/test/assets/_iface_test_boot.py

This file was deleted.

6 changes: 6 additions & 0 deletions source/isaaclab/test/assets/contract/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md).
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

"""Shared asset contract test infrastructure."""
Loading
Loading