Skip to content

Commit 666e9d5

Browse files
committed
use sim clock for tests, pub clock at .25 realtime rate.
Signed-off-by: Matt Condino <mwcondino@gmail.com>
1 parent 2fb28b9 commit 666e9d5

File tree

1 file changed

+130
-32
lines changed

1 file changed

+130
-32
lines changed

rclcpp/test/rclcpp/executors/test_executors.cpp

Lines changed: 130 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@
3636
#include "rclcpp/duration.hpp"
3737
#include "rclcpp/guard_condition.hpp"
3838
#include "rclcpp/rclcpp.hpp"
39+
#include "rclcpp/time_source.hpp"
3940

4041
#include "test_msgs/msg/empty.hpp"
42+
#include "rosgraph_msgs/msg/clock.hpp"
4143

4244
using namespace std::chrono_literals;
4345

@@ -881,6 +883,89 @@ class TimerNode : public rclcpp::Node
881883
int cnt2_ = 0;
882884
};
883885

886+
// Sets up a separate thread to publish /clock messages.
887+
// Clock rate relative to real clock is controlled by realtime_update_rate.
888+
// This is set conservatively slow to ensure unit tests are reliable on Windows
889+
// environments, where timing performance is subpar.
890+
//
891+
// Use `sleep_for` in tests to advance the clock. Clock should run and be published
892+
// in separate thread continuously to ensure correct behavior in node under test.
893+
class ClockPublisher : public rclcpp::Node
894+
{
895+
public:
896+
explicit ClockPublisher(float simulated_clock_step = .001f, float realtime_update_rate = 0.25f)
897+
: Node("clock_publisher"),
898+
ros_update_duration_(0, 0),
899+
realtime_clock_step_(0, 0),
900+
rostime_(0, 0)
901+
{
902+
clock_publisher_ = this->create_publisher<rosgraph_msgs::msg::Clock>("clock", 10);
903+
realtime_clock_step_ =
904+
rclcpp::Duration::from_seconds(simulated_clock_step / realtime_update_rate);
905+
ros_update_duration_ = rclcpp::Duration::from_seconds(simulated_clock_step);
906+
907+
timer_thread_ = std::thread(&ClockPublisher::RunTimer, this);
908+
}
909+
910+
~ClockPublisher()
911+
{
912+
running_ = false;
913+
if (timer_thread_.joinable()) {
914+
timer_thread_.join();
915+
}
916+
}
917+
918+
void sleep_for(rclcpp::Duration duration)
919+
{
920+
rclcpp::Time start_time(0, 0, RCL_ROS_TIME);
921+
{
922+
const std::lock_guard<std::mutex> lock(mutex_);
923+
start_time = rostime_;
924+
}
925+
rclcpp::Time current_time = start_time;
926+
927+
while (true) {
928+
{
929+
const std::lock_guard<std::mutex> lock(mutex_);
930+
current_time = rostime_;
931+
}
932+
if ((current_time - start_time) >= duration) {
933+
return;
934+
}
935+
std::this_thread::sleep_for(realtime_clock_step_.to_chrono<std::chrono::milliseconds>());
936+
rostime_ += ros_update_duration_;
937+
}
938+
}
939+
940+
private:
941+
void RunTimer()
942+
{
943+
while (running_) {
944+
PublishClock();
945+
std::this_thread::sleep_for(realtime_clock_step_.to_chrono<std::chrono::milliseconds>());
946+
}
947+
}
948+
949+
void PublishClock()
950+
{
951+
const std::lock_guard<std::mutex> lock(mutex_);
952+
auto message = rosgraph_msgs::msg::Clock();
953+
message.clock = rostime_;
954+
clock_publisher_->publish(message);
955+
}
956+
957+
rclcpp::Publisher<rosgraph_msgs::msg::Clock>::SharedPtr clock_publisher_;
958+
959+
rclcpp::Duration ros_update_duration_;
960+
rclcpp::Duration realtime_clock_step_;
961+
// Rostime must be guarded by a mutex, since accessible in running thread
962+
// as well as sleep_for
963+
rclcpp::Time rostime_;
964+
std::mutex mutex_;
965+
std::thread timer_thread_;
966+
std::atomic<bool> running_ = true;
967+
};
968+
884969

885970
template<typename T>
886971
class TestTimerCancelBehavior : public ::testing::Test
@@ -902,6 +987,17 @@ class TestTimerCancelBehavior : public ::testing::Test
902987
std::stringstream test_name;
903988
test_name << test_info->test_case_name() << "_" << test_info->name();
904989
node = std::make_shared<TimerNode>(test_name.str());
990+
param_client = std::make_shared<rclcpp::SyncParametersClient>(node);
991+
ASSERT_TRUE(param_client->wait_for_service(5s));
992+
993+
auto set_parameters_results = param_client->set_parameters(
994+
{rclcpp::Parameter("use_sim_time", false)});
995+
for (auto & result : set_parameters_results) {
996+
ASSERT_TRUE(result.successful);
997+
}
998+
999+
// Run standalone thread to publish clock time
1000+
sim_clock_node = std::make_shared<ClockPublisher>();
9051001

9061002
// Spin the executor in a standalone thread
9071003
executor.add_node(this->node);
@@ -922,6 +1018,8 @@ class TestTimerCancelBehavior : public ::testing::Test
9221018
}
9231019

9241020
std::shared_ptr<TimerNode> node;
1021+
std::shared_ptr<ClockPublisher> sim_clock_node;
1022+
rclcpp::SyncParametersClient::SharedPtr param_client;
9251023
std::thread standalone_thread;
9261024
T executor;
9271025
};
@@ -934,16 +1032,16 @@ TYPED_TEST(TestTimerCancelBehavior, testTimer1CancelledWithExecutorSpin) {
9341032
// executor, which is the most common usecase.
9351033

9361034
// Cancel to stop the spin after some time.
937-
std::this_thread::sleep_for(100ms);
1035+
this->sim_clock_node->sleep_for(50ms);
9381036
this->node->CancelTimer1();
939-
std::this_thread::sleep_for(300ms);
1037+
this->sim_clock_node->sleep_for(150ms);
9401038
this->executor.cancel();
9411039

9421040
int t1_runs = this->node->GetTimer1Cnt();
9431041
int t2_runs = this->node->GetTimer2Cnt();
9441042
EXPECT_NE(t1_runs, t2_runs);
9451043
// Check that t2 has significantly more calls
946-
EXPECT_LT(t1_runs + 150, t2_runs);
1044+
EXPECT_LT(t1_runs + 50, t2_runs);
9471045
}
9481046

9491047
TYPED_TEST(TestTimerCancelBehavior, testTimer2CancelledWithExecutorSpin) {
@@ -952,97 +1050,97 @@ TYPED_TEST(TestTimerCancelBehavior, testTimer2CancelledWithExecutorSpin) {
9521050
// executor, which is the most common usecase.
9531051

9541052
// Cancel to stop the spin after some time.
955-
std::this_thread::sleep_for(100ms);
1053+
this->sim_clock_node->sleep_for(50ms);
9561054
this->node->CancelTimer2();
957-
std::this_thread::sleep_for(300ms);
1055+
this->sim_clock_node->sleep_for(150ms);
9581056
this->executor.cancel();
9591057

9601058
int t1_runs = this->node->GetTimer1Cnt();
9611059
int t2_runs = this->node->GetTimer2Cnt();
9621060
EXPECT_NE(t1_runs, t2_runs);
9631061
// Check that t1 has significantly more calls
964-
EXPECT_LT(t2_runs + 150, t1_runs);
1062+
EXPECT_LT(t2_runs + 50, t1_runs);
9651063
}
9661064

9671065
TYPED_TEST(TestTimerCancelBehavior, testHeadTimerCancelThenResetBehavior) {
9681066
// Validate that cancelling timer doesn't affect operation of other timers,
9691067
// and that the cancelled timer starts executing normally once reset manually.
9701068

9711069
// Cancel to stop the spin after some time.
972-
std::this_thread::sleep_for(100ms);
1070+
this->sim_clock_node->sleep_for(50ms);
9731071
this->node->CancelTimer1();
974-
std::this_thread::sleep_for(300ms);
1072+
this->sim_clock_node->sleep_for(150ms);
9751073
int t1_runs_initial = this->node->GetTimer1Cnt();
9761074
int t2_runs_initial = this->node->GetTimer2Cnt();
9771075

9781076
// Manually reset timer 1, then sleep again
9791077
// Counts should update.
9801078
this->node->ResetTimer1();
981-
std::this_thread::sleep_for(300ms);
1079+
this->sim_clock_node->sleep_for(150ms);
9821080
int t1_runs_final = this->node->GetTimer1Cnt();
9831081
int t2_runs_final = this->node->GetTimer2Cnt();
9841082

9851083
this->executor.cancel();
9861084

9871085
// T1 should have been restarted, and execute about 15 additional times.
9881086
// Check 10 greater than initial, to account for some timing jitter.
989-
EXPECT_LT(t1_runs_initial + 150, t1_runs_final);
1087+
EXPECT_LT(t1_runs_initial + 50, t1_runs_final);
9901088

991-
EXPECT_LT(t1_runs_initial + 150, t2_runs_initial);
1089+
EXPECT_LT(t1_runs_initial + 50, t2_runs_initial);
9921090
// Check that t2 has significantly more calls, and keeps getting called.
993-
EXPECT_LT(t2_runs_initial + 150, t2_runs_final);
1091+
EXPECT_LT(t2_runs_initial + 50, t2_runs_final);
9941092
}
9951093

9961094
TYPED_TEST(TestTimerCancelBehavior, testBackTimerCancelThenResetBehavior) {
9971095
// Validate that cancelling timer doesn't affect operation of other timers,
9981096
// and that the cancelled timer starts executing normally once reset manually.
9991097

10001098
// Cancel to stop the spin after some time.
1001-
std::this_thread::sleep_for(100ms);
1099+
this->sim_clock_node->sleep_for(50ms);
10021100
this->node->CancelTimer2();
1003-
std::this_thread::sleep_for(300ms);
1101+
this->sim_clock_node->sleep_for(150ms);
10041102
int t1_runs_initial = this->node->GetTimer1Cnt();
10051103
int t2_runs_initial = this->node->GetTimer2Cnt();
10061104

10071105
// Manually reset timer 1, then sleep again
10081106
// Counts should update.
10091107
this->node->ResetTimer2();
1010-
std::this_thread::sleep_for(300ms);
1108+
this->sim_clock_node->sleep_for(150ms);
10111109
int t1_runs_final = this->node->GetTimer1Cnt();
10121110
int t2_runs_final = this->node->GetTimer2Cnt();
10131111

10141112
this->executor.cancel();
10151113

10161114
// T2 should have been restarted, and execute about 15 additional times.
10171115
// Check 10 greater than initial, to account for some timing jitter.
1018-
EXPECT_LT(t2_runs_initial + 150, t2_runs_final);
1116+
EXPECT_LT(t2_runs_initial + 50, t2_runs_final);
10191117

1020-
EXPECT_LT(t2_runs_initial + 150, t1_runs_initial);
1118+
EXPECT_LT(t2_runs_initial + 50, t1_runs_initial);
10211119
// Check that t1 has significantly more calls, and keeps getting called.
1022-
EXPECT_LT(t1_runs_initial + 150, t1_runs_final);
1120+
EXPECT_LT(t1_runs_initial + 50, t1_runs_final);
10231121
}
10241122

10251123
TYPED_TEST(TestTimerCancelBehavior, testBothTimerCancelThenResetT1Behavior) {
10261124
// Validate behavior from cancelling 2 timers, then only re-enabling one of them.
10271125
// Ensure that only the reset timer is executed.
10281126

10291127
// Cancel to stop the spin after some time.
1030-
std::this_thread::sleep_for(100ms);
1128+
this->sim_clock_node->sleep_for(50ms);
10311129
this->node->CancelTimer1();
10321130
this->node->CancelTimer2();
1033-
std::this_thread::sleep_for(300ms);
1131+
this->sim_clock_node->sleep_for(150ms);
10341132
int t1_runs_initial = this->node->GetTimer1Cnt();
10351133
int t2_runs_initial = this->node->GetTimer2Cnt();
10361134

10371135
// Manually reset timer 1, then sleep again
10381136
// Counts should update.
10391137
this->node->ResetTimer1();
1040-
std::this_thread::sleep_for(300ms);
1138+
this->sim_clock_node->sleep_for(150ms);
10411139
int t1_runs_intermediate = this->node->GetTimer1Cnt();
10421140
int t2_runs_intermediate = this->node->GetTimer2Cnt();
10431141

10441142
this->node->ResetTimer2();
1045-
std::this_thread::sleep_for(300ms);
1143+
this->sim_clock_node->sleep_for(150ms);
10461144
int t1_runs_final = this->node->GetTimer1Cnt();
10471145
int t2_runs_final = this->node->GetTimer2Cnt();
10481146

@@ -1054,34 +1152,34 @@ TYPED_TEST(TestTimerCancelBehavior, testBothTimerCancelThenResetT1Behavior) {
10541152
// Expect that T1 has up to 15 more calls than t2. Add some buffer
10551153
// to account for jitter.
10561154
EXPECT_EQ(t2_runs_initial, t2_runs_intermediate);
1057-
EXPECT_LT(t1_runs_initial + 150, t1_runs_intermediate);
1155+
EXPECT_LT(t1_runs_initial + 50, t1_runs_intermediate);
10581156

10591157
// Expect that by end of test, both are running properly again.
1060-
EXPECT_LT(t1_runs_intermediate + 150, t1_runs_final);
1061-
EXPECT_LT(t2_runs_intermediate + 150, t2_runs_final);
1158+
EXPECT_LT(t1_runs_intermediate + 50, t1_runs_final);
1159+
EXPECT_LT(t2_runs_intermediate + 50, t2_runs_final);
10621160
}
10631161

10641162
TYPED_TEST(TestTimerCancelBehavior, testBothTimerCancelThenResetT2Behavior) {
10651163
// Validate behavior from cancelling 2 timers, then only re-enabling one of them.
10661164
// Ensure that only the reset timer is executed.
10671165

10681166
// Cancel to stop the spin after some time.
1069-
std::this_thread::sleep_for(100ms);
1167+
this->sim_clock_node->sleep_for(50ms);
10701168
this->node->CancelTimer1();
10711169
this->node->CancelTimer2();
1072-
std::this_thread::sleep_for(300ms);
1170+
this->sim_clock_node->sleep_for(150ms);
10731171
int t1_runs_initial = this->node->GetTimer1Cnt();
10741172
int t2_runs_initial = this->node->GetTimer2Cnt();
10751173

10761174
// Manually reset timer 1, then sleep again
10771175
// Counts should update.
10781176
this->node->ResetTimer2();
1079-
std::this_thread::sleep_for(300ms);
1177+
this->sim_clock_node->sleep_for(150ms);
10801178
int t1_runs_intermediate = this->node->GetTimer1Cnt();
10811179
int t2_runs_intermediate = this->node->GetTimer2Cnt();
10821180

10831181
this->node->ResetTimer1();
1084-
std::this_thread::sleep_for(300ms);
1182+
this->sim_clock_node->sleep_for(150ms);
10851183
int t1_runs_final = this->node->GetTimer1Cnt();
10861184
int t2_runs_final = this->node->GetTimer2Cnt();
10871185

@@ -1093,9 +1191,9 @@ TYPED_TEST(TestTimerCancelBehavior, testBothTimerCancelThenResetT2Behavior) {
10931191
// Expect that T1 has up to 15 more calls than t2. Add some buffer
10941192
// to account for jitter.
10951193
EXPECT_EQ(t1_runs_initial, t1_runs_intermediate);
1096-
EXPECT_LT(t2_runs_initial + 150, t2_runs_intermediate);
1194+
EXPECT_LT(t2_runs_initial + 50, t2_runs_intermediate);
10971195

10981196
// Expect that by end of test, both are running properly again.
1099-
EXPECT_LT(t1_runs_intermediate + 150, t1_runs_final);
1100-
EXPECT_LT(t2_runs_intermediate + 150, t2_runs_final);
1197+
EXPECT_LT(t1_runs_intermediate + 50, t1_runs_final);
1198+
EXPECT_LT(t2_runs_intermediate + 50, t2_runs_final);
11011199
}

0 commit comments

Comments
 (0)