blob: 8d0f55297848924700f1a9e033af569ae6e70a82 [file] [log] [blame]
Parker Schuhe4a70d62017-12-27 20:10:20 -08001#include "aos/events/shm-event-loop.h"
2
3#include "aos/events/event-loop_param_test.h"
4#include "aos/testing/test_shm.h"
5#include "gtest/gtest.h"
6
7namespace aos {
8namespace testing {
9namespace {
Austin Schuh3115a202019-05-27 21:02:14 -070010namespace chrono = ::std::chrono;
Parker Schuhe4a70d62017-12-27 20:10:20 -080011
12class ShmEventLoopTestFactory : public EventLoopTestFactory {
13 public:
Austin Schuh44019f92019-05-19 19:58:27 -070014 ::std::unique_ptr<EventLoop> Make() override {
15 return ::std::unique_ptr<EventLoop>(new ShmEventLoop());
Parker Schuhe4a70d62017-12-27 20:10:20 -080016 }
17
Austin Schuh44019f92019-05-19 19:58:27 -070018 ::std::unique_ptr<EventLoop> MakePrimary() override {
19 ::std::unique_ptr<ShmEventLoop> loop =
20 ::std::unique_ptr<ShmEventLoop>(new ShmEventLoop());
21 primary_event_loop_ = loop.get();
22 return ::std::move(loop);
23 }
24
25 void Run() override { CHECK_NOTNULL(primary_event_loop_)->Run(); }
26
Austin Schuh52d325c2019-06-23 18:59:06 -070027 void SleepFor(::std::chrono::nanoseconds duration) override {
28 ::std::this_thread::sleep_for(duration);
29 }
30
Austin Schuh44019f92019-05-19 19:58:27 -070031 private:
Parker Schuhe4a70d62017-12-27 20:10:20 -080032 ::aos::testing::TestSharedMemory my_shm_;
Austin Schuh44019f92019-05-19 19:58:27 -070033
34 ::aos::ShmEventLoop *primary_event_loop_;
Parker Schuhe4a70d62017-12-27 20:10:20 -080035};
36
37INSTANTIATE_TEST_CASE_P(ShmEventLoopTest, AbstractEventLoopTest,
38 ::testing::Values([]() {
39 return new ShmEventLoopTestFactory();
40 }));
41
Austin Schuh6b6dfa52019-06-12 20:16:20 -070042INSTANTIATE_TEST_CASE_P(ShmEventLoopDeathTest, AbstractEventLoopDeathTest,
43 ::testing::Values([]() {
44 return new ShmEventLoopTestFactory();
45 }));
46
James Kuszmaulc79768b2019-02-18 15:08:44 -080047struct TestMessage : public ::aos::Message {
48 enum { kQueueLength = 100, kHash = 0x696c0cdc };
49 int msg_value;
50
51 void Zero() { msg_value = 0; }
52 static size_t Size() { return 1 + ::aos::Message::Size(); }
53 size_t Print(char *buffer, size_t length) const;
54 TestMessage() { Zero(); }
55};
56
Parker Schuhe4a70d62017-12-27 20:10:20 -080057} // namespace
James Kuszmaulc79768b2019-02-18 15:08:44 -080058
Austin Schuh3115a202019-05-27 21:02:14 -070059bool IsRealtime() {
60 int scheduler;
61 if ((scheduler = sched_getscheduler(0)) == -1) {
62 PLOG(FATAL, "sched_getscheduler(0) failed\n");
James Kuszmaulc79768b2019-02-18 15:08:44 -080063 }
Austin Schuh3115a202019-05-27 21:02:14 -070064 LOG(INFO, "scheduler is %d\n", scheduler);
65 return scheduler == SCHED_FIFO || scheduler == SCHED_RR;
66}
James Kuszmaulc79768b2019-02-18 15:08:44 -080067
Austin Schuh3115a202019-05-27 21:02:14 -070068// Tests that every handler type is realtime and runs. There are threads
69// involved and it's easy to miss one.
70TEST(ShmEventLoopTest, AllHandlersAreRealtime) {
71 ShmEventLoopTestFactory factory;
72 auto loop = factory.MakePrimary();
73 auto loop2 = factory.Make();
74
75 loop->SetRuntimeRealtimePriority(1);
76
77 auto sender = loop2->MakeSender<TestMessage>("/test");
78
79 bool did_onrun = false;
80 bool did_timer = false;
81 bool did_watcher = false;
82
83 auto timer = loop->AddTimer([&did_timer, &loop]() {
84 EXPECT_TRUE(IsRealtime());
85 did_timer = true;
86 loop->Exit();
87 });
88
89 loop->MakeWatcher("/test", [&did_watcher](const TestMessage &) {
90 EXPECT_TRUE(IsRealtime());
91 did_watcher = true;
92 });
93
94 loop->OnRun([&loop, &did_onrun, &sender, timer]() {
95 EXPECT_TRUE(IsRealtime());
96 did_onrun = true;
97 timer->Setup(loop->monotonic_now() + chrono::milliseconds(100));
James Kuszmaulc79768b2019-02-18 15:08:44 -080098 auto msg = sender.MakeMessage();
99 msg->msg_value = 200;
Austin Schuh3115a202019-05-27 21:02:14 -0700100 msg.Send();
101 });
James Kuszmaulc79768b2019-02-18 15:08:44 -0800102
Austin Schuh3115a202019-05-27 21:02:14 -0700103 factory.Run();
James Kuszmaulc79768b2019-02-18 15:08:44 -0800104
Austin Schuh3115a202019-05-27 21:02:14 -0700105 EXPECT_TRUE(did_onrun);
106 EXPECT_TRUE(did_timer);
107 EXPECT_TRUE(did_watcher);
James Kuszmaulc79768b2019-02-18 15:08:44 -0800108}
Austin Schuh52d325c2019-06-23 18:59:06 -0700109
110// Tests that missing a deadline inside the function still results in PhasedLoop
111// running at the right offset.
112TEST(ShmEventLoopTest, DelayedPhasedLoop) {
113 ShmEventLoopTestFactory factory;
114 auto loop1 = factory.MakePrimary();
115
116 ::std::vector<::aos::monotonic_clock::time_point> times;
117
118 constexpr chrono::milliseconds kOffset = chrono::milliseconds(400);
119
120 loop1->AddPhasedLoop(
121 [&times, &loop1, &kOffset](int count) {
122 const ::aos::monotonic_clock::time_point monotonic_now =
123 loop1->monotonic_now();
124
125 // Compute our offset.
126 const ::aos::monotonic_clock::duration remainder =
127 monotonic_now.time_since_epoch() -
128 chrono::duration_cast<chrono::seconds>(
129 monotonic_now.time_since_epoch());
130
131 // Make sure we we are called near where we should be even when we
132 // delay.
133 constexpr chrono::milliseconds kEpsilon(200);
134 EXPECT_LT(remainder, kOffset + kEpsilon);
135 EXPECT_GT(remainder, kOffset - kEpsilon);
136
137 // Confirm that we see the missed count when we sleep.
138 if (times.size() == 0) {
139 EXPECT_EQ(count, 1);
140 } else {
141 EXPECT_EQ(count, 3);
142 }
143
144 times.push_back(loop1->monotonic_now());
145 if (times.size() == 2) {
146 loop1->Exit();
147 }
148
149 // Now, add a large delay. This should push us up to 3 cycles.
150 ::std::this_thread::sleep_for(chrono::milliseconds(2500));
151 },
152 chrono::seconds(1), kOffset);
153
154 factory.Run();
155
156 EXPECT_EQ(times.size(), 2u);
157}
158
Parker Schuhe4a70d62017-12-27 20:10:20 -0800159} // namespace testing
160} // namespace aos