@@ -897,11 +897,11 @@ TYPED_TEST(TestExecutors, deterministic_execution_order_ub)
897897{
898898 using ExecutorType = TypeParam;
899899
900- // number of waitable to test
901- constexpr size_t number_of_waitables = 10 ;
902- std::vector<size_t > forward (number_of_waitables );
900+ // number of each entity to test
901+ constexpr size_t number_of_entities = 20 ;
902+ std::vector<size_t > forward (number_of_entities );
903903 std::iota (std::begin (forward), std::end (forward), 0 );
904- std::vector<size_t > reverse (number_of_waitables );
904+ std::vector<size_t > reverse (number_of_entities );
905905 std::reverse_copy (std::begin (forward), std::end (forward), std::begin (reverse));
906906
907907 struct test_case
@@ -948,42 +948,117 @@ TYPED_TEST(TestExecutors, deterministic_execution_order_ub)
948948 rclcpp::CallbackGroupType::MutuallyExclusive,
949949 automatically_add_to_executor_with_node);
950950
951- auto waitable_interfaces = this ->node ->get_node_waitables_interface ();
951+ // perform each of the test cases for waitables
952+ {
953+ auto waitable_interfaces = this ->node ->get_node_waitables_interface ();
952954
953- std::vector<std::shared_ptr<TestWaitable>> waitables;
954- for (size_t i = 0 ; i < number_of_waitables ; ++i) {
955- auto my_waitable = std::make_shared<TestWaitable>();
956- waitable_interfaces->add_waitable (my_waitable, isolated_callback_group);
957- waitables.push_back (my_waitable);
958- }
955+ std::vector<std::shared_ptr<TestWaitable>> waitables;
956+ for (size_t i = 0 ; i < number_of_entities ; ++i) {
957+ auto my_waitable = std::make_shared<TestWaitable>();
958+ waitable_interfaces->add_waitable (my_waitable, isolated_callback_group);
959+ waitables.push_back (my_waitable);
960+ }
959961
960- // perform each of the test cases
961- for (const auto & test_case_pair : test_cases) {
962- const std::string & test_case_name = test_case_pair.first ;
963- const auto & test_case = test_case_pair.second ;
962+ for (const auto & test_case_pair : test_cases) {
963+ const std::string & test_case_name = test_case_pair.first ;
964+ const auto & test_case = test_case_pair.second ;
964965
965- ExecutorType executor;
966- executor.add_callback_group (isolated_callback_group, this ->node ->get_node_base_interface ());
966+ ExecutorType executor;
967+ executor.add_callback_group (isolated_callback_group, this ->node ->get_node_base_interface ());
967968
968- RCPPUTILS_SCOPE_EXIT ({
969- for (size_t i = 0 ; i < number_of_waitables; ++i) {
970- waitables[i]->set_on_execute_callback (nullptr );
969+ RCPPUTILS_SCOPE_EXIT ({
970+ for (size_t i = 0 ; i < number_of_entities; ++i) {
971+ waitables[i]->set_on_execute_callback (nullptr );
972+ }
973+ });
974+
975+ std::vector<size_t > actual_order;
976+ for (size_t i : test_case.call_order ) {
977+ waitables[i]->set_on_execute_callback ([&actual_order, i]() {actual_order.push_back (i);});
978+ waitables[i]->trigger ();
971979 }
972- });
973980
974- std::vector<size_t > actual_order;
975- for (size_t i : test_case.call_order ) {
976- waitables[i]->set_on_execute_callback ([&actual_order, i]() {actual_order.push_back (i);});
977- waitables[i]->trigger ();
978- }
981+ while (actual_order.size () < number_of_entities && rclcpp::ok ()) {
982+ executor.spin_once (10s); // large timeout because it should normally exit quickly
983+ }
979984
980- while (actual_order.size () < number_of_waitables) {
981- executor.spin_once (10s); // large timeout because it should normally exit quickly
985+ EXPECT_EQ (actual_order, test_case.expected_execution_order )
986+ << " callback call order in test case '" << test_case_name << " ' different than expected, "
987+ << " this may be a false positive, see test description" ;
982988 }
989+ }
990+
991+ const std::string test_topic_name = " /deterministic_execution_order_ub" ;
992+ std::map<rclcpp::SubscriptionBase *, std::function<void ()>> on_sub_data_callbacks;
993+ std::vector<rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr> subscriptions;
994+ rclcpp::SubscriptionOptions so;
995+ so.callback_group = isolated_callback_group;
996+ for (size_t i = 0 ; i < number_of_entities; ++i) {
997+ size_t next_sub_index = subscriptions.size ();
998+ auto sub = this ->node ->template create_subscription <test_msgs::msg::Empty>(
999+ test_topic_name,
1000+ 10 ,
1001+ [&on_sub_data_callbacks, &subscriptions, next_sub_index](const test_msgs::msg::Empty &) {
1002+ auto this_sub_pointer = subscriptions[next_sub_index].get ();
1003+ auto callback_for_sub_it = on_sub_data_callbacks.find (this_sub_pointer);
1004+ ASSERT_NE (callback_for_sub_it, on_sub_data_callbacks.end ());
1005+ auto on_sub_data_callback = callback_for_sub_it->second ;
1006+ if (on_sub_data_callback) {
1007+ on_sub_data_callback ();
1008+ }
1009+ },
1010+ so);
1011+ subscriptions.push_back (sub);
1012+ }
1013+
1014+ // perform each of the test cases for subscriptions
1015+ if (
1016+ // TODO(wjwwood): the order of subscriptions in the EventsExecutor does not
1017+ // follow call order or the insertion order, though it seems to be
1018+ // consistently the same order (from what I can tell in testing).
1019+ // I don't know why that is, but it means that this part of the test
1020+ // will not pass for the EventsExecutor, so skip it.
1021+ !std::is_same<ExecutorType, rclcpp::experimental::executors::EventsExecutor>())
1022+ {
1023+ for (const auto & test_case_pair : test_cases) {
1024+ const std::string & test_case_name = test_case_pair.first ;
1025+ const auto & test_case = test_case_pair.second ;
1026+
1027+ ExecutorType executor;
1028+ executor.add_callback_group (isolated_callback_group, this ->node ->get_node_base_interface ());
1029+
1030+ RCPPUTILS_SCOPE_EXIT ({
1031+ for (auto & sub_pair : on_sub_data_callbacks) {
1032+ sub_pair.second = nullptr ;
1033+ }
1034+ });
9831035
984- EXPECT_EQ (actual_order, test_case.expected_execution_order )
985- << " callback call order in test case '" << test_case_name << " ' different than expected, "
986- << " this may be a false positive, see test description" ;
1036+ std::vector<size_t > actual_order;
1037+ for (size_t i = 0 ; i < number_of_entities; ++i) {
1038+ auto sub = subscriptions[i];
1039+ on_sub_data_callbacks[sub.get ()] = [&actual_order, i]() {
1040+ actual_order.push_back (i);
1041+ };
1042+ }
1043+
1044+ // create publisher and wait for all of the subscriptions to match
1045+ auto pub = this ->node ->template create_publisher <test_msgs::msg::Empty>(test_topic_name, 10 );
1046+ size_t number_of_matches = pub->get_subscription_count ();
1047+ while (number_of_matches < number_of_entities && rclcpp::ok ()) {
1048+ executor.spin_once (10s); // large timeout because it should normally exit quickly
1049+ number_of_matches = pub->get_subscription_count ();
1050+ }
1051+
1052+ // publish once and wait for all subscriptions to be handled
1053+ pub->publish (test_msgs::msg::Empty ());
1054+ while (actual_order.size () < number_of_entities && rclcpp::ok ()) {
1055+ executor.spin_once (10s); // large timeout because it should normally exit quickly
1056+ }
1057+
1058+ EXPECT_EQ (actual_order, test_case.expected_execution_order )
1059+ << " callback call order in test case '" << test_case_name << " ' different than expected, "
1060+ << " this may be a false positive, see test description" ;
1061+ }
9871062 }
9881063}
9891064
0 commit comments