Files
wehub-resource-sync db1d565b64
Integration Tests / melodic (push) Has been cancelled
Integration Tests / noetic (push) Has been cancelled
Integration Tests / humble (push) Has been cancelled
Integration Tests / jazzy (push) Has been cancelled
Ruff Lint & Format / ruff (push) Has been cancelled
Sync main to develop / Check if sync is needed (push) Has been cancelled
Sync main to develop / Sync main to develop (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:36:23 +08:00

98 lines
4.1 KiB
Python

"""Integration tests for node tools (step 2).
These tests call the actual MCP tool functions (get_nodes, get_node_details)
against a live rosbridge container.
Note: calling get_node_details for nonexistent nodes crashes rosapi_node
on ROS 2 (#273). Tests only query nodes confirmed to exist.
"""
import pytest
pytestmark = [pytest.mark.integration]
class TestGetNodes:
"""Verify get_nodes MCP tool returns the running node list."""
def test_returns_nodes(self, tools):
"""get_nodes should return nodes and node_count."""
result = tools["get_nodes"]()
assert "nodes" in result
assert "node_count" in result
assert result["node_count"] > 0
assert result["node_count"] == len(result["nodes"])
def test_includes_turtlesim(self, tools):
"""turtlesim node should be present (launched by Docker container)."""
result = tools["get_nodes"]()
nodes = result["nodes"]
assert any("/turtlesim" in n for n in nodes), f"turtlesim not in {nodes}"
def test_includes_rosbridge(self, tools):
"""rosbridge node should be present."""
result = tools["get_nodes"]()
nodes = result["nodes"]
assert any("rosbridge" in n for n in nodes), f"rosbridge not in {nodes}"
def test_node_count_at_least_three(self, tools):
"""Should have at least 3 nodes: turtlesim, rosbridge, rosapi."""
result = tools["get_nodes"]()
assert result["node_count"] >= 3, (
f"Expected >= 3, got {result['node_count']}: {result['nodes']}"
)
def test_all_nodes_are_ros_names(self, tools):
"""Every node name should be a string starting with /."""
result = tools["get_nodes"]()
for node in result["nodes"]:
assert isinstance(node, str), f"Expected string, got {type(node)}: {node}"
assert node.startswith("/"), f"Node name should start with /: {node}"
class TestGetNodeDetails:
"""Verify get_node_details MCP tool returns publishers/subscribers/services.
Only queries nodes confirmed to exist — calling get_node_details for
nonexistent nodes crashes rosapi_node on ROS 2 (#273).
"""
def test_turtlesim_details(self, tools):
"""get_node_details for /turtlesim should return publishers and subscribers."""
result = tools["get_node_details"](node="/turtlesim")
assert result["node"] == "/turtlesim"
assert result["publisher_count"] > 0, "turtlesim should have publishers"
assert result["subscriber_count"] > 0, "turtlesim should have subscribers"
assert any("pose" in p for p in result["publishers"]), f"No pose in {result['publishers']}"
assert any("cmd_vel" in s for s in result["subscribers"]), (
f"No cmd_vel in {result['subscribers']}"
)
def test_rosbridge_has_services(self, tools):
"""get_node_details for rosbridge should return services."""
# Find rosbridge node name dynamically (varies by distro)
nodes_result = tools["get_nodes"]()
rosbridge = next((n for n in nodes_result["nodes"] if "rosbridge" in n), None)
assert rosbridge is not None
result = tools["get_node_details"](node=rosbridge)
assert result["node"] == rosbridge
assert result["service_count"] > 0, "rosbridge should have services"
def test_detail_counts_match_lists(self, tools):
"""publisher_count/subscriber_count/service_count should match list lengths."""
result = tools["get_node_details"](node="/turtlesim")
assert result["publisher_count"] == len(result["publishers"])
assert result["subscriber_count"] == len(result["subscribers"])
assert result["service_count"] == len(result["services"])
def test_empty_node_name_returns_error(self, tools):
"""get_node_details with empty string should return error dict."""
result = tools["get_node_details"](node="")
assert "error" in result
def test_whitespace_node_name_returns_error(self, tools):
"""get_node_details with whitespace should return error dict."""
result = tools["get_node_details"](node=" ")
assert "error" in result