blob: 2fbe7351d2890025211b0492c44c8e77a0fe7ec4 [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
Philipp Schrader790cb542023-07-05 21:06:52 -07005#include "glog/logging.h"
6#include "gtest/gtest.h"
7
Alex Perrycb7da4b2019-08-28 19:35:56 -07008#include "aos/events/event_loop_param_test.h"
Austin Schuha94e1002021-07-21 15:45:21 -07009#include "aos/events/test_message_generated.h"
10#include "aos/network/team_number.h"
Austin Schuh62288252020-11-18 23:26:04 -080011#include "aos/realtime.h"
Parker Schuhe4a70d62017-12-27 20:10:20 -080012
Stephan Pleinesf63bde82024-01-13 15:59:33 -080013namespace aos::testing {
Parker Schuhe4a70d62017-12-27 20:10:20 -080014namespace {
Austin Schuh3115a202019-05-27 21:02:14 -070015namespace chrono = ::std::chrono;
Parker Schuhe4a70d62017-12-27 20:10:20 -080016
17class ShmEventLoopTestFactory : public EventLoopTestFactory {
18 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070019 ShmEventLoopTestFactory() {
20 // Put all the queue files in ${TEST_TMPDIR} if it is set, otherwise
21 // everything will be reusing /dev/shm when sharded.
22 char *test_tmpdir = getenv("TEST_TMPDIR");
23 if (test_tmpdir != nullptr) {
24 FLAGS_shm_base = std::string(test_tmpdir) + "/aos";
25 }
26
27 // Clean up anything left there before.
Austin Schuhac6d89e2024-03-27 14:56:09 -070028 unlink((FLAGS_shm_base + "/test/aos.TestMessage.v7").c_str());
29 unlink((FLAGS_shm_base + "/test1/aos.TestMessage.v7").c_str());
30 unlink((FLAGS_shm_base + "/test2/aos.TestMessage.v7").c_str());
31 unlink((FLAGS_shm_base + "/test2/aos.TestMessage.v7").c_str());
32 unlink((FLAGS_shm_base + "/aos/aos.timing.Report.v7").c_str());
33 unlink((FLAGS_shm_base + "/aos/aos.logging.LogMessageFbs.v7").c_str());
Alex Perrycb7da4b2019-08-28 19:35:56 -070034 }
35
Austin Schuh217a9782019-12-21 23:02:50 -080036 ~ShmEventLoopTestFactory() { FLAGS_override_hostname = ""; }
37
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080038 ::std::unique_ptr<EventLoop> Make(std::string_view name) override {
Austin Schuh217a9782019-12-21 23:02:50 -080039 if (configuration()->has_nodes()) {
Austin Schuh898f4972020-01-11 17:21:25 -080040 FLAGS_override_hostname =
41 std::string(my_node()->hostname()->string_view());
Austin Schuh217a9782019-12-21 23:02:50 -080042 }
43 ::std::unique_ptr<ShmEventLoop> loop(new ShmEventLoop(configuration()));
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080044 loop->set_name(name);
James Kuszmaul9776b392023-01-14 14:08:08 -080045 return loop;
Parker Schuhe4a70d62017-12-27 20:10:20 -080046 }
47
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080048 ::std::unique_ptr<EventLoop> MakePrimary(std::string_view name) override {
Austin Schuh217a9782019-12-21 23:02:50 -080049 if (configuration()->has_nodes()) {
Austin Schuh898f4972020-01-11 17:21:25 -080050 FLAGS_override_hostname =
51 std::string(my_node()->hostname()->string_view());
Austin Schuh217a9782019-12-21 23:02:50 -080052 }
Austin Schuh44019f92019-05-19 19:58:27 -070053 ::std::unique_ptr<ShmEventLoop> loop =
Alex Perrycb7da4b2019-08-28 19:35:56 -070054 ::std::unique_ptr<ShmEventLoop>(new ShmEventLoop(configuration()));
Austin Schuh44019f92019-05-19 19:58:27 -070055 primary_event_loop_ = loop.get();
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080056 loop->set_name(name);
James Kuszmaul9776b392023-01-14 14:08:08 -080057 return loop;
Austin Schuh44019f92019-05-19 19:58:27 -070058 }
59
James Kuszmaul9f998082024-05-23 15:37:35 -070060 Result<void> Run() override {
61 return CHECK_NOTNULL(primary_event_loop_)->Run();
62 }
63
64 std::unique_ptr<ExitHandle> MakeExitHandle() override {
65 return CHECK_NOTNULL(primary_event_loop_)->MakeExitHandle();
66 }
Austin Schuh44019f92019-05-19 19:58:27 -070067
Alex Perrycb7da4b2019-08-28 19:35:56 -070068 void Exit() override { CHECK_NOTNULL(primary_event_loop_)->Exit(); }
Austin Schuh9fe68f72019-08-10 19:32:03 -070069
Austin Schuh52d325c2019-06-23 18:59:06 -070070 void SleepFor(::std::chrono::nanoseconds duration) override {
71 ::std::this_thread::sleep_for(duration);
72 }
73
Austin Schuh44019f92019-05-19 19:58:27 -070074 private:
James Kuszmaul9f998082024-05-23 15:37:35 -070075 ::aos::ShmEventLoop *primary_event_loop_ = nullptr;
Parker Schuhe4a70d62017-12-27 20:10:20 -080076};
77
Austin Schuh6bae8252021-02-07 22:01:49 -080078auto CommonParameters() {
79 return ::testing::Combine(
80 ::testing::Values([]() { return new ShmEventLoopTestFactory(); }),
81 ::testing::Values(ReadMethod::COPY, ReadMethod::PIN),
82 ::testing::Values(DoTimingReports::kYes, DoTimingReports::kNo));
83}
Parker Schuhe4a70d62017-12-27 20:10:20 -080084
James Kuszmaulf4bf9fe2021-05-10 22:58:24 -070085INSTANTIATE_TEST_SUITE_P(ShmEventLoopCommonTest, AbstractEventLoopTest,
Brian Silvermance418d02021-11-03 11:25:52 -070086 CommonParameters());
Brian Silverman77162972020-08-12 19:52:40 -070087
Brian Silvermance418d02021-11-03 11:25:52 -070088INSTANTIATE_TEST_SUITE_P(ShmEventLoopCommonDeathTest,
89 AbstractEventLoopDeathTest, CommonParameters());
Austin Schuh6b6dfa52019-06-12 20:16:20 -070090
Parker Schuhe4a70d62017-12-27 20:10:20 -080091} // namespace
James Kuszmaulc79768b2019-02-18 15:08:44 -080092
Austin Schuh3115a202019-05-27 21:02:14 -070093bool IsRealtime() {
94 int scheduler;
Alex Perrycb7da4b2019-08-28 19:35:56 -070095 PCHECK((scheduler = sched_getscheduler(0)) != -1);
96
Austin Schuh62288252020-11-18 23:26:04 -080097 {
98 // If we are RT, logging the scheduler will crash us. Mark that we just
99 // don't care.
100 aos::ScopedNotRealtime nrt;
101 LOG(INFO) << "scheduler is " << scheduler;
102 }
103
104 const bool result = scheduler == SCHED_FIFO || scheduler == SCHED_RR;
105 // Confirm that the scheduler matches AOS' interpretation of if we are
106 // realtime or not.
107 if (result) {
108 aos::CheckRealtime();
109 } else {
110 aos::CheckNotRealtime();
111 }
112 return result;
Austin Schuh3115a202019-05-27 21:02:14 -0700113}
James Kuszmaulc79768b2019-02-18 15:08:44 -0800114
Brian Silvermana5450a92020-08-12 19:59:57 -0700115class ShmEventLoopTest : public ::testing::TestWithParam<ReadMethod> {
116 public:
117 ShmEventLoopTest() {
118 if (GetParam() == ReadMethod::PIN) {
119 factory_.PinReads();
120 }
121 }
122
123 ShmEventLoopTestFactory *factory() { return &factory_; }
124
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700125 // Helper functions for testing when a fetcher cannot fetch the next message
126 // because it was overwritten
127 void TestNextMessageNotAvailable(const bool skip_timing_report) {
128 auto loop1 = factory()->MakePrimary("loop1");
129 if (skip_timing_report) {
130 loop1->SkipTimingReport();
131 }
132 auto fetcher = loop1->MakeFetcher<TestMessage>("/test");
133 auto loop2 = factory()->Make("loop2");
134 auto sender = loop2->MakeSender<TestMessage>("/test");
135 bool ran = false;
136 loop1->AddPhasedLoop(
137 [&sender](int) {
138 auto builder = sender.MakeBuilder();
139 TestMessage::Builder test_builder(*builder.fbb());
140 test_builder.add_value(0);
141 builder.CheckOk(builder.Send(test_builder.Finish()));
142 },
143 std::chrono::milliseconds(2));
144 loop1
145 ->AddTimer([this, &fetcher, &ran]() {
146 EXPECT_DEATH(fetcher.FetchNext(),
147 "The next message is no longer "
148 "available.*\"/test\".*\"aos\\.TestMessage\"");
149 factory()->Exit();
150 ran = true;
151 })
Philipp Schradera6712522023-07-05 20:25:11 -0700152 ->Schedule(loop1->monotonic_now() + std::chrono::seconds(4));
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700153 factory()->Run();
154 EXPECT_TRUE(ran);
155 }
156 void TestNextMessageNotAvailableNoRun(const bool skip_timing_report) {
157 auto loop1 = factory()->MakePrimary("loop1");
158 if (skip_timing_report) {
159 loop1->SkipTimingReport();
160 }
161 auto fetcher = loop1->MakeFetcher<TestMessage>("/test");
162 auto loop2 = factory()->Make("loop2");
163 auto sender = loop2->MakeSender<TestMessage>("/test");
164 time::PhasedLoop phased_loop(std::chrono::milliseconds(2),
165 loop2->monotonic_now());
166 for (int i = 0; i < 2000; ++i) {
167 auto builder = sender.MakeBuilder();
168 TestMessage::Builder test_builder(*builder.fbb());
169 test_builder.add_value(0);
170 builder.CheckOk(builder.Send(test_builder.Finish()));
171 phased_loop.SleepUntilNext();
172 }
173 EXPECT_DEATH(fetcher.FetchNext(),
174 "The next message is no longer "
175 "available.*\"/test\".*\"aos\\.TestMessage\"");
176 }
177
Brian Silvermana5450a92020-08-12 19:59:57 -0700178 private:
179 ShmEventLoopTestFactory factory_;
180};
181
182using ShmEventLoopDeathTest = ShmEventLoopTest;
183
Austin Schuha94e1002021-07-21 15:45:21 -0700184// Tests that we don't leave the calling thread realtime when calling Send
185// before Run.
186TEST_P(ShmEventLoopTest, SendBeforeRun) {
187 auto loop = factory()->MakePrimary("primary");
188 loop->SetRuntimeRealtimePriority(1);
189
190 auto loop2 = factory()->Make("loop2");
191 loop2->SetRuntimeRealtimePriority(2);
192 loop2->MakeWatcher("/test", [](const TestMessage &) {});
193 // Need the other one running for its watcher to record in SHM that it wants
194 // wakers to boost their priority, so leave it running in a thread for this
195 // test.
196 std::thread loop2_thread(
197 [&loop2]() { static_cast<ShmEventLoop *>(loop2.get())->Run(); });
198 std::this_thread::sleep_for(std::chrono::milliseconds(100));
199
200 auto sender = loop->MakeSender<TestMessage>("/test");
201 EXPECT_FALSE(IsRealtime());
202 {
203 aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
204 TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
205 builder.add_value(200);
milind1f1dca32021-07-03 13:50:07 -0700206 msg.CheckOk(msg.Send(builder.Finish()));
Austin Schuha94e1002021-07-21 15:45:21 -0700207 }
208 EXPECT_FALSE(IsRealtime());
209
210 static_cast<ShmEventLoop *>(loop2.get())->Exit();
211 loop2_thread.join();
212}
213
Austin Schuh3115a202019-05-27 21:02:14 -0700214// Tests that every handler type is realtime and runs. There are threads
215// involved and it's easy to miss one.
Brian Silvermana5450a92020-08-12 19:59:57 -0700216TEST_P(ShmEventLoopTest, AllHandlersAreRealtime) {
217 auto loop = factory()->MakePrimary("primary");
218 auto loop2 = factory()->Make("loop2");
Austin Schuh3115a202019-05-27 21:02:14 -0700219
220 loop->SetRuntimeRealtimePriority(1);
221
222 auto sender = loop2->MakeSender<TestMessage>("/test");
223
224 bool did_onrun = false;
225 bool did_timer = false;
226 bool did_watcher = false;
227
Brian Silvermana5450a92020-08-12 19:59:57 -0700228 auto timer = loop->AddTimer([this, &did_timer]() {
Austin Schuh3115a202019-05-27 21:02:14 -0700229 EXPECT_TRUE(IsRealtime());
230 did_timer = true;
Brian Silvermana5450a92020-08-12 19:59:57 -0700231 factory()->Exit();
Austin Schuh3115a202019-05-27 21:02:14 -0700232 });
233
234 loop->MakeWatcher("/test", [&did_watcher](const TestMessage &) {
235 EXPECT_TRUE(IsRealtime());
236 did_watcher = true;
237 });
238
239 loop->OnRun([&loop, &did_onrun, &sender, timer]() {
240 EXPECT_TRUE(IsRealtime());
241 did_onrun = true;
Philipp Schradera6712522023-07-05 20:25:11 -0700242 timer->Schedule(loop->monotonic_now() + chrono::milliseconds(100));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700243
244 aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
245 TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
246 builder.add_value(200);
milind1f1dca32021-07-03 13:50:07 -0700247 msg.CheckOk(msg.Send(builder.Finish()));
Austin Schuh3115a202019-05-27 21:02:14 -0700248 });
James Kuszmaulc79768b2019-02-18 15:08:44 -0800249
Brian Silvermana5450a92020-08-12 19:59:57 -0700250 factory()->Run();
James Kuszmaulc79768b2019-02-18 15:08:44 -0800251
Austin Schuh3115a202019-05-27 21:02:14 -0700252 EXPECT_TRUE(did_onrun);
253 EXPECT_TRUE(did_timer);
254 EXPECT_TRUE(did_watcher);
James Kuszmaulc79768b2019-02-18 15:08:44 -0800255}
Austin Schuh52d325c2019-06-23 18:59:06 -0700256
257// Tests that missing a deadline inside the function still results in PhasedLoop
258// running at the right offset.
Brian Silvermana5450a92020-08-12 19:59:57 -0700259TEST_P(ShmEventLoopTest, DelayedPhasedLoop) {
260 auto loop1 = factory()->MakePrimary("primary");
Austin Schuh52d325c2019-06-23 18:59:06 -0700261
262 ::std::vector<::aos::monotonic_clock::time_point> times;
263
264 constexpr chrono::milliseconds kOffset = chrono::milliseconds(400);
265
266 loop1->AddPhasedLoop(
Brian Silvermana5450a92020-08-12 19:59:57 -0700267 [this, &times, &loop1, &kOffset](int count) {
Austin Schuh52d325c2019-06-23 18:59:06 -0700268 const ::aos::monotonic_clock::time_point monotonic_now =
269 loop1->monotonic_now();
270
271 // Compute our offset.
272 const ::aos::monotonic_clock::duration remainder =
273 monotonic_now.time_since_epoch() -
274 chrono::duration_cast<chrono::seconds>(
275 monotonic_now.time_since_epoch());
276
277 // Make sure we we are called near where we should be even when we
278 // delay.
279 constexpr chrono::milliseconds kEpsilon(200);
280 EXPECT_LT(remainder, kOffset + kEpsilon);
281 EXPECT_GT(remainder, kOffset - kEpsilon);
282
283 // Confirm that we see the missed count when we sleep.
284 if (times.size() == 0) {
Austin Schuhde8a8ff2019-11-30 15:25:36 -0800285 CHECK_EQ(count, 1);
Austin Schuh52d325c2019-06-23 18:59:06 -0700286 } else {
Austin Schuhde8a8ff2019-11-30 15:25:36 -0800287 CHECK_EQ(count, 3);
Austin Schuh52d325c2019-06-23 18:59:06 -0700288 }
289
290 times.push_back(loop1->monotonic_now());
291 if (times.size() == 2) {
Brian Silvermana5450a92020-08-12 19:59:57 -0700292 factory()->Exit();
Austin Schuh52d325c2019-06-23 18:59:06 -0700293 }
294
295 // Now, add a large delay. This should push us up to 3 cycles.
296 ::std::this_thread::sleep_for(chrono::milliseconds(2500));
297 },
298 chrono::seconds(1), kOffset);
299
Brian Silvermana5450a92020-08-12 19:59:57 -0700300 factory()->Run();
Austin Schuh52d325c2019-06-23 18:59:06 -0700301
302 EXPECT_EQ(times.size(), 2u);
303}
304
James Kuszmaul9f998082024-05-23 15:37:35 -0700305// Tests that the ShmEventLoop::Exit() method causes the ShmEventLoop to return
306// with a successful status.
307TEST_P(ShmEventLoopTest, SuccessfulExitTest) {
308 auto loop1 = factory()->MakePrimary("primary");
309 auto exit_handle = factory()->MakeExitHandle();
310
311 loop1->OnRun([this, &exit_handle]() {
312 factory()->Exit();
313 // The second Exit() call should get ignored.
314 exit_handle->Exit(aos::Error::MakeUnexpectedError("Hello, World!"));
315 });
316
317 EXPECT_TRUE(factory()->Run().has_value());
318}
319
Brian Silverman5120afb2020-01-31 17:44:35 -0800320// Test GetWatcherSharedMemory in a few basic scenarios.
Brian Silvermana5450a92020-08-12 19:59:57 -0700321TEST_P(ShmEventLoopDeathTest, GetWatcherSharedMemory) {
322 auto generic_loop1 = factory()->MakePrimary("primary");
Brian Silverman5120afb2020-01-31 17:44:35 -0800323 ShmEventLoop *const loop1 = static_cast<ShmEventLoop *>(generic_loop1.get());
324 const auto channel = configuration::GetChannel(
325 loop1->configuration(), "/test", TestMessage::GetFullyQualifiedName(),
326 loop1->name(), loop1->node());
327
328 // First verify it handles an invalid channel reasonably.
329 EXPECT_DEATH(loop1->GetWatcherSharedMemory(channel),
330 "No watcher found for channel");
331
332 // Then, actually create a watcher, and verify it returns something sane.
Brian Silvermana5450a92020-08-12 19:59:57 -0700333 absl::Span<const char> shared_memory;
334 bool ran = false;
335 loop1->MakeWatcher("/test", [this, &shared_memory,
336 &ran](const TestMessage &message) {
337 EXPECT_FALSE(ran);
338 ran = true;
339 // If we're using pinning, then we can verify that the message is actually
340 // in the specified region.
341 if (GetParam() == ReadMethod::PIN) {
342 EXPECT_GE(reinterpret_cast<const char *>(&message),
343 shared_memory.begin());
344 EXPECT_LT(reinterpret_cast<const char *>(&message), shared_memory.end());
345 }
346 factory()->Exit();
347 });
348 shared_memory = loop1->GetWatcherSharedMemory(channel);
349 EXPECT_FALSE(shared_memory.empty());
350
351 auto loop2 = factory()->Make("sender");
352 auto sender = loop2->MakeSender<TestMessage>("/test");
353 generic_loop1->OnRun([&sender]() {
354 auto builder = sender.MakeBuilder();
355 TestMessage::Builder test_builder(*builder.fbb());
356 test_builder.add_value(1);
milind1f1dca32021-07-03 13:50:07 -0700357 builder.CheckOk(builder.Send(test_builder.Finish()));
Brian Silvermana5450a92020-08-12 19:59:57 -0700358 });
359 factory()->Run();
360 EXPECT_TRUE(ran);
Brian Silverman5120afb2020-01-31 17:44:35 -0800361}
362
Brian Silvermana5450a92020-08-12 19:59:57 -0700363TEST_P(ShmEventLoopTest, GetSenderSharedMemory) {
364 auto generic_loop1 = factory()->MakePrimary("primary");
Brian Silverman5120afb2020-01-31 17:44:35 -0800365 ShmEventLoop *const loop1 = static_cast<ShmEventLoop *>(generic_loop1.get());
366
Brian Silvermana5450a92020-08-12 19:59:57 -0700367 // Check that GetSenderSharedMemory returns non-null/non-empty memory span.
Brian Silverman5120afb2020-01-31 17:44:35 -0800368 auto sender = loop1->MakeSender<TestMessage>("/test");
Brian Silvermana5450a92020-08-12 19:59:57 -0700369 const absl::Span<char> shared_memory = loop1->GetSenderSharedMemory(&sender);
370 EXPECT_FALSE(shared_memory.empty());
371
372 auto builder = sender.MakeBuilder();
373 uint8_t *buffer;
James Kuszmaul65541cb2022-11-08 14:53:47 -0800374 builder.fbb()->CreateUninitializedVector(5, &buffer);
Brian Silvermana5450a92020-08-12 19:59:57 -0700375 EXPECT_GE(reinterpret_cast<char *>(buffer), shared_memory.begin());
376 EXPECT_LT(reinterpret_cast<char *>(buffer), shared_memory.end());
Brian Silverman5120afb2020-01-31 17:44:35 -0800377}
378
Brian Silvermana5450a92020-08-12 19:59:57 -0700379TEST_P(ShmEventLoopTest, GetFetcherPrivateMemory) {
380 auto generic_loop1 = factory()->MakePrimary("primary");
Brian Silverman6d2b3592020-06-18 14:40:15 -0700381 ShmEventLoop *const loop1 = static_cast<ShmEventLoop *>(generic_loop1.get());
382
Brian Silvermana5450a92020-08-12 19:59:57 -0700383 // Check that GetFetcherPrivateMemory returns non-null/non-empty memory span.
Brian Silverman6d2b3592020-06-18 14:40:15 -0700384 auto fetcher = loop1->MakeFetcher<TestMessage>("/test");
Brian Silvermana5450a92020-08-12 19:59:57 -0700385 const auto private_memory = loop1->GetFetcherPrivateMemory(&fetcher);
386 EXPECT_FALSE(private_memory.empty());
387
388 auto loop2 = factory()->Make("sender");
389 auto sender = loop2->MakeSender<TestMessage>("/test");
390 {
391 auto builder = sender.MakeBuilder();
392 TestMessage::Builder test_builder(*builder.fbb());
393 test_builder.add_value(1);
milind1f1dca32021-07-03 13:50:07 -0700394 builder.CheckOk(builder.Send(test_builder.Finish()));
Brian Silvermana5450a92020-08-12 19:59:57 -0700395 }
396
397 ASSERT_TRUE(fetcher.Fetch());
398 EXPECT_GE(fetcher.context().data, private_memory.begin());
399 EXPECT_LT(fetcher.context().data, private_memory.end());
Brian Silverman6d2b3592020-06-18 14:40:15 -0700400}
401
Brian Silverman0eaa1da2020-08-12 20:03:52 -0700402// Tests that corrupting the bytes around the data buffer results in a crash.
403TEST_P(ShmEventLoopDeathTest, OutOfBoundsWrite) {
404 auto loop1 = factory()->Make("loop1");
405 std::unique_ptr<aos::RawSender> sender =
406 loop1->MakeRawSender(configuration::GetChannel(
407 loop1->configuration(), "/test", "aos.TestMessage", "", nullptr));
408 for (size_t i = 0; i < kChannelDataRedzone; ++i) {
409 SCOPED_TRACE(std::to_string(i));
410 EXPECT_DEATH(
411 {
Philipp Schrader4473d2c2023-12-01 13:43:09 -0800412 // Can't use `data()[-1 -i]` here because that's undefined behaviour.
413 // We do manual pointer arithmetic to work around that.
414 ++(*(static_cast<char *>(sender->data()) - 1 - i));
milind1f1dca32021-07-03 13:50:07 -0700415 sender->CheckOk(sender->Send(0));
Brian Silverman0eaa1da2020-08-12 20:03:52 -0700416 },
417 "Somebody wrote outside the buffer of their message");
418 EXPECT_DEATH(
419 {
420 ++static_cast<char *>(sender->data())[sender->size() + 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 }
425}
426
Brian Silvermance418d02021-11-03 11:25:52 -0700427// Tests that the next message not being available prints a helpful error in the
428// normal case.
429TEST_P(ShmEventLoopDeathTest, NextMessageNotAvailable) {
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700430 TestNextMessageNotAvailable(false);
Brian Silvermance418d02021-11-03 11:25:52 -0700431}
432
433// Tests that the next message not being available prints a helpful error with
434// timing reports disabled.
435TEST_P(ShmEventLoopDeathTest, NextMessageNotAvailableNoTimingReports) {
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700436 TestNextMessageNotAvailable(true);
Brian Silvermance418d02021-11-03 11:25:52 -0700437}
438
439// Tests that the next message not being available prints a helpful error even
440// when Run is never called.
441TEST_P(ShmEventLoopDeathTest, NextMessageNotAvailableNoRun) {
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700442 TestNextMessageNotAvailableNoRun(false);
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 without timing reports.
447TEST_P(ShmEventLoopDeathTest, NextMessageNotAvailableNoRunNoTimingReports) {
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700448 TestNextMessageNotAvailableNoRun(true);
Brian Silvermance418d02021-11-03 11:25:52 -0700449}
450
Brian Silvermane1fe2512022-08-14 23:18:50 -0700451// Test that an ExitHandle outliving its EventLoop is caught.
452TEST_P(ShmEventLoopDeathTest, ExitHandleOutlivesEventLoop) {
453 auto loop1 = factory()->MakePrimary("loop1");
454 auto exit_handle = static_cast<ShmEventLoop *>(loop1.get())->MakeExitHandle();
455 EXPECT_DEATH(loop1.reset(),
456 "All ExitHandles must be destroyed before the ShmEventLoop");
457}
458
Austin Schuh39788ff2019-12-01 18:22:57 -0800459// TODO(austin): Test that missing a deadline with a timer recovers as expected.
460
James Kuszmaulf4bf9fe2021-05-10 22:58:24 -0700461INSTANTIATE_TEST_SUITE_P(ShmEventLoopCopyTest, ShmEventLoopTest,
Brian Silvermance418d02021-11-03 11:25:52 -0700462 ::testing::Values(ReadMethod::COPY));
James Kuszmaulf4bf9fe2021-05-10 22:58:24 -0700463INSTANTIATE_TEST_SUITE_P(ShmEventLoopPinTest, ShmEventLoopTest,
Brian Silvermance418d02021-11-03 11:25:52 -0700464 ::testing::Values(ReadMethod::PIN));
James Kuszmaulf4bf9fe2021-05-10 22:58:24 -0700465INSTANTIATE_TEST_SUITE_P(ShmEventLoopCopyDeathTest, ShmEventLoopDeathTest,
Brian Silvermance418d02021-11-03 11:25:52 -0700466 ::testing::Values(ReadMethod::COPY));
James Kuszmaulf4bf9fe2021-05-10 22:58:24 -0700467INSTANTIATE_TEST_SUITE_P(ShmEventLoopPinDeathTest, ShmEventLoopDeathTest,
Brian Silvermance418d02021-11-03 11:25:52 -0700468 ::testing::Values(ReadMethod::PIN));
Brian Silvermana5450a92020-08-12 19:59:57 -0700469
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800470} // namespace aos::testing