blob: 9665478fe894eb5d902923d2710c9b9fb5eaa69f [file] [log] [blame]
Alex Perrycb7da4b2019-08-28 19:35:56 -07001#include "aos/events/shm_event_loop.h"
Parker Schuhe4a70d62017-12-27 20:10:20 -08002
Austin Schuh5f1cc5c2019-12-01 18:01:11 -08003#include <string_view>
4
Austin Schuh99f7c6a2024-06-25 22:07:44 -07005#include "absl/flags/flag.h"
6#include "absl/log/check.h"
7#include "absl/log/log.h"
Philipp Schrader790cb542023-07-05 21:06:52 -07008#include "gtest/gtest.h"
9
Alex Perrycb7da4b2019-08-28 19:35:56 -070010#include "aos/events/event_loop_param_test.h"
Austin Schuha94e1002021-07-21 15:45:21 -070011#include "aos/events/test_message_generated.h"
12#include "aos/network/team_number.h"
Austin Schuh62288252020-11-18 23:26:04 -080013#include "aos/realtime.h"
Parker Schuhe4a70d62017-12-27 20:10:20 -080014
Stephan Pleinesf63bde82024-01-13 15:59:33 -080015namespace aos::testing {
Parker Schuhe4a70d62017-12-27 20:10:20 -080016namespace {
Austin Schuh3115a202019-05-27 21:02:14 -070017namespace chrono = ::std::chrono;
Parker Schuhe4a70d62017-12-27 20:10:20 -080018
19class ShmEventLoopTestFactory : public EventLoopTestFactory {
20 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070021 ShmEventLoopTestFactory() {
Alex Perrycb7da4b2019-08-28 19:35:56 -070022 // Clean up anything left there before.
Austin Schuh99f7c6a2024-06-25 22:07:44 -070023 unlink(
24 (absl::GetFlag(FLAGS_shm_base) + "/test/aos.TestMessage.v7").c_str());
25 unlink(
26 (absl::GetFlag(FLAGS_shm_base) + "/test1/aos.TestMessage.v7").c_str());
27 unlink(
28 (absl::GetFlag(FLAGS_shm_base) + "/test2/aos.TestMessage.v7").c_str());
29 unlink(
30 (absl::GetFlag(FLAGS_shm_base) + "/test2/aos.TestMessage.v7").c_str());
31 unlink(
32 (absl::GetFlag(FLAGS_shm_base) + "/aos/aos.timing.Report.v7").c_str());
33 unlink((absl::GetFlag(FLAGS_shm_base) + "/aos/aos.logging.LogMessageFbs.v7")
34 .c_str());
Alex Perrycb7da4b2019-08-28 19:35:56 -070035 }
36
Austin Schuh99f7c6a2024-06-25 22:07:44 -070037 ~ShmEventLoopTestFactory() { absl::SetFlag(&FLAGS_override_hostname, ""); }
Austin Schuh217a9782019-12-21 23:02:50 -080038
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080039 ::std::unique_ptr<EventLoop> Make(std::string_view name) override {
Austin Schuh217a9782019-12-21 23:02:50 -080040 if (configuration()->has_nodes()) {
Austin Schuh99f7c6a2024-06-25 22:07:44 -070041 absl::SetFlag(&FLAGS_override_hostname,
42 std::string(my_node()->hostname()->string_view()));
Austin Schuh217a9782019-12-21 23:02:50 -080043 }
44 ::std::unique_ptr<ShmEventLoop> loop(new ShmEventLoop(configuration()));
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080045 loop->set_name(name);
James Kuszmaul9776b392023-01-14 14:08:08 -080046 return loop;
Parker Schuhe4a70d62017-12-27 20:10:20 -080047 }
48
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080049 ::std::unique_ptr<EventLoop> MakePrimary(std::string_view name) override {
Austin Schuh217a9782019-12-21 23:02:50 -080050 if (configuration()->has_nodes()) {
Austin Schuh99f7c6a2024-06-25 22:07:44 -070051 absl::SetFlag(&FLAGS_override_hostname,
52 std::string(my_node()->hostname()->string_view()));
Austin Schuh217a9782019-12-21 23:02:50 -080053 }
Austin Schuh44019f92019-05-19 19:58:27 -070054 ::std::unique_ptr<ShmEventLoop> loop =
Alex Perrycb7da4b2019-08-28 19:35:56 -070055 ::std::unique_ptr<ShmEventLoop>(new ShmEventLoop(configuration()));
Austin Schuh44019f92019-05-19 19:58:27 -070056 primary_event_loop_ = loop.get();
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080057 loop->set_name(name);
James Kuszmaul9776b392023-01-14 14:08:08 -080058 return loop;
Austin Schuh44019f92019-05-19 19:58:27 -070059 }
60
James Kuszmaul9f998082024-05-23 15:37:35 -070061 Result<void> Run() override {
Austin Schuh6bdcc372024-06-27 14:49:11 -070062 CHECK(primary_event_loop_ != nullptr);
63 return primary_event_loop_->Run();
James Kuszmaul9f998082024-05-23 15:37:35 -070064 }
65
66 std::unique_ptr<ExitHandle> MakeExitHandle() override {
Austin Schuh6bdcc372024-06-27 14:49:11 -070067 CHECK(primary_event_loop_ != nullptr);
68 return primary_event_loop_->MakeExitHandle();
James Kuszmaul9f998082024-05-23 15:37:35 -070069 }
Austin Schuh44019f92019-05-19 19:58:27 -070070
Austin Schuh6bdcc372024-06-27 14:49:11 -070071 void Exit() override {
72 CHECK(primary_event_loop_ != nullptr);
73 primary_event_loop_->Exit();
74 }
Austin Schuh9fe68f72019-08-10 19:32:03 -070075
Austin Schuh52d325c2019-06-23 18:59:06 -070076 void SleepFor(::std::chrono::nanoseconds duration) override {
77 ::std::this_thread::sleep_for(duration);
78 }
79
Austin Schuh44019f92019-05-19 19:58:27 -070080 private:
James Kuszmaul9f998082024-05-23 15:37:35 -070081 ::aos::ShmEventLoop *primary_event_loop_ = nullptr;
Parker Schuhe4a70d62017-12-27 20:10:20 -080082};
83
Austin Schuh6bae8252021-02-07 22:01:49 -080084auto CommonParameters() {
85 return ::testing::Combine(
86 ::testing::Values([]() { return new ShmEventLoopTestFactory(); }),
87 ::testing::Values(ReadMethod::COPY, ReadMethod::PIN),
88 ::testing::Values(DoTimingReports::kYes, DoTimingReports::kNo));
89}
Parker Schuhe4a70d62017-12-27 20:10:20 -080090
James Kuszmaulf4bf9fe2021-05-10 22:58:24 -070091INSTANTIATE_TEST_SUITE_P(ShmEventLoopCommonTest, AbstractEventLoopTest,
Brian Silvermance418d02021-11-03 11:25:52 -070092 CommonParameters());
Brian Silverman77162972020-08-12 19:52:40 -070093
Brian Silvermance418d02021-11-03 11:25:52 -070094INSTANTIATE_TEST_SUITE_P(ShmEventLoopCommonDeathTest,
95 AbstractEventLoopDeathTest, CommonParameters());
Austin Schuh6b6dfa52019-06-12 20:16:20 -070096
Parker Schuhe4a70d62017-12-27 20:10:20 -080097} // namespace
James Kuszmaulc79768b2019-02-18 15:08:44 -080098
Austin Schuh3115a202019-05-27 21:02:14 -070099bool IsRealtime() {
100 int scheduler;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700101 PCHECK((scheduler = sched_getscheduler(0)) != -1);
102
Austin Schuh62288252020-11-18 23:26:04 -0800103 {
104 // If we are RT, logging the scheduler will crash us. Mark that we just
105 // don't care.
106 aos::ScopedNotRealtime nrt;
107 LOG(INFO) << "scheduler is " << scheduler;
108 }
109
110 const bool result = scheduler == SCHED_FIFO || scheduler == SCHED_RR;
111 // Confirm that the scheduler matches AOS' interpretation of if we are
112 // realtime or not.
113 if (result) {
114 aos::CheckRealtime();
115 } else {
116 aos::CheckNotRealtime();
117 }
118 return result;
Austin Schuh3115a202019-05-27 21:02:14 -0700119}
James Kuszmaulc79768b2019-02-18 15:08:44 -0800120
Brian Silvermana5450a92020-08-12 19:59:57 -0700121class ShmEventLoopTest : public ::testing::TestWithParam<ReadMethod> {
122 public:
123 ShmEventLoopTest() {
124 if (GetParam() == ReadMethod::PIN) {
125 factory_.PinReads();
126 }
127 }
128
129 ShmEventLoopTestFactory *factory() { return &factory_; }
130
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700131 // Helper functions for testing when a fetcher cannot fetch the next message
132 // because it was overwritten
133 void TestNextMessageNotAvailable(const bool skip_timing_report) {
134 auto loop1 = factory()->MakePrimary("loop1");
135 if (skip_timing_report) {
136 loop1->SkipTimingReport();
137 }
138 auto fetcher = loop1->MakeFetcher<TestMessage>("/test");
139 auto loop2 = factory()->Make("loop2");
140 auto sender = loop2->MakeSender<TestMessage>("/test");
141 bool ran = false;
142 loop1->AddPhasedLoop(
143 [&sender](int) {
144 auto builder = sender.MakeBuilder();
145 TestMessage::Builder test_builder(*builder.fbb());
146 test_builder.add_value(0);
147 builder.CheckOk(builder.Send(test_builder.Finish()));
148 },
149 std::chrono::milliseconds(2));
150 loop1
151 ->AddTimer([this, &fetcher, &ran]() {
152 EXPECT_DEATH(fetcher.FetchNext(),
153 "The next message is no longer "
154 "available.*\"/test\".*\"aos\\.TestMessage\"");
155 factory()->Exit();
156 ran = true;
157 })
Philipp Schradera6712522023-07-05 20:25:11 -0700158 ->Schedule(loop1->monotonic_now() + std::chrono::seconds(4));
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700159 factory()->Run();
160 EXPECT_TRUE(ran);
161 }
162 void TestNextMessageNotAvailableNoRun(const bool skip_timing_report) {
163 auto loop1 = factory()->MakePrimary("loop1");
164 if (skip_timing_report) {
165 loop1->SkipTimingReport();
166 }
167 auto fetcher = loop1->MakeFetcher<TestMessage>("/test");
168 auto loop2 = factory()->Make("loop2");
169 auto sender = loop2->MakeSender<TestMessage>("/test");
170 time::PhasedLoop phased_loop(std::chrono::milliseconds(2),
171 loop2->monotonic_now());
172 for (int i = 0; i < 2000; ++i) {
173 auto builder = sender.MakeBuilder();
174 TestMessage::Builder test_builder(*builder.fbb());
175 test_builder.add_value(0);
176 builder.CheckOk(builder.Send(test_builder.Finish()));
177 phased_loop.SleepUntilNext();
178 }
179 EXPECT_DEATH(fetcher.FetchNext(),
180 "The next message is no longer "
181 "available.*\"/test\".*\"aos\\.TestMessage\"");
182 }
183
Brian Silvermana5450a92020-08-12 19:59:57 -0700184 private:
185 ShmEventLoopTestFactory factory_;
186};
187
188using ShmEventLoopDeathTest = ShmEventLoopTest;
189
Austin Schuha94e1002021-07-21 15:45:21 -0700190// Tests that we don't leave the calling thread realtime when calling Send
191// before Run.
192TEST_P(ShmEventLoopTest, SendBeforeRun) {
193 auto loop = factory()->MakePrimary("primary");
194 loop->SetRuntimeRealtimePriority(1);
195
196 auto loop2 = factory()->Make("loop2");
197 loop2->SetRuntimeRealtimePriority(2);
198 loop2->MakeWatcher("/test", [](const TestMessage &) {});
199 // Need the other one running for its watcher to record in SHM that it wants
200 // wakers to boost their priority, so leave it running in a thread for this
201 // test.
202 std::thread loop2_thread(
203 [&loop2]() { static_cast<ShmEventLoop *>(loop2.get())->Run(); });
204 std::this_thread::sleep_for(std::chrono::milliseconds(100));
205
206 auto sender = loop->MakeSender<TestMessage>("/test");
207 EXPECT_FALSE(IsRealtime());
208 {
209 aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
210 TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
211 builder.add_value(200);
milind1f1dca32021-07-03 13:50:07 -0700212 msg.CheckOk(msg.Send(builder.Finish()));
Austin Schuha94e1002021-07-21 15:45:21 -0700213 }
214 EXPECT_FALSE(IsRealtime());
215
216 static_cast<ShmEventLoop *>(loop2.get())->Exit();
217 loop2_thread.join();
218}
219
Austin Schuh3115a202019-05-27 21:02:14 -0700220// Tests that every handler type is realtime and runs. There are threads
221// involved and it's easy to miss one.
Brian Silvermana5450a92020-08-12 19:59:57 -0700222TEST_P(ShmEventLoopTest, AllHandlersAreRealtime) {
223 auto loop = factory()->MakePrimary("primary");
224 auto loop2 = factory()->Make("loop2");
Austin Schuh3115a202019-05-27 21:02:14 -0700225
226 loop->SetRuntimeRealtimePriority(1);
227
228 auto sender = loop2->MakeSender<TestMessage>("/test");
229
230 bool did_onrun = false;
231 bool did_timer = false;
232 bool did_watcher = false;
233
Brian Silvermana5450a92020-08-12 19:59:57 -0700234 auto timer = loop->AddTimer([this, &did_timer]() {
Austin Schuh3115a202019-05-27 21:02:14 -0700235 EXPECT_TRUE(IsRealtime());
236 did_timer = true;
Brian Silvermana5450a92020-08-12 19:59:57 -0700237 factory()->Exit();
Austin Schuh3115a202019-05-27 21:02:14 -0700238 });
239
240 loop->MakeWatcher("/test", [&did_watcher](const TestMessage &) {
241 EXPECT_TRUE(IsRealtime());
242 did_watcher = true;
243 });
244
245 loop->OnRun([&loop, &did_onrun, &sender, timer]() {
246 EXPECT_TRUE(IsRealtime());
247 did_onrun = true;
Philipp Schradera6712522023-07-05 20:25:11 -0700248 timer->Schedule(loop->monotonic_now() + chrono::milliseconds(100));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700249
250 aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
251 TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
252 builder.add_value(200);
milind1f1dca32021-07-03 13:50:07 -0700253 msg.CheckOk(msg.Send(builder.Finish()));
Austin Schuh3115a202019-05-27 21:02:14 -0700254 });
James Kuszmaulc79768b2019-02-18 15:08:44 -0800255
Brian Silvermana5450a92020-08-12 19:59:57 -0700256 factory()->Run();
James Kuszmaulc79768b2019-02-18 15:08:44 -0800257
Austin Schuh3115a202019-05-27 21:02:14 -0700258 EXPECT_TRUE(did_onrun);
259 EXPECT_TRUE(did_timer);
260 EXPECT_TRUE(did_watcher);
James Kuszmaulc79768b2019-02-18 15:08:44 -0800261}
Austin Schuh52d325c2019-06-23 18:59:06 -0700262
263// Tests that missing a deadline inside the function still results in PhasedLoop
264// running at the right offset.
Brian Silvermana5450a92020-08-12 19:59:57 -0700265TEST_P(ShmEventLoopTest, DelayedPhasedLoop) {
266 auto loop1 = factory()->MakePrimary("primary");
Austin Schuh52d325c2019-06-23 18:59:06 -0700267
268 ::std::vector<::aos::monotonic_clock::time_point> times;
269
270 constexpr chrono::milliseconds kOffset = chrono::milliseconds(400);
271
272 loop1->AddPhasedLoop(
Brian Silvermana5450a92020-08-12 19:59:57 -0700273 [this, &times, &loop1, &kOffset](int count) {
Austin Schuh52d325c2019-06-23 18:59:06 -0700274 const ::aos::monotonic_clock::time_point monotonic_now =
275 loop1->monotonic_now();
276
277 // Compute our offset.
278 const ::aos::monotonic_clock::duration remainder =
279 monotonic_now.time_since_epoch() -
280 chrono::duration_cast<chrono::seconds>(
281 monotonic_now.time_since_epoch());
282
283 // Make sure we we are called near where we should be even when we
284 // delay.
285 constexpr chrono::milliseconds kEpsilon(200);
286 EXPECT_LT(remainder, kOffset + kEpsilon);
287 EXPECT_GT(remainder, kOffset - kEpsilon);
288
289 // Confirm that we see the missed count when we sleep.
290 if (times.size() == 0) {
Austin Schuhde8a8ff2019-11-30 15:25:36 -0800291 CHECK_EQ(count, 1);
Austin Schuh52d325c2019-06-23 18:59:06 -0700292 } else {
Austin Schuhde8a8ff2019-11-30 15:25:36 -0800293 CHECK_EQ(count, 3);
Austin Schuh52d325c2019-06-23 18:59:06 -0700294 }
295
296 times.push_back(loop1->monotonic_now());
297 if (times.size() == 2) {
Brian Silvermana5450a92020-08-12 19:59:57 -0700298 factory()->Exit();
Austin Schuh52d325c2019-06-23 18:59:06 -0700299 }
300
301 // Now, add a large delay. This should push us up to 3 cycles.
302 ::std::this_thread::sleep_for(chrono::milliseconds(2500));
303 },
304 chrono::seconds(1), kOffset);
305
Brian Silvermana5450a92020-08-12 19:59:57 -0700306 factory()->Run();
Austin Schuh52d325c2019-06-23 18:59:06 -0700307
308 EXPECT_EQ(times.size(), 2u);
309}
310
James Kuszmaul9f998082024-05-23 15:37:35 -0700311// Tests that the ShmEventLoop::Exit() method causes the ShmEventLoop to return
312// with a successful status.
313TEST_P(ShmEventLoopTest, SuccessfulExitTest) {
314 auto loop1 = factory()->MakePrimary("primary");
315 auto exit_handle = factory()->MakeExitHandle();
316
317 loop1->OnRun([this, &exit_handle]() {
318 factory()->Exit();
319 // The second Exit() call should get ignored.
320 exit_handle->Exit(aos::Error::MakeUnexpectedError("Hello, World!"));
321 });
322
323 EXPECT_TRUE(factory()->Run().has_value());
324}
325
Brian Silverman5120afb2020-01-31 17:44:35 -0800326// Test GetWatcherSharedMemory in a few basic scenarios.
Brian Silvermana5450a92020-08-12 19:59:57 -0700327TEST_P(ShmEventLoopDeathTest, GetWatcherSharedMemory) {
328 auto generic_loop1 = factory()->MakePrimary("primary");
Brian Silverman5120afb2020-01-31 17:44:35 -0800329 ShmEventLoop *const loop1 = static_cast<ShmEventLoop *>(generic_loop1.get());
330 const auto channel = configuration::GetChannel(
331 loop1->configuration(), "/test", TestMessage::GetFullyQualifiedName(),
332 loop1->name(), loop1->node());
333
334 // First verify it handles an invalid channel reasonably.
335 EXPECT_DEATH(loop1->GetWatcherSharedMemory(channel),
336 "No watcher found for channel");
337
338 // Then, actually create a watcher, and verify it returns something sane.
Brian Silvermana5450a92020-08-12 19:59:57 -0700339 absl::Span<const char> shared_memory;
340 bool ran = false;
341 loop1->MakeWatcher("/test", [this, &shared_memory,
342 &ran](const TestMessage &message) {
343 EXPECT_FALSE(ran);
344 ran = true;
345 // If we're using pinning, then we can verify that the message is actually
346 // in the specified region.
347 if (GetParam() == ReadMethod::PIN) {
348 EXPECT_GE(reinterpret_cast<const char *>(&message),
349 shared_memory.begin());
350 EXPECT_LT(reinterpret_cast<const char *>(&message), shared_memory.end());
351 }
352 factory()->Exit();
353 });
354 shared_memory = loop1->GetWatcherSharedMemory(channel);
355 EXPECT_FALSE(shared_memory.empty());
356
357 auto loop2 = factory()->Make("sender");
358 auto sender = loop2->MakeSender<TestMessage>("/test");
359 generic_loop1->OnRun([&sender]() {
360 auto builder = sender.MakeBuilder();
361 TestMessage::Builder test_builder(*builder.fbb());
362 test_builder.add_value(1);
milind1f1dca32021-07-03 13:50:07 -0700363 builder.CheckOk(builder.Send(test_builder.Finish()));
Brian Silvermana5450a92020-08-12 19:59:57 -0700364 });
365 factory()->Run();
366 EXPECT_TRUE(ran);
Brian Silverman5120afb2020-01-31 17:44:35 -0800367}
368
Brian Silvermana5450a92020-08-12 19:59:57 -0700369TEST_P(ShmEventLoopTest, GetSenderSharedMemory) {
370 auto generic_loop1 = factory()->MakePrimary("primary");
Brian Silverman5120afb2020-01-31 17:44:35 -0800371 ShmEventLoop *const loop1 = static_cast<ShmEventLoop *>(generic_loop1.get());
372
Brian Silvermana5450a92020-08-12 19:59:57 -0700373 // Check that GetSenderSharedMemory returns non-null/non-empty memory span.
Brian Silverman5120afb2020-01-31 17:44:35 -0800374 auto sender = loop1->MakeSender<TestMessage>("/test");
Brian Silvermana5450a92020-08-12 19:59:57 -0700375 const absl::Span<char> shared_memory = loop1->GetSenderSharedMemory(&sender);
376 EXPECT_FALSE(shared_memory.empty());
377
378 auto builder = sender.MakeBuilder();
379 uint8_t *buffer;
James Kuszmaul65541cb2022-11-08 14:53:47 -0800380 builder.fbb()->CreateUninitializedVector(5, &buffer);
Brian Silvermana5450a92020-08-12 19:59:57 -0700381 EXPECT_GE(reinterpret_cast<char *>(buffer), shared_memory.begin());
382 EXPECT_LT(reinterpret_cast<char *>(buffer), shared_memory.end());
Brian Silverman5120afb2020-01-31 17:44:35 -0800383}
384
Brian Silvermana5450a92020-08-12 19:59:57 -0700385TEST_P(ShmEventLoopTest, GetFetcherPrivateMemory) {
386 auto generic_loop1 = factory()->MakePrimary("primary");
Brian Silverman6d2b3592020-06-18 14:40:15 -0700387 ShmEventLoop *const loop1 = static_cast<ShmEventLoop *>(generic_loop1.get());
388
Brian Silvermana5450a92020-08-12 19:59:57 -0700389 // Check that GetFetcherPrivateMemory returns non-null/non-empty memory span.
Brian Silverman6d2b3592020-06-18 14:40:15 -0700390 auto fetcher = loop1->MakeFetcher<TestMessage>("/test");
Brian Silvermana5450a92020-08-12 19:59:57 -0700391 const auto private_memory = loop1->GetFetcherPrivateMemory(&fetcher);
392 EXPECT_FALSE(private_memory.empty());
393
394 auto loop2 = factory()->Make("sender");
395 auto sender = loop2->MakeSender<TestMessage>("/test");
396 {
397 auto builder = sender.MakeBuilder();
398 TestMessage::Builder test_builder(*builder.fbb());
399 test_builder.add_value(1);
milind1f1dca32021-07-03 13:50:07 -0700400 builder.CheckOk(builder.Send(test_builder.Finish()));
Brian Silvermana5450a92020-08-12 19:59:57 -0700401 }
402
403 ASSERT_TRUE(fetcher.Fetch());
404 EXPECT_GE(fetcher.context().data, private_memory.begin());
405 EXPECT_LT(fetcher.context().data, private_memory.end());
Brian Silverman6d2b3592020-06-18 14:40:15 -0700406}
407
Brian Silverman0eaa1da2020-08-12 20:03:52 -0700408// Tests that corrupting the bytes around the data buffer results in a crash.
409TEST_P(ShmEventLoopDeathTest, OutOfBoundsWrite) {
410 auto loop1 = factory()->Make("loop1");
411 std::unique_ptr<aos::RawSender> sender =
412 loop1->MakeRawSender(configuration::GetChannel(
413 loop1->configuration(), "/test", "aos.TestMessage", "", nullptr));
414 for (size_t i = 0; i < kChannelDataRedzone; ++i) {
415 SCOPED_TRACE(std::to_string(i));
416 EXPECT_DEATH(
417 {
Philipp Schrader4473d2c2023-12-01 13:43:09 -0800418 // Can't use `data()[-1 -i]` here because that's undefined behaviour.
419 // We do manual pointer arithmetic to work around that.
420 ++(*(static_cast<char *>(sender->data()) - 1 - i));
milind1f1dca32021-07-03 13:50:07 -0700421 sender->CheckOk(sender->Send(0));
Brian Silverman0eaa1da2020-08-12 20:03:52 -0700422 },
423 "Somebody wrote outside the buffer of their message");
424 EXPECT_DEATH(
425 {
426 ++static_cast<char *>(sender->data())[sender->size() + i];
milind1f1dca32021-07-03 13:50:07 -0700427 sender->CheckOk(sender->Send(0));
Brian Silverman0eaa1da2020-08-12 20:03:52 -0700428 },
429 "Somebody wrote outside the buffer of their message");
430 }
431}
432
Brian Silvermance418d02021-11-03 11:25:52 -0700433// Tests that the next message not being available prints a helpful error in the
434// normal case.
435TEST_P(ShmEventLoopDeathTest, NextMessageNotAvailable) {
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700436 TestNextMessageNotAvailable(false);
Brian Silvermance418d02021-11-03 11:25:52 -0700437}
438
439// Tests that the next message not being available prints a helpful error with
440// timing reports disabled.
441TEST_P(ShmEventLoopDeathTest, NextMessageNotAvailableNoTimingReports) {
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700442 TestNextMessageNotAvailable(true);
Brian Silvermance418d02021-11-03 11:25:52 -0700443}
444
445// Tests that the next message not being available prints a helpful error even
446// when Run is never called.
447TEST_P(ShmEventLoopDeathTest, NextMessageNotAvailableNoRun) {
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700448 TestNextMessageNotAvailableNoRun(false);
Brian Silvermance418d02021-11-03 11:25:52 -0700449}
450
451// Tests that the next message not being available prints a helpful error even
452// when Run is never called without timing reports.
453TEST_P(ShmEventLoopDeathTest, NextMessageNotAvailableNoRunNoTimingReports) {
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700454 TestNextMessageNotAvailableNoRun(true);
Brian Silvermance418d02021-11-03 11:25:52 -0700455}
456
Brian Silvermane1fe2512022-08-14 23:18:50 -0700457// Test that an ExitHandle outliving its EventLoop is caught.
458TEST_P(ShmEventLoopDeathTest, ExitHandleOutlivesEventLoop) {
459 auto loop1 = factory()->MakePrimary("loop1");
460 auto exit_handle = static_cast<ShmEventLoop *>(loop1.get())->MakeExitHandle();
461 EXPECT_DEATH(loop1.reset(),
462 "All ExitHandles must be destroyed before the ShmEventLoop");
463}
464
Austin Schuh39788ff2019-12-01 18:22:57 -0800465// TODO(austin): Test that missing a deadline with a timer recovers as expected.
466
James Kuszmaulf4bf9fe2021-05-10 22:58:24 -0700467INSTANTIATE_TEST_SUITE_P(ShmEventLoopCopyTest, ShmEventLoopTest,
Brian Silvermance418d02021-11-03 11:25:52 -0700468 ::testing::Values(ReadMethod::COPY));
James Kuszmaulf4bf9fe2021-05-10 22:58:24 -0700469INSTANTIATE_TEST_SUITE_P(ShmEventLoopPinTest, ShmEventLoopTest,
Brian Silvermance418d02021-11-03 11:25:52 -0700470 ::testing::Values(ReadMethod::PIN));
James Kuszmaulf4bf9fe2021-05-10 22:58:24 -0700471INSTANTIATE_TEST_SUITE_P(ShmEventLoopCopyDeathTest, ShmEventLoopDeathTest,
Brian Silvermance418d02021-11-03 11:25:52 -0700472 ::testing::Values(ReadMethod::COPY));
James Kuszmaulf4bf9fe2021-05-10 22:58:24 -0700473INSTANTIATE_TEST_SUITE_P(ShmEventLoopPinDeathTest, ShmEventLoopDeathTest,
Brian Silvermance418d02021-11-03 11:25:52 -0700474 ::testing::Values(ReadMethod::PIN));
Brian Silvermana5450a92020-08-12 19:59:57 -0700475
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800476} // namespace aos::testing