Skip to content

Commit 81ef9fd

Browse files
committed
Bugfix: C++ Recorder fails on stop()->record() due to reusing bag name
Signed-off-by: Michael Orlov <[email protected]>
1 parent a1b4bc5 commit 81ef9fd

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

rosbag2_transport/src/rosbag2_transport/recorder.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,31 @@ void RecorderImpl::record()
383383
subscriptions_.clear();
384384
event_notifier_->reset_total_num_messages_lost_in_transport();
385385
event_notifier_->reset_total_num_messages_lost_in_recorder();
386+
387+
// Check if storage_options.uri already exists and try to add '(n)' postfix
388+
namespace fs = std::filesystem;
389+
fs::path storage_path(storage_options_.uri);
390+
if (fs::is_directory(storage_path)) {
391+
RCLCPP_WARN_STREAM(node->get_logger(),
392+
"Bag directory '" << storage_path.c_str() << "' already exists.");
393+
for (size_t i = 1U; i < std::numeric_limits<size_t>::max(); i++) {
394+
fs::path new_path = storage_path;
395+
new_path += "(" + std::to_string(i) + ")";
396+
if (!fs::exists(new_path)) {
397+
RCLCPP_WARN_STREAM(node->get_logger(),
398+
"Changing bag directory to '" << new_path.c_str() << "'.");
399+
storage_options_.uri = new_path.generic_string();
400+
storage_path = new_path;
401+
break;
402+
}
403+
}
404+
}
405+
if (fs::is_directory(storage_path)) {
406+
throw std::runtime_error{
407+
"Failed to derive non-existent directory for the new Rosbag2 recording. "
408+
"Please specify non existent uri explicitly."};
409+
}
410+
386411
writer_->open(
387412
storage_options_,
388413
{record_options_.input_serialization_format, record_options_.output_serialization_format});

rosbag2_transport/test/rosbag2_transport/test_record.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,21 @@
1414

1515
#include <gmock/gmock.h>
1616

17+
#include <filesystem>
1718
#include <memory>
1819
#include <string>
1920
#include <unordered_map>
2021
#include <utility>
2122
#include <vector>
2223
#include <rosbag2_storage/ros_helper.hpp>
2324

25+
#include "mock_recorder.hpp"
2426
#include "rclcpp/rclcpp.hpp"
27+
#include "rcpputils/scope_exit.hpp"
2528

2629
#include "rosbag2_test_common/publication_manager.hpp"
2730
#include "rosbag2_test_common/wait_for.hpp"
31+
#include "rosbag2_test_common/temporary_directory_fixture.hpp"
2832

2933
#include "rosbag2_transport/recorder.hpp"
3034

@@ -34,6 +38,11 @@
3438

3539
#include "rosbag2_storage/qos.hpp"
3640
#include "record_integration_fixture.hpp"
41+
#include "rosbag2_transport/reader_writer_factory.hpp"
42+
43+
using namespace ::testing; // NOLINT
44+
using rosbag2_test_common::TemporaryDirectoryFixture;
45+
namespace fs = std::filesystem;
3746

3847
TEST_F(RecordIntegrationTestFixture, published_messages_from_multiple_topics_are_recorded)
3948
{
@@ -126,6 +135,33 @@ TEST_F(RecordIntegrationTestFixture, published_messages_from_multiple_topics_are
126135
}
127136
}
128137

138+
TEST_F(TemporaryDirectoryFixture, can_record_again_after_stop_with_real_storage) {
139+
rclcpp::init(0, nullptr);
140+
auto cleanup_process_handle = rcpputils::make_scope_exit([&]() {rclcpp::shutdown();});
141+
std::string test_topic = "/can_record_again_after_stop_topic";
142+
rosbag2_storage::StorageOptions storage_options{};
143+
storage_options.uri = (fs::path(temporary_dir_path_) / "start_stop_again").generic_string();
144+
145+
rosbag2_transport::RecordOptions record_options{};
146+
147+
auto writer = rosbag2_transport::ReaderWriterFactory::make_writer(record_options);
148+
{
149+
auto recorder = std::make_shared<MockRecorder>(
150+
std::move(writer), storage_options, record_options);
151+
152+
EXPECT_NO_THROW(recorder->record());
153+
fs::path storage_path(storage_options.uri);
154+
EXPECT_TRUE(fs::is_directory(storage_path));
155+
156+
EXPECT_NO_THROW(recorder->stop());
157+
EXPECT_NO_THROW(recorder->record());
158+
storage_path = recorder->get_storage_options().uri;
159+
EXPECT_TRUE(fs::is_directory(storage_path));
160+
std::string expected_path_str = storage_options.uri + "(1)";
161+
EXPECT_EQ(storage_path.generic_string(), expected_path_str);
162+
}
163+
}
164+
129165
TEST_F(RecordIntegrationTestFixture, can_record_again_after_stop)
130166
{
131167
GTEST_SKIP() << "Skipping test `can_record_again_after_stop` in rosbag2_transport, until "

0 commit comments

Comments
 (0)