Skip to content

Commit 735901d

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

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
@@ -292,6 +292,31 @@ void RecorderImpl::record()
292292
subscriptions_.clear();
293293
event_notifier_->reset_total_num_messages_lost_in_transport();
294294
event_notifier_->reset_total_num_messages_lost_in_recorder();
295+
296+
// Check if storage_options.uri already exists and try to add '(n)' postfix
297+
namespace fs = std::filesystem;
298+
fs::path storage_path(storage_options_.uri);
299+
if (fs::is_directory(storage_path)) {
300+
RCLCPP_WARN_STREAM(node->get_logger(),
301+
"Bag directory '" << storage_path.c_str() << "' already exists.");
302+
for (size_t i = 1U; i < std::numeric_limits<size_t>::max(); i++) {
303+
fs::path new_path = storage_path;
304+
new_path += "(" + std::to_string(i) + ")";
305+
if (!fs::exists(new_path)) {
306+
RCLCPP_WARN_STREAM(node->get_logger(),
307+
"Changing bag directory to '" << new_path.c_str() << "'.");
308+
storage_options_.uri = new_path.generic_string();
309+
storage_path = new_path;
310+
break;
311+
}
312+
}
313+
}
314+
if (fs::is_directory(storage_path)) {
315+
throw std::runtime_error{
316+
"Failed to derive non-existent directory for the new Rosbag2 recording. "
317+
"Please specify non existent uri explicitly."};
318+
}
319+
295320
writer_->open(
296321
storage_options_,
297322
{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,16 +14,20 @@
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

24+
#include "mock_recorder.hpp"
2325
#include "rclcpp/rclcpp.hpp"
26+
#include "rcpputils/scope_exit.hpp"
2427

2528
#include "rosbag2_test_common/publication_manager.hpp"
2629
#include "rosbag2_test_common/wait_for.hpp"
30+
#include "rosbag2_test_common/temporary_directory_fixture.hpp"
2731

2832
#include "rosbag2_transport/recorder.hpp"
2933

@@ -33,6 +37,11 @@
3337

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

3746
TEST_F(RecordIntegrationTestFixture, published_messages_from_multiple_topics_are_recorded)
3847
{
@@ -125,6 +134,33 @@ TEST_F(RecordIntegrationTestFixture, published_messages_from_multiple_topics_are
125134
}
126135
}
127136

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

0 commit comments

Comments
 (0)