Skip to content

Commit a4dfc40

Browse files
committed
refactor: refactor tests to reduce duplication
1 parent 3700be2 commit a4dfc40

7 files changed

Lines changed: 154 additions & 537 deletions

test/conftest.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
"""Utility functions to transition the Manager to a specific state for testing."""
2+
3+
import pytest
4+
from manager.manager.manager import Manager
5+
6+
7+
class DummyConsumer:
8+
"""A dummy consumer to capture messages sent by the Manager."""
9+
10+
def __init__(self):
11+
"""
12+
Initialize the DummyConsumer with empty message storage.
13+
14+
This constructor sets up the messages list and last_message attribute.
15+
"""
16+
self.messages = []
17+
self.last_message = None
18+
19+
def send_message(self, *args, **kwargs):
20+
"""
21+
Capture and store a message sent by the Manager.
22+
23+
Stores the message arguments and updates the last_message attribute.
24+
"""
25+
self.messages.append((args, kwargs))
26+
self.last_message = (args, kwargs)
27+
28+
29+
@pytest.fixture
30+
def manager(monkeypatch):
31+
"""Fixture to provide a Manager instance with patched dependencies for testing."""
32+
33+
# Patch subprocess.check_output for ROS_DISTRO and IMAGE_TAG
34+
def fake_check_output(cmd, *a, **k):
35+
if "ROS_DISTRO" in cmd[-1]:
36+
return b"humble"
37+
if "IMAGE_TAG" in cmd[-1]:
38+
return b"test_image_tag"
39+
return b""
40+
41+
monkeypatch.setattr("subprocess.check_output", fake_check_output)
42+
43+
# Patch check_gpu_acceleration where it is used
44+
monkeypatch.setattr(
45+
"manager.manager.manager.check_gpu_acceleration", lambda x=None: "OFF"
46+
)
47+
48+
# Patch os.makedirs and os.path.isdir to avoid real FS operations
49+
monkeypatch.setattr("os.makedirs", lambda path, exist_ok=False: None)
50+
monkeypatch.setattr("os.path.isdir", lambda path: True)
51+
52+
# Patch LauncherWorld to avoid launching real processes
53+
class DummyLauncherWorld:
54+
def __init__(self, *a, **k):
55+
self.launched = False
56+
57+
def launch(self):
58+
self.launched = True
59+
60+
def run(self):
61+
self.launched = True
62+
# Simulate running the world
63+
return
64+
65+
def terminate(self):
66+
pass
67+
68+
monkeypatch.setattr("manager.manager.manager.LauncherWorld", DummyLauncherWorld)
69+
70+
# Patch Server and FileWatchdog to avoid starting real servers
71+
class DummyServer:
72+
def __init__(self, port, update_callback):
73+
self.port = port
74+
self.update_callback = update_callback
75+
self.started = False
76+
77+
def start(self):
78+
self.started = True
79+
80+
def stop(self):
81+
self.started = False
82+
83+
class DummyFileWatchdog:
84+
def __init__(self, path, update_callback):
85+
self.path = path
86+
self.update_callback = update_callback
87+
self.started = False
88+
89+
def start(self):
90+
self.started = True
91+
92+
def stop(self):
93+
self.started = False
94+
95+
class DummyVisualizationLauncher:
96+
def __init__(self, *args, **kwargs):
97+
self.launchers = []
98+
99+
def run(self):
100+
# Simulate running the visualization launcher
101+
return
102+
103+
def terminate(self):
104+
pass
105+
106+
monkeypatch.setattr(
107+
"manager.manager.manager.LauncherVisualization", DummyVisualizationLauncher
108+
)
109+
monkeypatch.setattr("manager.manager.manager.Server", DummyServer)
110+
monkeypatch.setattr("manager.manager.manager.FileWatchdog", DummyFileWatchdog)
111+
112+
# Setup Manager with dummy consumer
113+
m = Manager(host="localhost", port=12345)
114+
m.consumer = DummyConsumer()
115+
return m

test/test_connected_to_world_ready.py

Lines changed: 11 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,13 @@
11
"""Tests for transitioning Manager from 'connected' to 'world_ready' state."""
22

33
import pytest
4+
from test_utils import setup_manager_to_connected
45

5-
from manager.manager.manager import Manager
66

7-
8-
class DummyConsumer:
9-
"""A dummy consumer to capture messages sent by the Manager."""
10-
11-
def __init__(self):
12-
"""
13-
Initialize the DummyConsumer with empty message storage.
14-
15-
This constructor sets up the messages list and last_message attribute.
16-
"""
17-
self.messages = []
18-
self.last_message = None
19-
20-
def send_message(self, *args, **kwargs):
21-
"""
22-
Capture and store a message sent by the Manager.
23-
24-
Stores the message arguments and updates the last_message attribute.
25-
"""
26-
self.messages.append((args, kwargs))
27-
self.last_message = (args, kwargs)
28-
29-
30-
@pytest.fixture
31-
def manager(monkeypatch):
32-
"""Fixture to provide a Manager instance with patched dependencies for testing."""
33-
34-
# Patch subprocess.check_output for ROS_DISTRO and IMAGE_TAG
35-
def fake_check_output(cmd, *a, **k):
36-
if "ROS_DISTRO" in cmd[-1]:
37-
return b"humble"
38-
if "IMAGE_TAG" in cmd[-1]:
39-
return b"test_image_tag"
40-
return b""
41-
42-
monkeypatch.setattr("subprocess.check_output", fake_check_output)
43-
44-
# Patch check_gpu_acceleration where it is used
45-
monkeypatch.setattr(
46-
"manager.manager.manager.check_gpu_acceleration", lambda x=None: "OFF"
47-
)
48-
49-
# Patch os.makedirs and os.path.isdir to avoid real FS operations
50-
monkeypatch.setattr("os.makedirs", lambda path, exist_ok=False: None)
51-
monkeypatch.setattr("os.path.isdir", lambda path: True)
52-
53-
# Patch LauncherWorld to avoid launching real processes
54-
class DummyLauncherWorld:
55-
def __init__(self, *a, **k):
56-
self.launched = False
57-
58-
def launch(self):
59-
self.launched = True
60-
61-
def run(self):
62-
self.launched = True
63-
# Simulate running the world
64-
return
65-
66-
def terminate(self):
67-
pass
68-
69-
monkeypatch.setattr("manager.manager.manager.LauncherWorld", DummyLauncherWorld)
70-
71-
# Setup Manager with dummy consumer
72-
m = Manager(host="localhost", port=12345)
73-
m.consumer = DummyConsumer()
74-
# Move to 'connected' state first
75-
m.trigger("connect", event=None)
76-
return m
77-
78-
79-
def test_connected_to_world_ready(manager):
7+
def test_connected_to_world_ready(manager, monkeypatch):
808
"""Test transitioning Manager from 'connected' to 'world_ready' state."""
819
# Initial state should be 'connected'
82-
assert manager.state == "connected"
10+
setup_manager_to_connected(manager, monkeypatch)
8311

8412
# Use ConfigurationModel for valid world config
8513
from manager.libs.launch_world_model import ConfigurationModel
@@ -110,6 +38,8 @@ def test_connected_to_world_ready(manager):
11038

11139
def test_launch_world_with_invalid_world_config(manager, monkeypatch):
11240
"""Test that launching world with invalid world config logs error."""
41+
# Initial state should be 'connected'
42+
setup_manager_to_connected(manager, monkeypatch)
11343

11444
# Patch ConfigurationManager.validate to simulate a failed validation
11545
# but still return a dummy config
@@ -144,6 +74,8 @@ def fake_validate(cfg):
14474

14575
def test_launch_world_with_invalid_robot_config(manager, monkeypatch):
14676
"""Test that launching world with invalid robot config logs error."""
77+
# Initial state should be 'connected'
78+
setup_manager_to_connected(manager, monkeypatch)
14779

14880
# Patch ConfigurationManager.validate to simulate a failed validation
14981
# but still return a dummy config
@@ -184,10 +116,10 @@ def fake_validate(cfg):
184116
)
185117

186118

187-
def test_launch_world_with_no_world_config(manager):
119+
def test_launch_world_with_no_world_config(manager, monkeypatch):
188120
"""Test that launching world with no world config does not raise an error."""
189121
# Initial state should be 'connected'
190-
assert manager.state == "connected"
122+
setup_manager_to_connected(manager, monkeypatch)
191123

192124
# Use ConfigurationModel for valid robot config
193125
from manager.libs.launch_world_model import ConfigurationModel
@@ -211,10 +143,10 @@ def test_launch_world_with_no_world_config(manager):
211143
assert manager.world_launcher is None
212144

213145

214-
def test_launch_world_with_no_robot_config(manager):
146+
def test_launch_world_with_no_robot_config(manager, monkeypatch):
215147
"""Test that launching world with no robot config does not raise an error."""
216148
# Initial state should be 'connected'
217-
assert manager.state == "connected"
149+
setup_manager_to_connected(manager, monkeypatch)
218150

219151
# Use ConfigurationModel for valid world config
220152
from manager.libs.launch_world_model import ConfigurationModel

test/test_idle_to_connected.py

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,6 @@
22

33
import pytest
44

5-
from manager.manager.manager import Manager
6-
7-
8-
class DummyConsumer:
9-
"""A dummy consumer to capture messages sent by the Manager."""
10-
11-
def __init__(self):
12-
"""Initialize the DummyConsumer with empty message storage."""
13-
self.messages = []
14-
self.last_message = None
15-
16-
def send_message(self, *args, **kwargs):
17-
"""Capture the message sent by the Manager."""
18-
self.messages.append((args, kwargs))
19-
# Store the last message for verification
20-
self.last_message = (args, kwargs)
21-
22-
23-
@pytest.fixture
24-
def manager(monkeypatch):
25-
"""Fixture to provide a Manager instance with patched dependencies for testing."""
26-
27-
# Patch subprocess.check_output for ROS_DISTRO and IMAGE_TAG
28-
def fake_check_output(cmd, *a, **k):
29-
if "ROS_DISTRO" in cmd[-1]:
30-
return b"humble"
31-
if "IMAGE_TAG" in cmd[-1]:
32-
return b"test_image_tag"
33-
return b""
34-
35-
monkeypatch.setattr("subprocess.check_output", fake_check_output)
36-
37-
# Patch check_gpu_acceleration where it is used
38-
monkeypatch.setattr(
39-
"manager.manager.manager.check_gpu_acceleration", lambda x=None: "OFF"
40-
)
41-
42-
# Patch os.makedirs and os.path.isdir to avoid real FS operations
43-
monkeypatch.setattr("os.makedirs", lambda path, exist_ok=False: None)
44-
monkeypatch.setattr("os.path.isdir", lambda path: True)
45-
46-
# Setup Manager with dummy consumer
47-
m = Manager(host="localhost", port=12345)
48-
m.consumer = DummyConsumer()
49-
return m
50-
515

526
def test_idle_to_connected(manager):
537
"""Test transitioning Manager from 'idle' to 'connected' state."""

0 commit comments

Comments
 (0)