From ad0fb3b11dd5f9e9ed7b7919ef845ef3b31f43f2 Mon Sep 17 00:00:00 2001 From: ChenYing Kuo Date: Thu, 12 Dec 2024 11:03:13 +0800 Subject: [PATCH] Move CI to an independent crate. Signed-off-by: ChenYing Kuo --- .github/workflows/ci.yml | 78 ++++++++-------- Cargo.toml | 5 -- zenoh-plugin-ros2dds/Cargo.toml | 9 -- zenoh-plugin-ros2dds/tests/test.rs | 140 ----------------------------- zenoh-test-ros2dds/Cargo.toml | 33 +++++++ zenoh-test-ros2dds/tests/topic.rs | 131 +++++++++++++++++++++++++++ 6 files changed, 203 insertions(+), 193 deletions(-) delete mode 100644 zenoh-plugin-ros2dds/tests/test.rs create mode 100644 zenoh-test-ros2dds/Cargo.toml create mode 100644 zenoh-test-ros2dds/tests/topic.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 482a99d..1809edc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,45 +63,45 @@ jobs: - name: Run tests run: cargo test --verbose - # system_tests_with_ros2_humble: - # name: System tests with ROS 2 Humble - # runs-on: ubuntu-latest - # container: - # image: rostooling/setup-ros-docker:ubuntu-jammy-ros-humble-ros-base-latest - # steps: - # - uses: ros-tooling/setup-ros@v0.7 - # with: - # required-ros-distributions: humble - - # - uses: actions/checkout@v4 - # - uses: actions-rust-lang/setup-rust-toolchain@v1 - - # - name: Install ACL - # run: sudo apt-get -y install libacl1-dev - - # - name: Run ROS tests (enable feature ros_test) - # shell: bash - # run: "source /opt/ros/humble/setup.bash && cargo test --features ros_test --verbose" - - # system_tests_with_ros2_jazzy: - # name: System tests with ROS 2 Jazzy - # runs-on: ubuntu-latest - # container: - # image: rostooling/setup-ros-docker:ubuntu-noble-ros-jazzy-ros-base-latest - # steps: - # - uses: ros-tooling/setup-ros@v0.7 - # with: - # required-ros-distributions: jazzy - - # - uses: actions/checkout@v4 - # - uses: actions-rust-lang/setup-rust-toolchain@v1 - - # - name: Install ACL - # run: sudo apt-get -y install libacl1-dev - - # - name: Run ROS tests (enable feature ros_test) - # shell: bash - # run: "source /opt/ros/jazzy/setup.bash && cargo test --features ros_test --verbose" + system_tests_with_ros2_humble: + name: System tests with ROS 2 Humble + runs-on: ubuntu-latest + container: + image: rostooling/setup-ros-docker:ubuntu-jammy-ros-humble-ros-base-latest + steps: + - uses: ros-tooling/setup-ros@v0.7 + with: + required-ros-distributions: humble + + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + + - name: Install ACL + run: sudo apt-get -y install libacl1-dev + + - name: Run ROS tests + shell: bash + run: "source /opt/ros/humble/setup.bash && cd zenoh-test-ros2dds && cargo test --verbose" + + system_tests_with_ros2_jazzy: + name: System tests with ROS 2 Jazzy + runs-on: ubuntu-latest + container: + image: rostooling/setup-ros-docker:ubuntu-noble-ros-jazzy-ros-base-latest + steps: + - uses: ros-tooling/setup-ros@v0.7 + with: + required-ros-distributions: jazzy + + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + + - name: Install ACL + run: sudo apt-get -y install libacl1-dev + + - name: Run ROS tests + shell: bash + run: "source /opt/ros/jazzy/setup.bash && cd zenoh-test-ros2dds && cargo test --verbose" # NOTE: In GitHub repository settings, the "Require status checks to pass # before merging" branch protection rule ensures that commits are only merged diff --git a/Cargo.toml b/Cargo.toml index fcdd2dc..d534709 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,11 +57,6 @@ zenoh-plugin-rest = { version = "1.0.0-dev", git = "https://github.com/eclipse-z ] } zenoh-plugin-trait = { version = "1.0.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "main", default-features = false } -# r2r is for tests only. See in in zenoh-plugins-ros2dds/Cargo.toml -# TODO: The ros_test should be re-enabled as soon the r2r dependency is removed from the build of zenoh-plugin-ros2dds -# r2r = "0.9" - - [profile.release] codegen-units = 1 debug = false diff --git a/zenoh-plugin-ros2dds/Cargo.toml b/zenoh-plugin-ros2dds/Cargo.toml index d4a8e94..67b671a 100644 --- a/zenoh-plugin-ros2dds/Cargo.toml +++ b/zenoh-plugin-ros2dds/Cargo.toml @@ -32,9 +32,6 @@ stats = ["zenoh/stats"] dynamic_plugin = [] dds_shm = ["cyclors/iceoryx"] -# TODO: The ros_test should be re-enabled as soon the r2r dependency is removed from the build of zenoh-plugin-ros2dds -# ros_test = ["r2r"] - [dependencies] async-trait = { workspace = true } bincode = { workspace = true } @@ -57,12 +54,6 @@ zenoh-config = { workspace = true } zenoh-ext = { workspace = true } zenoh-plugin-trait = { workspace = true } -# r2r is for tests only. It has to be optional because its building requires a full ROS 2 environement -# However "optional" is not supported for "dev-dependencies". -# Hence it's declared as a dependency but active only with "ros_test" feature -# r2r = { workspace = true, optional = true } - - [build-dependencies] rustc_version = { workspace = true } diff --git a/zenoh-plugin-ros2dds/tests/test.rs b/zenoh-plugin-ros2dds/tests/test.rs deleted file mode 100644 index ecf1a90..0000000 --- a/zenoh-plugin-ros2dds/tests/test.rs +++ /dev/null @@ -1,140 +0,0 @@ -// -// Copyright (c) 2024 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -// TODO: The ros_test should be re-enabled as soon the r2r dependency is removed from the build of zenoh-plugin-ros2dds - -// #[cfg(feature = "ros_test")] -// mod ros_test { -// use std::{sync::mpsc::channel, time::Duration}; - -// use futures::StreamExt; -// use r2r::{self, QosProfile}; -// use zenoh::{ -// config::Config, -// internal::{plugins::PluginsManager, runtime::RuntimeBuilder}, -// }; -// use zenoh_config::ModeDependentValue; - -// // The test topic -// const TEST_TOPIC: &str = "test_topic"; -// // The test TEST_PAYLOAD -// const TEST_PAYLOAD: &str = "Hello World"; - -// fn init_env() { -// std::env::set_var("RMW_IMPLEMENTATION", "rmw_cyclonedds_cpp"); -// } - -// async fn create_bridge() { -// let mut plugins_mgr = PluginsManager::static_plugins_only(); -// plugins_mgr -// .declare_static_plugin::("ros2dds", true); -// let mut config = Config::default(); -// config.insert_json5("plugins/ros2dds", "{}").unwrap(); -// config -// .timestamping -// .set_enabled(Some(ModeDependentValue::Unique(true))) -// .unwrap(); -// config.adminspace.set_enabled(true).unwrap(); -// config.plugins_loading.set_enabled(true).unwrap(); -// let mut runtime = RuntimeBuilder::new(config) -// .plugins_manager(plugins_mgr) -// .build() -// .await -// .unwrap(); -// runtime.start().await.unwrap(); -// } - -// #[tokio::test(flavor = "multi_thread")] -// async fn test_zenoh_pub_ros_sub() { -// init_env(); -// let (tx, rx) = channel(); - -// // Create zenoh-bridge-ros2dds -// tokio::spawn(create_bridge()); - -// // ROS subscriber -// let ctx = r2r::Context::create().unwrap(); -// let mut node = r2r::Node::create(ctx, "ros_sub", "").unwrap(); -// let subscriber = node -// .subscribe::( -// &format!("/{}", TEST_TOPIC), -// QosProfile::default(), -// ) -// .unwrap(); - -// // Zenoh publisher -// let session = zenoh::open(zenoh::Config::default()).await.unwrap(); -// let publisher = session.declare_publisher(TEST_TOPIC).await.unwrap(); - -// // Wait for the environment to be ready -// tokio::time::sleep(Duration::from_secs(1)).await; - -// // Publish Zenoh message -// let buf = cdr::serialize::<_, _, cdr::CdrLe>(TEST_PAYLOAD, cdr::size::Infinite).unwrap(); -// publisher.put(buf).await.unwrap(); - -// // Check ROS subscriber will receive the data -// tokio::spawn(async move { -// subscriber -// .for_each(|msg| { -// tx.send(msg.data).unwrap(); -// futures::future::ready(()) -// }) -// .await -// }); -// node.spin_once(std::time::Duration::from_millis(100)); -// let data = rx -// .recv_timeout(Duration::from_secs(3)) -// .expect("Receiver timeout"); -// assert_eq!(data, TEST_PAYLOAD); -// } - -// #[tokio::test(flavor = "multi_thread")] -// async fn test_ros_pub_zenoh_sub() { -// init_env(); -// // Create zenoh-bridge-ros2dds -// tokio::spawn(create_bridge()); - -// // Zenoh subscriber -// let session = zenoh::open(zenoh::Config::default()).await.unwrap(); -// let subscriber = session.declare_subscriber(TEST_TOPIC).await.unwrap(); - -// // ROS publisher -// let ctx = r2r::Context::create().unwrap(); -// let mut node = r2r::Node::create(ctx, "ros_pub", "").unwrap(); -// let publisher = node -// .create_publisher(&format!("/{}", TEST_TOPIC), QosProfile::default()) -// .unwrap(); -// let msg = r2r::std_msgs::msg::String { -// data: TEST_PAYLOAD.into(), -// }; - -// // Wait for the environment to be ready -// tokio::time::sleep(Duration::from_secs(1)).await; - -// // Publish ROS message -// publisher.publish(&msg).unwrap(); - -// // Check Zenoh subscriber will receive the data -// tokio::time::timeout(Duration::from_secs(3), async { -// let sample = subscriber.recv_async().await.unwrap(); -// let result: Result = -// cdr::deserialize_from(sample.payload().reader(), cdr::size::Infinite); -// let recv_data = result.expect("Fail to receive data"); -// assert_eq!(recv_data, TEST_PAYLOAD); -// }) -// .await -// .expect("Timeout: Zenoh subscriber didn't receive any ROS message."); -// } -// } diff --git a/zenoh-test-ros2dds/Cargo.toml b/zenoh-test-ros2dds/Cargo.toml new file mode 100644 index 0000000..7e35d71 --- /dev/null +++ b/zenoh-test-ros2dds/Cargo.toml @@ -0,0 +1,33 @@ +# +# Copyright (c) 2024 ZettaScale Technology +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +# which is available at https://www.apache.org/licenses/LICENSE-2.0. +# +# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +# +# Contributors: +# ZettaScale Zenoh Team, +# +[package] +name = "zenoh-test-ros2dds" +edition = "2021" + +[dependencies] +cdr = "0.2.4" +futures = "0.3.26" +r2r = "0.9" +serde = "1.0.154" +serde_json = "1.0.114" +tokio = { version = "1.35.1", default-features = false } # Default features are disabled due to some crates' requirements +zenoh = { version = "1.0.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "main", features = [ + "plugins", + "unstable", +] } +zenoh-config = { version = "1.0.0-dev", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "main", default-features = false } +zenoh-plugin-ros2dds = { version = "1.0.0-dev", path = "../zenoh-plugin-ros2dds/", default-features = false } + +# We need an empty workspace to avoid being viewed as a part of zenoh-plugin-ros2dds +[workspace] diff --git a/zenoh-test-ros2dds/tests/topic.rs b/zenoh-test-ros2dds/tests/topic.rs new file mode 100644 index 0000000..9ceb43d --- /dev/null +++ b/zenoh-test-ros2dds/tests/topic.rs @@ -0,0 +1,131 @@ +// +// Copyright (c) 2024 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +use std::{sync::mpsc::channel, time::Duration}; + +use futures::StreamExt; +use r2r::{self, QosProfile}; +use zenoh::{ + config::Config, + internal::{plugins::PluginsManager, runtime::RuntimeBuilder}, +}; +use zenoh_config::ModeDependentValue; + +// The test topic +const TEST_TOPIC: &str = "test_topic"; +// The test TEST_PAYLOAD +const TEST_PAYLOAD: &str = "Hello World"; + +fn init_env() { + std::env::set_var("RMW_IMPLEMENTATION", "rmw_cyclonedds_cpp"); +} + +async fn create_bridge() { + let mut plugins_mgr = PluginsManager::static_plugins_only(); + plugins_mgr.declare_static_plugin::("ros2dds", true); + let mut config = Config::default(); + config.insert_json5("plugins/ros2dds", "{}").unwrap(); + config + .timestamping + .set_enabled(Some(ModeDependentValue::Unique(true))) + .unwrap(); + config.adminspace.set_enabled(true).unwrap(); + config.plugins_loading.set_enabled(true).unwrap(); + let mut runtime = RuntimeBuilder::new(config) + .plugins_manager(plugins_mgr) + .build() + .await + .unwrap(); + runtime.start().await.unwrap(); +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_zenoh_pub_ros_sub() { + init_env(); + let (tx, rx) = channel(); + + // Create zenoh-bridge-ros2dds + tokio::spawn(create_bridge()); + + // ROS subscriber + let ctx = r2r::Context::create().unwrap(); + let mut node = r2r::Node::create(ctx, "ros_sub", "").unwrap(); + let subscriber = node + .subscribe::(&format!("/{}", TEST_TOPIC), QosProfile::default()) + .unwrap(); + + // Zenoh publisher + let session = zenoh::open(zenoh::Config::default()).await.unwrap(); + let publisher = session.declare_publisher(TEST_TOPIC).await.unwrap(); + + // Wait for the environment to be ready + tokio::time::sleep(Duration::from_secs(1)).await; + + // Publish Zenoh message + let buf = cdr::serialize::<_, _, cdr::CdrLe>(TEST_PAYLOAD, cdr::size::Infinite).unwrap(); + publisher.put(buf).await.unwrap(); + + // Check ROS subscriber will receive the data + tokio::spawn(async move { + subscriber + .for_each(|msg| { + tx.send(msg.data).unwrap(); + futures::future::ready(()) + }) + .await + }); + node.spin_once(std::time::Duration::from_millis(100)); + let data = rx + .recv_timeout(Duration::from_secs(3)) + .expect("Receiver timeout"); + assert_eq!(data, TEST_PAYLOAD); +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_ros_pub_zenoh_sub() { + init_env(); + // Create zenoh-bridge-ros2dds + tokio::spawn(create_bridge()); + + // Zenoh subscriber + let session = zenoh::open(zenoh::Config::default()).await.unwrap(); + let subscriber = session.declare_subscriber(TEST_TOPIC).await.unwrap(); + + // ROS publisher + let ctx = r2r::Context::create().unwrap(); + let mut node = r2r::Node::create(ctx, "ros_pub", "").unwrap(); + let publisher = node + .create_publisher(&format!("/{}", TEST_TOPIC), QosProfile::default()) + .unwrap(); + let msg = r2r::std_msgs::msg::String { + data: TEST_PAYLOAD.into(), + }; + + // Wait for the environment to be ready + tokio::time::sleep(Duration::from_secs(1)).await; + + // Publish ROS message + publisher.publish(&msg).unwrap(); + + // Check Zenoh subscriber will receive the data + tokio::time::timeout(Duration::from_secs(3), async { + let sample = subscriber.recv_async().await.unwrap(); + let result: Result = + cdr::deserialize_from(sample.payload().reader(), cdr::size::Infinite); + let recv_data = result.expect("Fail to receive data"); + assert_eq!(recv_data, TEST_PAYLOAD); + }) + .await + .expect("Timeout: Zenoh subscriber didn't receive any ROS message."); +}