Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions source/isaaclab/changelog.d/core-test-direct-marl.skip
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Test-only: split Direct MARL Gym-space construction from simulator lifecycle coverage.
Reused the shared config-only environment factory in both test paths.
70 changes: 18 additions & 52 deletions source/isaaclab/test/envs/test_direct_marl_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,62 +20,28 @@
import pytest

import isaaclab.sim as sim_utils
from isaaclab.envs import DirectMARLEnv, DirectMARLEnvCfg
from isaaclab.scene import InteractiveSceneCfg
from isaaclab.utils.configclass import configclass
from isaaclab.envs import DirectMARLEnv
from isaaclab.test.env_cfgs import make_empty_direct_marl_env_cfg

pytestmark = pytest.mark.integration


@configclass
class EmptySceneCfg(InteractiveSceneCfg):
"""Configuration for an empty scene."""

pass


def get_empty_base_env_cfg(device: str = "cuda:0", num_envs: int = 1, env_spacing: float = 1.0):
"""Generate base environment config based on device"""

@configclass
class EmptyEnvCfg(DirectMARLEnvCfg):
"""Configuration for the empty test environment."""

# Scene settings
scene: EmptySceneCfg = EmptySceneCfg(num_envs=num_envs, env_spacing=env_spacing)
# Basic settings
decimation = 1
possible_agents = ["agent_0", "agent_1"]
action_spaces = {"agent_0": 1, "agent_1": 2}
observation_spaces = {"agent_0": 3, "agent_1": 4}
state_space = -1
episode_length_s = 100.0

return EmptyEnvCfg()


@pytest.mark.parametrize("device", ["cuda:0", "cpu"])
def test_initialization(device):
"""Test initialization of DirectMARLEnv."""
# create a new stage
def test_initialization_and_close(device):
"""DirectMARLEnv initializes its spaces and releases its simulation context."""
sim_utils.create_new_stage()
try:
# create environment
env = DirectMARLEnv(cfg=get_empty_base_env_cfg(device=device))
except Exception as e:
if "env" in locals() and hasattr(env, "_is_closed"):
env.close()
else:
if hasattr(e, "obj") and hasattr(e.obj, "_is_closed"):
e.obj.close()
pytest.fail(f"Failed to set-up the DirectMARLEnv environment. Error: {e}")
env = DirectMARLEnv(cfg=make_empty_direct_marl_env_cfg(device=device))

# check multi-agent config
assert env.num_agents == 2
assert env.max_num_agents == 2
# check spaces
assert env.state_space.shape == (7,)
assert len(env.observation_spaces) == 2
assert len(env.action_spaces) == 2
# close the environment
env.close()
try:
assert not env._is_closed
assert sim_utils.SimulationContext.instance() is env.sim
assert env.num_agents == 2
assert env.max_num_agents == 2
assert len(env.observation_spaces) == 2
assert len(env.action_spaces) == 2
assert env.state_space.shape == (7,)
finally:
env.close()
Comment thread
nvsekkin marked this conversation as resolved.

assert env._is_closed
assert sim_utils.SimulationContext.instance() is None
53 changes: 53 additions & 0 deletions source/isaaclab/test/envs/test_direct_marl_env_unit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# 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

# ignore private usage of variables warning
# pyright: reportPrivateUsage=none

"""Unit tests for direct multi-agent reinforcement-learning environments."""

from __future__ import annotations

from types import SimpleNamespace

import gymnasium as gym
import pytest

from isaaclab.envs import DirectMARLEnv, DirectMARLEnvCfg
from isaaclab.test.env_cfgs import make_empty_direct_marl_env_cfg

pytestmark = pytest.mark.unit


class _StubMARLEnv(DirectMARLEnv):
"""Direct MARL environment stub that skips simulator initialization."""

def __init__(self, cfg: DirectMARLEnvCfg) -> None:
self._is_closed = True
self.cfg = cfg
self.scene = SimpleNamespace(num_envs=cfg.scene.num_envs)
self.sim = SimpleNamespace(device=cfg.sim.device)


def test_agent_and_space_configuration():
"""Agent counts and spaces are configured without initializing the simulator."""
env = _StubMARLEnv(make_empty_direct_marl_env_cfg(device="cpu"))

env._configure_env_spaces()

assert env.agents == ["agent_0", "agent_1"]
assert env.possible_agents == ["agent_0", "agent_1"]
assert env.num_agents == 2
assert env.max_num_agents == 2
assert len(env.observation_spaces) == 2
assert len(env.action_spaces) == 2
assert all(isinstance(space, gym.spaces.Box) for space in env.observation_spaces.values())
assert all(isinstance(space, gym.spaces.Box) for space in env.action_spaces.values())
assert env.observation_spaces["agent_0"].shape == (3,)
assert env.observation_spaces["agent_1"].shape == (4,)
assert env.action_spaces["agent_0"].shape == (1,)
assert env.action_spaces["agent_1"].shape == (2,)
assert isinstance(env.state_space, gym.spaces.Box)
assert env.state_space.shape == (7,)
Loading