Skip to content

Commit 496132e

Browse files
committed
Add ROS 2 integration tests
Closes #746
1 parent 343c121 commit 496132e

File tree

10 files changed

+239
-186
lines changed

10 files changed

+239
-186
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
strategy:
1818
fail-fast: false
1919
matrix:
20-
ros_distro: [noetic]
20+
ros_distro: [noetic, humble, jazzy]
2121
node_version: [20, 22, 24]
2222
env:
2323
ROS_DISTRO: ${{ matrix.ros_distro }}

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ COPY test/examples/ /workspace/test/examples/
1717
EXPOSE 9090
1818

1919
# Default command runs the ROS backend for testing
20-
CMD ["bash", "-c", "source /opt/ros/$ROS_DISTRO/setup.bash && roslaunch /workspace/test/examples/setup_examples.launch"]
20+
CMD ["bash", "-c", "source /opt/ros/$ROS_DISTRO/setup.bash && bash /workspace/test/examples/setup_examples.bash"]

package.xml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" ?>
2-
<package>
2+
<package xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/ros-infrastructure/rep/master/xsd/package_format3.xsd" format="3">
33
<name>roslibjs</name>
44
<version>2.0.0</version>
55
<description>The Robot Web Tools ROS JavaScript Library</description>
@@ -18,7 +18,11 @@
1818
<test_depend>libnss3-dev</test_depend>
1919
<test_depend>rosbridge_server</test_depend>
2020
<test_depend>tf2_web_republisher</test_depend>
21-
<test_depend>common_tutorials</test_depend>
22-
<test_depend>ros_tutorials</test_depend>
21+
<test_depend condition="$ROS_VERSION == 1">common_tutorials</test_depend>
22+
<test_depend condition="$ROS_VERSION == 1">ros_tutorials</test_depend>
23+
<test_depend condition="$ROS_VERSION == 2">action_tutorials_cpp</test_depend>
24+
<test_depend condition="$ROS_VERSION == 2">examples_rclpy_minimal_service</test_depend>
25+
<test_depend condition="$ROS_VERSION == 2">tf2_ros</test_depend>
26+
2327

2428
</package>

test/examples/check-topics.example.ts

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,7 @@
1-
import { describe, it, expect } from "vitest";
1+
import { describe, it, expect, vi } from "vitest";
22
import * as ROSLIB from "../../src/RosLib.js";
33

4-
const expectedTopics = [
5-
/*
6-
* '/turtle1/cmd_vel', '/turtle1/color_sensor', '/turtle1/pose',
7-
* '/turtle2/cmd_vel', '/turtle2/color_sensor', '/turtle2/pose',
8-
*/
9-
"/tf2_web_republisher/status",
10-
"/tf2_web_republisher/feedback",
11-
// '/tf2_web_republisher/goal', '/tf2_web_republisher/result',
12-
"/fibonacci/feedback",
13-
"/fibonacci/status",
14-
"/fibonacci/result",
15-
];
4+
const expectedTopics = ["/listener"];
165

176
describe("Example topics are live", function () {
187
const ros = new ROSLIB.Ros({
@@ -55,18 +44,12 @@ describe("Example topics are live", function () {
5544
});
5645
}));
5746

58-
it(
59-
"unadvertise will end the topic (if it's the last around)",
60-
() =>
61-
new Promise((done) => {
62-
console.log("Unadvertisement test. Wait for 15 seconds..");
63-
setTimeout(function () {
64-
ros.getTopics(function (result) {
65-
expect(result.topics).not.to.contain("/some_test_topic");
66-
done(result);
67-
});
68-
}, 15000);
69-
}),
70-
20000,
71-
);
47+
it("unadvertise will end the topic (if it's the last around)", async () => {
48+
console.log("Unadvertisement test. Wait for 15 seconds..");
49+
vi.waitFor(function () {
50+
ros.getTopics(function (result) {
51+
expect(result.topics).not.to.contain("/some_test_topic");
52+
});
53+
}, 15000);
54+
});
7255
});

test/examples/fibonacci.example.ts

Lines changed: 60 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,67 @@
11
import { describe, it, expect } from "vitest";
22
import * as ROSLIB from "../../src/RosLib.js";
33

4-
describe("Fibonacci Example", function () {
5-
it(
6-
"Fibonacci",
7-
() =>
8-
new Promise<void>((done) => {
9-
const ros = new ROSLIB.Ros({
10-
url: "ws://localhost:9090",
11-
});
12-
/*
13-
* The ActionClient
14-
* ----------------
15-
*/
4+
// Noetic is the only version of ROS 1 we support, so we skip based on distro name
5+
// instead of adding extra plumbing for ROS_VERSION.
6+
describe.skipIf(process.env.ROS_DISTRO !== "noetic")(
7+
"ROS 1 Fibonacci Example",
8+
function () {
9+
it(
10+
"Fibonacci",
11+
() =>
12+
new Promise<void>((done) => {
13+
const ros = new ROSLIB.Ros({
14+
url: "ws://localhost:9090",
15+
});
16+
/*
17+
* The ActionClient
18+
* ----------------
19+
*/
1620

17-
const fibonacciClient = new ROSLIB.ActionClient({
18-
ros: ros,
19-
serverName: "/fibonacci",
20-
actionName: "actionlib_tutorials/FibonacciAction",
21-
});
21+
const fibonacciClient = new ROSLIB.ActionClient({
22+
ros: ros,
23+
serverName: "/fibonacci",
24+
actionName: "actionlib_tutorials/FibonacciAction",
25+
});
2226

23-
// Create a goal.
24-
const goal = new ROSLIB.Goal({
25-
actionClient: fibonacciClient,
26-
goalMessage: {
27-
order: 7,
28-
},
29-
});
27+
// Create a goal.
28+
const goal = new ROSLIB.Goal({
29+
actionClient: fibonacciClient,
30+
goalMessage: {
31+
order: 7,
32+
},
33+
});
3034

31-
// Print out their output into the terminal.
32-
const items = [
33-
{ sequence: [0, 1, 1] },
34-
{ sequence: [0, 1, 1, 2] },
35-
{ sequence: [0, 1, 1, 2, 3] },
36-
{ sequence: [0, 1, 1, 2, 3, 5] },
37-
{ sequence: [0, 1, 1, 2, 3, 5, 8] },
38-
{ sequence: [0, 1, 1, 2, 3, 5, 8, 13] },
39-
{ sequence: [0, 1, 1, 2, 3, 5, 8, 13, 21] },
40-
];
41-
goal.on("feedback", function (feedback) {
42-
console.log("Feedback:", feedback);
43-
expect(feedback).to.eql(items.shift());
44-
});
45-
goal.on("result", function (result) {
46-
console.log("Result:", result);
47-
expect(result).to.eql({ sequence: [0, 1, 1, 2, 3, 5, 8, 13, 21] });
48-
done();
49-
});
35+
// Print out their output into the terminal.
36+
const items = [
37+
{ sequence: [0, 1, 1] },
38+
{ sequence: [0, 1, 1, 2] },
39+
{ sequence: [0, 1, 1, 2, 3] },
40+
{ sequence: [0, 1, 1, 2, 3, 5] },
41+
{ sequence: [0, 1, 1, 2, 3, 5, 8] },
42+
{ sequence: [0, 1, 1, 2, 3, 5, 8, 13] },
43+
{ sequence: [0, 1, 1, 2, 3, 5, 8, 13, 21] },
44+
];
45+
goal.on("feedback", function (feedback) {
46+
console.log("Feedback:", feedback);
47+
expect(feedback).to.eql(items.shift());
48+
});
49+
goal.on("result", function (result) {
50+
console.log("Result:", result);
51+
expect(result).to.eql({ sequence: [0, 1, 1, 2, 3, 5, 8, 13, 21] });
52+
done();
53+
});
5054

51-
/*
52-
* Send the goal to the action server.
53-
* The timeout is to allow rosbridge to properly subscribe all the
54-
* Action topics - otherwise, the first feedback message might get lost
55-
*/
56-
setTimeout(function () {
57-
goal.send();
58-
}, 100);
59-
}),
60-
8000,
61-
);
62-
});
55+
/*
56+
* Send the goal to the action server.
57+
* The timeout is to allow rosbridge to properly subscribe all the
58+
* Action topics - otherwise, the first feedback message might get lost
59+
*/
60+
setTimeout(function () {
61+
goal.send();
62+
}, 100);
63+
}),
64+
8000,
65+
);
66+
},
67+
);

test/examples/setup_examples.bash

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,64 @@
11
#! /usr/bin/env bash
22

3-
if command -v rosrun 2>/dev/null
4-
then
3+
# Change to the directory where this script is located
4+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5+
cd "$SCRIPT_DIR"
6+
7+
# Function to check if ROS 1 is available
8+
check_ros1() {
9+
command -v rosrun >/dev/null 2>&1
10+
}
11+
12+
# Function to check if ROS 2 is available
13+
check_ros2() {
14+
command -v ros2 >/dev/null 2>&1
15+
}
16+
17+
# Function to setup ROS 1
18+
setup_ros1() {
19+
echo "Setting up ROS 1 environment"
20+
521
echo "Shutting everything down"
622
pgrep -f "ros" | xargs kill -9 2>/dev/null
723
sleep 1
824

9-
echo "Starting roscore and various examples in background processes"
10-
roslaunch examples/setup_examples.launch > roslaunch.log &
11-
12-
LAUNCHED=false
13-
for i in {1..10}
14-
do
15-
echo "Waiting for /hello_world_publisher...$i"
16-
sleep 1
17-
rostopic info /listener > /dev/null && LAUNCHED=true && break
18-
done
19-
if [ $LAUNCHED == true ]
20-
then
21-
echo "Ready for lift off"
22-
exit 0
25+
echo "Starting roscore and various examples"
26+
roslaunch setup_examples.launch
27+
}
28+
29+
# Function to setup ROS 2
30+
setup_ros2() {
31+
echo "Setting up ROS 2 environment"
32+
33+
echo "Shutting everything down"
34+
pgrep -f "ros2\|launch" | xargs kill -9 2>/dev/null
35+
sleep 1
36+
37+
echo "Starting ROS 2 launch file and various examples"
38+
ros2 launch setup_examples_ros2.launch.xml
39+
}
40+
41+
# Main logic
42+
if [ "$ROS_VERSION" == "2" ]; then
43+
if check_ros2; then
44+
setup_ros2
45+
else
46+
echo "ROS_VERSION is set to 2 but ROS 2 is not available on path"
47+
# shellcheck disable=SC2016
48+
echo 'Make sure to source ROS 2: source /opt/ros/$ROS_DISTRO/setup.bash'
49+
exit 1
50+
fi
51+
elif [ "$ROS_VERSION" == "1" ] || [ -z "$ROS_VERSION" ]; then
52+
if check_ros1; then
53+
setup_ros1
2354
else
24-
echo "/hello_world_publisher not launched"
55+
echo "Couldn't find ROS 1 on path (try to source it)"
56+
# shellcheck disable=SC2016
57+
echo 'source /opt/ros/$ROS_DISTRO/setup.bash'
2558
exit 1
2659
fi
2760
else
28-
echo "Couldn't find ROS on path (try to source it)"
29-
# shellcheck disable=SC2016
30-
echo 'source /opt/ros/$ROS_DISTRO/setup.bash'
61+
echo "Unknown ROS_VERSION: $ROS_VERSION"
62+
echo "Please set ROS_VERSION to either '1' or '2'"
3163
exit 1
3264
fi
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0"?>
2+
<launch>
3+
<!-- Include rosbridge websocket launch file for ROS 2 -->
4+
<include file="$(find-pkg-share rosbridge_server)/launch/rosbridge_websocket_launch.xml"/>
5+
6+
<!-- Static transform publisher (equivalent to tf static_transform_publisher) -->
7+
<node pkg="tf2_ros" exec="static_transform_publisher" name="tf_publisher"
8+
args="0 0 0 0 0 0 world turtle1"/>
9+
10+
<!-- TF2 web republisher -->
11+
<node pkg="tf2_web_republisher" exec="tf2_web_republisher_node" name="tf2_web_republisher"/>
12+
13+
<!-- Fibonacci action server (ROS 2 equivalent) -->
14+
<node pkg="action_tutorials_cpp" exec="fibonacci_action_server" name="fibonacci_server"/>
15+
16+
<!-- Add two ints service server (ROS 2 equivalent) -->
17+
<node pkg="examples_rclpy_minimal_service" exec="service" name="add_two_ints_server"/>
18+
19+
<!-- Hello world publisher using ros2 topic pub command -->
20+
<executable cmd="ros2 topic pub --rate 1 /listener std_msgs/msg/String 'data: Hello, World'"
21+
name="hello_world_publisher"/>
22+
</launch>

0 commit comments

Comments
 (0)