Skip to content

Commit 4414d5e

Browse files
Add rclrs_test package for unit/integration tests (#239)
This package is meant to test behaviors with dependencies that don't belong in the rclrs crate - namely, msgs
1 parent efb3779 commit 4414d5e

File tree

5 files changed

+279
-1
lines changed

5 files changed

+279
-1
lines changed

.github/workflows/rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ jobs:
9595
- name: Run cargo test on Rust packages
9696
run: |
9797
cd ${{ steps.build.outputs.ros-workspace-directory-name }}
98-
. /opt/ros/${{ matrix.ros_distribution }}/setup.sh
98+
. install/setup.sh
9999
for path in $(colcon list | awk '$3 == "(ament_cargo)" && $1 != "examples_rclrs_minimal_pub_sub" && $1 != "examples_rclrs_minimal_client_service" { print $2 }'); do
100100
cd $path
101101
echo "Running cargo test in $path"

rclrs_tests/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "rclrs_tests"
3+
version = "0.2.0"
4+
authors = ["Chris Reid <christopherjreid@outlook.com>"]
5+
edition = "2021"
6+
7+
[lib]
8+
path = "src/lib.rs"
9+
10+
[dependencies]
11+
anyhow = {version = "1", features = ["backtrace"]}
12+
test_msgs = {version = "*"}
13+
14+
[dependencies.rclrs]
15+
version = "*"
16+
17+
[dependencies.rosidl_runtime_rs]
18+
version = "*"

rclrs_tests/package.xml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="2.0"?>
2+
<?xml-model
3+
href="http://download.ros.org/schema/package_format3.xsd"
4+
schematypens="http://www.w3.org/2001/XMLSchema"?>
5+
<package format="3">
6+
<name>rclrs_tests</name>
7+
<version>0.2.0</version>
8+
<description>Package containing tests for rclrs that make use of msgs and other dependencies</description>
9+
<maintainer email="christopherjreid@outlook.com">Chris Reid</maintainer>
10+
<license>Apache License 2.0</license>
11+
12+
<depend>test_msgs</depend>
13+
<depend>rclrs</depend>
14+
<depend>rosidl_runtime_rs</depend>
15+
16+
<export>
17+
<build_type>ament_cargo</build_type>
18+
</export>
19+
</package>

rclrs_tests/src/graph_tests.rs

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
use rclrs::{
2+
Context, Node, NodeBuilder, RclrsError, TopicNamesAndTypes, QOS_PROFILE_SYSTEM_DEFAULT,
3+
};
4+
5+
use test_msgs::{msg, srv};
6+
7+
struct TestGraph {
8+
node1: Node,
9+
node2: Node,
10+
}
11+
12+
fn construct_test_graph(namespace: &str) -> Result<TestGraph, RclrsError> {
13+
let context = Context::new([])?;
14+
Ok(TestGraph {
15+
node1: NodeBuilder::new(&context, "graph_test_node_1")
16+
.namespace(namespace)
17+
.build()?,
18+
node2: NodeBuilder::new(&context, "graph_test_node_2")
19+
.namespace(namespace)
20+
.build()?,
21+
})
22+
}
23+
24+
#[test]
25+
fn test_publishers() -> Result<(), RclrsError> {
26+
let graph = construct_test_graph("test_publishers_graph")?;
27+
28+
let _node_1_empty_publisher = graph
29+
.node1
30+
.create_publisher::<msg::Empty>("graph_test_topic_1", QOS_PROFILE_SYSTEM_DEFAULT)?;
31+
let _node_1_basic_types_publisher = graph
32+
.node1
33+
.create_publisher::<msg::BasicTypes>("graph_test_topic_2", QOS_PROFILE_SYSTEM_DEFAULT)?;
34+
let _node_2_default_publisher = graph
35+
.node2
36+
.create_publisher::<msg::Defaults>("graph_test_topic_3", QOS_PROFILE_SYSTEM_DEFAULT)?;
37+
38+
std::thread::sleep(std::time::Duration::from_millis(100));
39+
40+
assert_eq!(
41+
graph
42+
.node1
43+
.count_publishers(&(graph.node1.namespace() + "/graph_test_topic_1"))?,
44+
1
45+
);
46+
assert_eq!(
47+
graph
48+
.node1
49+
.count_publishers(&(graph.node1.namespace() + "/graph_test_topic_2"))?,
50+
1
51+
);
52+
let node_1_publisher_names_and_types = graph
53+
.node1
54+
.get_publisher_names_and_types_by_node(&graph.node1.name(), &graph.node1.namespace())?;
55+
56+
let types = node_1_publisher_names_and_types
57+
.get(&(graph.node1.namespace() + "/graph_test_topic_1"))
58+
.unwrap();
59+
assert!(types.contains(&"test_msgs/msg/Empty".to_string()));
60+
61+
let types = node_1_publisher_names_and_types
62+
.get(&(graph.node1.namespace() + "/graph_test_topic_2"))
63+
.unwrap();
64+
assert!(types.contains(&"test_msgs/msg/BasicTypes".to_string()));
65+
66+
let node_2_publisher_names_and_types = graph
67+
.node2
68+
.get_publisher_names_and_types_by_node(&graph.node2.name(), &graph.node2.namespace())?;
69+
70+
let types = node_2_publisher_names_and_types
71+
.get(&(graph.node2.namespace() + "/graph_test_topic_3"))
72+
.unwrap();
73+
assert_eq!(
74+
graph
75+
.node2
76+
.count_publishers(&(graph.node2.namespace() + "/graph_test_topic_3"))?,
77+
1
78+
);
79+
assert!(types.contains(&"test_msgs/msg/Defaults".to_string()));
80+
81+
Ok(())
82+
}
83+
84+
#[test]
85+
fn test_subscriptions() -> Result<(), RclrsError> {
86+
let mut graph = construct_test_graph("test_subscriptions_graph")?;
87+
88+
let _node_1_defaults_subscription = graph.node1.create_subscription::<msg::Defaults, _>(
89+
"graph_test_topic_3",
90+
QOS_PROFILE_SYSTEM_DEFAULT,
91+
|_msg| {},
92+
)?;
93+
let _node_2_empty_subscription = graph.node2.create_subscription::<msg::Empty, _>(
94+
"graph_test_topic_1",
95+
QOS_PROFILE_SYSTEM_DEFAULT,
96+
|_msg| {},
97+
)?;
98+
let _node_2_basic_types_subscription = graph.node2.create_subscription::<msg::BasicTypes, _>(
99+
"graph_test_topic_2",
100+
QOS_PROFILE_SYSTEM_DEFAULT,
101+
|_msg| {},
102+
)?;
103+
104+
std::thread::sleep(std::time::Duration::from_millis(100));
105+
106+
let node_1_subscription_names_and_types = graph
107+
.node1
108+
.get_subscription_names_and_types_by_node(&graph.node1.name(), &graph.node1.namespace())?;
109+
110+
let types = node_1_subscription_names_and_types
111+
.get(&(graph.node2.namespace() + "/graph_test_topic_3"))
112+
.unwrap();
113+
assert!(types.contains(&"test_msgs/msg/Defaults".to_string()));
114+
115+
assert_eq!(
116+
graph
117+
.node2
118+
.count_subscriptions(&(graph.node2.namespace() + "/graph_test_topic_1"))?,
119+
1
120+
);
121+
assert_eq!(
122+
graph
123+
.node2
124+
.count_subscriptions(&(graph.node2.namespace() + "/graph_test_topic_2"))?,
125+
1
126+
);
127+
128+
let node_2_subscription_names_and_types = graph
129+
.node2
130+
.get_subscription_names_and_types_by_node(&graph.node2.name(), &graph.node2.namespace())?;
131+
132+
let types = node_2_subscription_names_and_types
133+
.get(&(graph.node1.namespace() + "/graph_test_topic_1"))
134+
.unwrap();
135+
assert!(types.contains(&"test_msgs/msg/Empty".to_string()));
136+
137+
let types = node_2_subscription_names_and_types
138+
.get(&(graph.node2.namespace() + "/graph_test_topic_2"))
139+
.unwrap();
140+
assert!(types.contains(&"test_msgs/msg/BasicTypes".to_string()));
141+
142+
Ok(())
143+
}
144+
145+
#[test]
146+
fn test_topic_names_and_types() -> Result<(), RclrsError> {
147+
let mut graph = construct_test_graph("test_topics_graph")?;
148+
149+
let _node_1_defaults_subscription = graph.node1.create_subscription::<msg::Defaults, _>(
150+
"graph_test_topic_3",
151+
QOS_PROFILE_SYSTEM_DEFAULT,
152+
|_msg| {},
153+
)?;
154+
let _node_2_empty_subscription = graph.node2.create_subscription::<msg::Empty, _>(
155+
"graph_test_topic_1",
156+
QOS_PROFILE_SYSTEM_DEFAULT,
157+
|_msg| {},
158+
)?;
159+
let _node_2_basic_types_subscription = graph.node2.create_subscription::<msg::BasicTypes, _>(
160+
"graph_test_topic_2",
161+
QOS_PROFILE_SYSTEM_DEFAULT,
162+
|_msg| {},
163+
)?;
164+
165+
std::thread::sleep(std::time::Duration::from_millis(100));
166+
167+
let topic_names_and_types = graph.node1.get_topic_names_and_types()?;
168+
169+
let types = topic_names_and_types
170+
.get("/test_topics_graph/graph_test_topic_1")
171+
.unwrap();
172+
assert!(types.contains(&"test_msgs/msg/Empty".to_string()));
173+
let types = topic_names_and_types
174+
.get("/test_topics_graph/graph_test_topic_2")
175+
.unwrap();
176+
assert!(types.contains(&"test_msgs/msg/BasicTypes".to_string()));
177+
178+
let types = topic_names_and_types
179+
.get("/test_topics_graph/graph_test_topic_3")
180+
.unwrap();
181+
assert!(types.contains(&"test_msgs/msg/Defaults".to_string()));
182+
183+
Ok(())
184+
}
185+
186+
#[test]
187+
fn test_services() -> Result<(), RclrsError> {
188+
let mut graph = construct_test_graph("test_services_graph")?;
189+
let check_names_and_types = |names_and_types: TopicNamesAndTypes| {
190+
let types = names_and_types
191+
.get("/test_services_graph/graph_test_topic_4")
192+
.unwrap();
193+
assert!(types.contains(&"test_msgs/srv/Empty".to_string()));
194+
};
195+
196+
let _node_1_empty_service =
197+
graph
198+
.node1
199+
.create_service::<srv::Empty, _>("graph_test_topic_4", |_, _| srv::Empty_Response {
200+
structure_needs_at_least_one_member: 0,
201+
})?;
202+
let _node_2_empty_client = graph
203+
.node2
204+
.create_client::<srv::Empty>("graph_test_topic_4")?;
205+
206+
std::thread::sleep(std::time::Duration::from_millis(100));
207+
208+
let service_names_and_types = graph.node1.get_service_names_and_types()?;
209+
check_names_and_types(service_names_and_types);
210+
211+
let service_names_and_types = graph
212+
.node1
213+
.get_service_names_and_types_by_node(&graph.node1.name(), &graph.node1.namespace())?;
214+
check_names_and_types(service_names_and_types);
215+
216+
Ok(())
217+
}
218+
219+
#[test]
220+
fn test_clients() -> Result<(), RclrsError> {
221+
let mut graph = construct_test_graph("test_clients_graph")?;
222+
let _node_2_empty_client = graph
223+
.node2
224+
.create_client::<srv::Empty>("graph_test_topic_4")?;
225+
226+
std::thread::sleep(std::time::Duration::from_millis(200));
227+
228+
let client_names_and_types = graph
229+
.node2
230+
.get_client_names_and_types_by_node(&graph.node2.name(), &graph.node2.namespace())?;
231+
let types = client_names_and_types
232+
.get("/test_clients_graph/graph_test_topic_4")
233+
.unwrap();
234+
235+
assert!(types.contains(&"test_msgs/srv/Empty".to_string()));
236+
237+
Ok(())
238+
}

rclrs_tests/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#![cfg(test)]
2+
3+
mod graph_tests;

0 commit comments

Comments
 (0)