Skip to content

Commit 8fa9fc8

Browse files
committed
add test for playback using qos profile
Signed-off-by: Emerson Knapp <[email protected]>
1 parent 4652cc3 commit 8fa9fc8

File tree

2 files changed

+69
-34
lines changed

2 files changed

+69
-34
lines changed

rosbag2_transport/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ function(create_tests_for_rmw_implementation)
157157

158158
rosbag2_transport_add_gmock(test_play
159159
test/rosbag2_transport/test_play.cpp
160+
INCLUDE_DIRS $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/rosbag2_transport>
160161
${SKIP_TEST}
161162
LINK_LIBS rosbag2_transport
162163
AMENT_DEPS test_msgs rosbag2_test_common)

rosbag2_transport/test/rosbag2_transport/test_play.cpp

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@
3232
#include "test_msgs/msg/basic_types.hpp"
3333
#include "test_msgs/message_fixtures.hpp"
3434

35+
#include "qos.hpp"
36+
3537
#include "rosbag2_play_test_fixture.hpp"
38+
#include "rosbag2_transport_test_fixture.hpp"
3639

3740
using namespace ::testing; // NOLINT
3841
using namespace rosbag2_transport; // NOLINT
@@ -205,35 +208,59 @@ class RosBag2PlayQosOverrideTestFixture : public RosBag2PlayTestFixture
205208
RosBag2PlayQosOverrideTestFixture()
206209
: RosBag2PlayTestFixture()
207210
{
208-
// Because this test only cares about compatibility (receiving any messages at all)
211+
}
212+
213+
void initialize(const std::vector<rosbag2_transport::Rosbag2QoS> & offered_qos)
214+
{
215+
// Because these tests only cares about compatibility (receiving any messages at all)
209216
// We publish one more message than we expect to receive, to avoid caring about
210217
// shutdown edge behaviors that are not explicitly being tested here.
211218
const size_t num_msgs_to_publish = num_msgs_to_wait_for_ + 1;
212-
topic_timestamps_ms_.reserve(num_msgs_to_publish);
219+
messages_.reserve(num_msgs_to_publish);
213220
for (size_t i = 0; i < num_msgs_to_publish; i++) {
214-
topic_timestamps_ms_.push_back(start_time_ms_ + message_spacing_ms_ * i);
221+
const auto timestamp = start_time_ms_ + message_spacing_ms_ * i;
222+
messages_.push_back(serialize_test_message(topic_name_, timestamp, basic_msg_));
215223
}
216224

217-
messages_.reserve(topic_timestamps_ms_.size());
218-
for (const auto topic_timestamp : topic_timestamps_ms_) {
219-
messages_.push_back(serialize_test_message(topic_name_, topic_timestamp, basic_msg_));
225+
std::string serialized_offered_qos = "";
226+
if (!offered_qos.empty()) {
227+
YAML::Node offered_qos_yaml;
228+
for (const auto & profile : offered_qos) {
229+
offered_qos_yaml.push_back(profile);
230+
}
231+
serialized_offered_qos = YAML::Dump(offered_qos_yaml);
220232
}
233+
topic_types_.push_back(
234+
{topic_name_, msg_type_, "" /*serialization_format*/, serialized_offered_qos});
221235

222236
auto prepared_mock_reader = std::make_unique<MockSequentialReader>();
223237
prepared_mock_reader->prepare(messages_, topic_types_);
224238
reader_ = std::make_unique<rosbag2_cpp::Reader>(std::move(prepared_mock_reader));
225239
}
226240

241+
template<typename Duration>
242+
void play_and_wait(Duration timeout, bool expect_timeout = false)
243+
{
244+
auto await_received_messages = sub_->spin_subscriptions();
245+
Rosbag2Transport transport(reader_, writer_, info_);
246+
transport.play(storage_options_, play_options_);
247+
const auto result = await_received_messages.wait_for(timeout);
248+
if (expect_timeout) {
249+
ASSERT_EQ(result, std::future_status::timeout);
250+
} else {
251+
ASSERT_NE(result, std::future_status::timeout);
252+
}
253+
transport.shutdown();
254+
}
255+
227256
const std::string topic_name_{"/test_topic"};
228257
const std::string msg_type_{"test_msgs/BasicTypes"};
229-
const size_t num_msgs_to_wait_for_{3};
258+
// Receiving _any_ messages means we've confirmed compatibility in these tests
259+
const size_t num_msgs_to_wait_for_{1};
230260
test_msgs::msg::BasicTypes::SharedPtr basic_msg_{get_messages_basic_types()[0]};
231-
const std::vector<rosbag2_storage::TopicMetadata> topic_types_{
232-
{topic_name_, msg_type_, "" /*serialization_format*/, "" /*offered_qos_profiles*/}
233-
};
261+
std::vector<rosbag2_storage::TopicMetadata> topic_types_{};
234262
const int64_t start_time_ms_{500};
235263
const int64_t message_spacing_ms_{200};
236-
std::vector<int64_t> topic_timestamps_ms_{};
237264
std::vector<std::shared_ptr<rosbag2_storage::SerializedBagMessage>> messages_;
238265
};
239266

@@ -246,27 +273,19 @@ TEST_F(RosBag2PlayQosOverrideTestFixture, topic_qos_profiles_overridden)
246273
// to receive messages.
247274
const auto qos_request = rclcpp::QoS{rclcpp::KeepAll()}.reliable().transient_local();
248275
const auto qos_playback_override = rclcpp::QoS{rclcpp::KeepAll()}.reliable().transient_local();
249-
250276
const auto topic_qos_profile_overrides = std::unordered_map<std::string, rclcpp::QoS>{
251277
std::pair<std::string, rclcpp::QoS>{topic_name_, qos_playback_override},
252278
};
279+
// This should normally take less than 1s - just making it shorter than 60s default
280+
const auto timeout = 5s;
281+
282+
initialize({});
253283

254284
sub_->add_subscription<test_msgs::msg::BasicTypes>(
255285
topic_name_, num_msgs_to_wait_for_, qos_request);
256-
auto await_received_messages = sub_->spin_subscriptions();
257286
play_options_.topic_qos_profile_overrides = topic_qos_profile_overrides;
258287

259-
Rosbag2Transport rosbag2_transport{reader_, writer_, info_};
260-
rosbag2_transport.play(storage_options_, play_options_);
261-
262-
// This should normally take less than 1s - just making it shorter than 60s default
263-
const auto future_result = await_received_messages.wait_for(5s);
264-
EXPECT_NE(future_result, std::future_status::timeout);
265-
rosbag2_transport.shutdown();
266-
267-
const auto received_messages =
268-
sub_->get_received_messages<test_msgs::msg::BasicTypes>(topic_name_);
269-
EXPECT_FALSE(received_messages.empty());
288+
play_and_wait(timeout);
270289
}
271290

272291
TEST_F(RosBag2PlayQosOverrideTestFixture, topic_qos_profiles_overridden_incompatible)
@@ -277,25 +296,40 @@ TEST_F(RosBag2PlayQosOverrideTestFixture, topic_qos_profiles_overridden_incompat
277296
// which should not be a compatible offer and therefore we should receive no messages.
278297
const auto qos_request = rclcpp::QoS{rclcpp::KeepAll()}.reliable();
279298
const auto qos_playback_override = rclcpp::QoS{rclcpp::KeepAll()}.best_effort();
280-
281299
const auto topic_qos_profile_overrides = std::unordered_map<std::string, rclcpp::QoS>{
282300
std::pair<std::string, rclcpp::QoS>{topic_name_, qos_playback_override},
283301
};
284-
play_options_.topic_qos_profile_overrides = topic_qos_profile_overrides;
302+
// If any messages were going to come in, it should happen in under 1s even in slow scenarios
303+
const auto timeout = 3s;
304+
305+
initialize({});
285306

286307
sub_->add_subscription<test_msgs::msg::BasicTypes>(
287308
topic_name_, num_msgs_to_wait_for_, qos_request);
288-
auto await_received_messages = sub_->spin_subscriptions();
289-
290-
Rosbag2Transport rosbag2_transport{reader_, writer_, info_};
291-
rosbag2_transport.play(storage_options_, play_options_);
309+
play_options_.topic_qos_profile_overrides = topic_qos_profile_overrides;
292310

293-
using namespace std::chrono_literals;
294-
const auto future_result = await_received_messages.wait_for(3s);
295-
EXPECT_EQ(future_result, std::future_status::timeout);
311+
play_and_wait(timeout, true /* expect timeout */);
296312

297-
rosbag2_transport.shutdown();
298313
const auto received_messages =
299314
sub_->get_received_messages<test_msgs::msg::BasicTypes>(topic_name_);
300315
EXPECT_EQ(received_messages.size(), 0u);
301316
}
317+
318+
TEST_F(RosBag2PlayQosOverrideTestFixture, playback_uses_recorded_profiles)
319+
{
320+
// In this test, we subscribe requesting DURABILITY_TRANSIENT_LOCAL.
321+
// The bag metadata has this recorded for the original Publisher,
322+
// so playback's offer should be compatible (whereas the default offer would not be)
323+
const size_t arbitrary_finite_history{5};
324+
const auto transient_local_profile = Rosbag2QoS{
325+
rclcpp::QoS{arbitrary_finite_history}.transient_local()};
326+
// This should normally take less than 1s - just making it shorter than 60s default
327+
const auto timeout = 5s;
328+
329+
initialize({transient_local_profile});
330+
331+
sub_->add_subscription<test_msgs::msg::BasicTypes>(
332+
topic_name_, num_msgs_to_wait_for_, transient_local_profile);
333+
334+
play_and_wait(timeout);
335+
}

0 commit comments

Comments
 (0)