-
Notifications
You must be signed in to change notification settings - Fork 547
Fix topic statistics source collision for multiple subscriptions #3171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: rolling
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -81,8 +81,10 @@ class TestSubscriptionTopicStatistics : public SubscriptionTopicStatistics | |
| public: | ||
| TestSubscriptionTopicStatistics( | ||
| const std::string & node_name, | ||
| const std::string & topic_name, | ||
| rclcpp::Publisher<statistics_msgs::msg::MetricsMessage>::SharedPtr publisher) | ||
| : SubscriptionTopicStatistics(node_name, std::move(publisher)) | ||
| : SubscriptionTopicStatistics<CallbackMessageT>( | ||
| node_name, topic_name, publisher) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we build this PR successfully and all test pass via colcon test? it looks like we can't apply template arguments to a non-template class...
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for taking a look. You're right regarding the collision. My change only differentiates subscriptions using the unqualified node name and topic name, so nodes with the same name in different namespaces could still collide. I overlooked that I'll take another look at how the source identifier is constructed and see whether a fully-qualified node name can be used instead. I'll also revisit the test changes and verify that the updated constructor usage builds correctly and that the affected tests pass. |
||
| { | ||
| } | ||
|
|
||
|
|
@@ -291,6 +293,7 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_manual_construction) | |
| // Construct a separate instance | ||
| auto sub_topic_stats = std::make_unique<TestSubscriptionTopicStatistics>( | ||
| empty_subscriber->get_name(), | ||
| "/test_topic", | ||
| topic_stats_publisher); | ||
|
|
||
| // Expect no data has been collected / no samples received | ||
|
|
@@ -478,3 +481,81 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_stats_with_intra_process_com | |
| EXPECT_EQ(kNumExpectedMessageAgeMessages, message_age_count); | ||
| EXPECT_EQ(kNumExpectedMessagePeriodMessages, message_period_count); | ||
| } | ||
| /** | ||
| * Test that multiple subscriptions on the same node produce differentiated | ||
| * measurement_source_name values in their statistics messages. | ||
| * Regression test for #2756. | ||
| */ | ||
| TEST_F(TestSubscriptionTopicStatisticsFixture, test_multiple_subscriptions_differentiated) | ||
| { | ||
| constexpr const char kTopicA[]{"/test_topic_a"}; | ||
| constexpr const char kTopicB[]{"/test_topic_b"}; | ||
| constexpr const uint64_t kNumStatsMessages{4}; | ||
|
|
||
| auto pub_a = std::make_shared<EmptyPublisher>("pub_node_a", kTopicA); | ||
| auto pub_b = std::make_shared<EmptyPublisher>("pub_node_b", kTopicB); | ||
|
|
||
| auto multi_sub_node = std::make_shared<rclcpp::Node>("multi_sub_node"); | ||
|
|
||
| auto options = rclcpp::SubscriptionOptions(); | ||
| options.topic_stats_options.state = rclcpp::TopicStatisticsState::Enable; | ||
| options.topic_stats_options.publish_period = defaultStatisticsPublishPeriod; | ||
|
|
||
| auto cb = [](Empty::UniquePtr msg) {(void) msg;}; | ||
|
|
||
| auto sub_a = multi_sub_node->create_subscription<Empty>( | ||
| kTopicA, | ||
| rclcpp::QoS(rclcpp::KeepAll()), | ||
| std::function<void(Empty::UniquePtr)>(cb), | ||
| options); | ||
|
|
||
| auto sub_b = multi_sub_node->create_subscription<Empty>( | ||
| kTopicB, | ||
| rclcpp::QoS(rclcpp::KeepAll()), | ||
| std::function<void(Empty::UniquePtr)>(cb), | ||
| options); | ||
|
|
||
| auto stats_listener = | ||
| std::make_shared<rclcpp::topic_statistics::MetricsMessageSubscriber>( | ||
| "multi_sub_stats_listener", | ||
| "/statistics", | ||
| kNumStatsMessages); | ||
|
|
||
| rclcpp::executors::SingleThreadedExecutor ex; | ||
| ex.add_node(pub_a); | ||
| ex.add_node(pub_b); | ||
| ex.add_node(multi_sub_node); | ||
| ex.add_node(stats_listener); | ||
|
|
||
| ex.spin_until_future_complete(stats_listener->GetFuture(), kTestTimeout); | ||
|
|
||
| const auto received_messages = stats_listener->GetReceivedMessages(); | ||
| ASSERT_GE(received_messages.size(), kNumStatsMessages); | ||
|
|
||
| std::set<std::string> source_names; | ||
| for (const auto & msg : received_messages) { | ||
| source_names.insert(msg.measurement_source_name); | ||
| } | ||
|
|
||
| bool found_topic_a = false; | ||
| bool found_topic_b = false; | ||
|
|
||
| for (const auto & name : source_names) { | ||
| if (name.find("test_topic_a") != std::string::npos) { | ||
| found_topic_a = true; | ||
| } | ||
|
|
||
| if (name.find("test_topic_b") != std::string::npos) { | ||
| found_topic_b = true; | ||
| } | ||
| } | ||
|
|
||
| EXPECT_TRUE(found_topic_a) | ||
| << "No stats found containing topic_a in source name"; | ||
|
|
||
| EXPECT_TRUE(found_topic_b) | ||
| << "No stats found containing topic_b in source name"; | ||
|
|
||
| EXPECT_GT(source_names.size(), 1u) | ||
| << "Both subscriptions produced the same measurement_source_name"; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The member now has a different meaning, thus the name is not matching any more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Since the identifier now includes both the node and topic information, 'node_name_' no longer accurately described what the member stores. I've renamed it to 'measurement_source_name_' and pushed the update.