Skip to content

Commit 4ef312a

Browse files
committed
test(smoke/ros2): decode the traffic light topics with the real ros-carla-msgs package
Add test_ros2_traffic_light_decode_with_carla_msgs: subscribe to /carla/traffic_lights/info and /carla/traffic_lights/status with the canonical carla_msgs definitions, decode one sample of each and cross-check the published ids against the client-visible traffic light actors. This catches wire-format drift that a type hash comparison alone cannot. The test skips when rclpy or carla_msgs is not importable, so plain smoke runs are unaffected.
1 parent 5102ace commit 4ef312a

1 file changed

Lines changed: 74 additions & 3 deletions

File tree

PythonAPI/test/smoke/test_ros2.py

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ class TestROS2(SyncSmokeTest):
1919
does not crash when publishing large-payload sensor data (Image, PointCloud2)
2020
over DDS.
2121
22-
No ROS2 subscriber is needed: the tests exercise the full server-side
23-
publish path (PublisherImpl -> FastDDSPublisherMiddleware ->
22+
No ROS2 subscriber is needed for most tests: they exercise the full
23+
server-side publish path (PublisherImpl -> FastDDSPublisherMiddleware ->
2424
GenericCdrPubSubType::serialize()) without verifying that data arrives at
25-
an external ROS2 node.
25+
an external ROS2 node. The exception is
26+
test_ros2_traffic_light_decode_with_carla_msgs, which subscribes with the
27+
real ros-carla-msgs package when rclpy is importable and skips otherwise.
2628
"""
2729

2830
def test_ros2_api(self):
@@ -295,6 +297,75 @@ def test_ros2_traffic_lights_lifecycle(self):
295297
for _ in range(5):
296298
self.world.tick()
297299

300+
def test_ros2_traffic_light_decode_with_carla_msgs(self):
301+
"""Traffic light topics decode with the real ros-carla-msgs package.
302+
303+
The type-hash unit tests pin the REP-2011 hashes, but only a real
304+
subscriber proves the CDR payload decodes with the canonical
305+
carla_msgs definitions, catching wire-format drift a hash test alone
306+
cannot. Subscribes to both latched traffic light topics, decodes one
307+
sample of each, and cross-checks the published ids against the
308+
client-visible traffic light actors. Skips when rclpy or carla_msgs
309+
is not importable (both come from sourcing a ROS2 environment with
310+
ros-carla-msgs built), so plain smoke runs are unaffected.
311+
"""
312+
try:
313+
import rclpy
314+
from rclpy.qos import (DurabilityPolicy, HistoryPolicy,
315+
QoSProfile, ReliabilityPolicy)
316+
from carla_msgs.msg import (CarlaTrafficLightInfoList,
317+
CarlaTrafficLightStatus,
318+
CarlaTrafficLightStatusList)
319+
except ImportError:
320+
self.skipTest('rclpy and ros-carla-msgs are required '
321+
'for the decode test')
322+
323+
lights = self.world.get_actors().filter('traffic.traffic_light')
324+
self.assertTrue(len(lights) > 0,
325+
'expected traffic lights in the default map')
326+
expected_ids = {light.id for light in lights}
327+
328+
rclpy.init()
329+
node = rclpy.create_node('carla_smoke_traffic_light_decode')
330+
latched = QoSProfile(
331+
depth=1,
332+
history=HistoryPolicy.KEEP_LAST,
333+
reliability=ReliabilityPolicy.RELIABLE,
334+
durability=DurabilityPolicy.TRANSIENT_LOCAL)
335+
received = {}
336+
node.create_subscription(
337+
CarlaTrafficLightInfoList, '/carla/traffic_lights/info',
338+
lambda msg: received.__setitem__('info', msg), latched)
339+
node.create_subscription(
340+
CarlaTrafficLightStatusList, '/carla/traffic_lights/status',
341+
lambda msg: received.__setitem__('status', msg), latched)
342+
try:
343+
deadline = time.time() + 30.0
344+
while time.time() < deadline and len(received) < 2:
345+
self.world.tick()
346+
rclpy.spin_once(node, timeout_sec=0.1)
347+
348+
self.assertIn('info', received,
349+
'no decodable CarlaTrafficLightInfoList arrived '
350+
'on /carla/traffic_lights/info')
351+
self.assertIn('status', received,
352+
'no decodable CarlaTrafficLightStatusList arrived '
353+
'on /carla/traffic_lights/status')
354+
355+
info = received['info'].traffic_lights
356+
status = received['status'].traffic_lights
357+
self.assertEqual({entry.id for entry in info}, expected_ids,
358+
'info ids should match the traffic light actors')
359+
self.assertEqual({entry.id for entry in status}, expected_ids,
360+
'status ids should match the traffic light actors')
361+
for entry in status:
362+
self.assertLessEqual(entry.state, CarlaTrafficLightStatus.UNKNOWN)
363+
for entry in info:
364+
self.assertGreater(entry.trigger_volume.size.x, 0.0)
365+
finally:
366+
node.destroy_node()
367+
rclpy.shutdown()
368+
298369
def test_ros2_multi_sensor_publish(self):
299370
"""4 sensors + hero vehicle: 100-tick stress run then sequential teardown.
300371

0 commit comments

Comments
 (0)