blob: d1025fad568fb08cc31844a8e2ed31802d54985d [file] [log] [blame]
Austin Schuhc243b422020-10-11 15:35:08 -07001#include "aos/events/logging/logfile_utils.h"
2
Austin Schuhe243aaf2020-10-11 15:46:02 -07003#include <chrono>
4#include <string>
Austin Schuhc243b422020-10-11 15:35:08 -07005
Austin Schuhc41603c2020-10-11 16:17:37 -07006#include "aos/events/logging/logfile_sorting.h"
Austin Schuhc243b422020-10-11 15:35:08 -07007#include "aos/events/logging/test_message_generated.h"
Austin Schuh4b5c22a2020-11-30 22:58:43 -08008#include "aos/flatbuffer_merge.h"
Austin Schuhe243aaf2020-10-11 15:46:02 -07009#include "aos/flatbuffers.h"
Austin Schuhc243b422020-10-11 15:35:08 -070010#include "aos/json_to_flatbuffer.h"
11#include "aos/testing/tmpdir.h"
Austin Schuhe243aaf2020-10-11 15:46:02 -070012#include "gtest/gtest.h"
Austin Schuhc243b422020-10-11 15:35:08 -070013
14namespace aos {
15namespace logger {
16namespace testing {
Austin Schuhe243aaf2020-10-11 15:46:02 -070017namespace chrono = std::chrono;
Austin Schuhc243b422020-10-11 15:35:08 -070018
Austin Schuhe243aaf2020-10-11 15:46:02 -070019// Creates a size prefixed flatbuffer from json.
Austin Schuhc243b422020-10-11 15:35:08 -070020template <typename T>
21SizePrefixedFlatbufferDetachedBuffer<T> JsonToSizedFlatbuffer(
22 const std::string_view data) {
23 flatbuffers::FlatBufferBuilder fbb;
24 fbb.ForceDefaults(true);
25 fbb.FinishSizePrefixed(JsonToFlatbuffer<T>(data, &fbb));
26 return fbb.Release();
27}
28
Austin Schuhe243aaf2020-10-11 15:46:02 -070029// Tests that we can write and read 2 flatbuffers to file.
Austin Schuhc243b422020-10-11 15:35:08 -070030TEST(SpanReaderTest, ReadWrite) {
31 const std::string logfile = aos::testing::TestTmpDir() + "/log.bfbs";
32 unlink(logfile.c_str());
33
34 const aos::SizePrefixedFlatbufferDetachedBuffer<TestMessage> m1 =
Austin Schuh4b5c22a2020-11-30 22:58:43 -080035 JsonToSizedFlatbuffer<TestMessage>(R"({ "value": 1 })");
Austin Schuhc243b422020-10-11 15:35:08 -070036 const aos::SizePrefixedFlatbufferDetachedBuffer<TestMessage> m2 =
Austin Schuh4b5c22a2020-11-30 22:58:43 -080037 JsonToSizedFlatbuffer<TestMessage>(R"({ "value": 2 })");
Austin Schuhc243b422020-10-11 15:35:08 -070038
39 {
40 DetachedBufferWriter writer(logfile, std::make_unique<DummyEncoder>());
Austin Schuhadd6eb32020-11-09 21:24:26 -080041 writer.QueueSpan(m1.span());
42 writer.QueueSpan(m2.span());
Austin Schuhc243b422020-10-11 15:35:08 -070043 }
44
45 SpanReader reader(logfile);
46
47 EXPECT_EQ(reader.filename(), logfile);
Austin Schuhadd6eb32020-11-09 21:24:26 -080048 EXPECT_EQ(reader.ReadMessage(), m1.span());
49 EXPECT_EQ(reader.ReadMessage(), m2.span());
Austin Schuhc243b422020-10-11 15:35:08 -070050 EXPECT_EQ(reader.ReadMessage(), absl::Span<const uint8_t>());
51}
52
Austin Schuhe243aaf2020-10-11 15:46:02 -070053// Tests that we can actually parse the resulting messages at a basic level
54// through MessageReader.
55TEST(MessageReaderTest, ReadWrite) {
56 const std::string logfile = aos::testing::TestTmpDir() + "/log.bfbs";
57 unlink(logfile.c_str());
58
59 const aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> config =
60 JsonToSizedFlatbuffer<LogFileHeader>(
61 R"({ "max_out_of_order_duration": 100000000 })");
62 const aos::SizePrefixedFlatbufferDetachedBuffer<MessageHeader> m1 =
63 JsonToSizedFlatbuffer<MessageHeader>(
64 R"({ "channel_index": 0, "monotonic_sent_time": 1 })");
65 const aos::SizePrefixedFlatbufferDetachedBuffer<MessageHeader> m2 =
66 JsonToSizedFlatbuffer<MessageHeader>(
67 R"({ "channel_index": 0, "monotonic_sent_time": 2 })");
68
69 {
70 DetachedBufferWriter writer(logfile, std::make_unique<DummyEncoder>());
Austin Schuhadd6eb32020-11-09 21:24:26 -080071 writer.QueueSpan(config.span());
72 writer.QueueSpan(m1.span());
73 writer.QueueSpan(m2.span());
Austin Schuhe243aaf2020-10-11 15:46:02 -070074 }
75
76 MessageReader reader(logfile);
77
78 EXPECT_EQ(reader.filename(), logfile);
79
80 EXPECT_EQ(
81 reader.max_out_of_order_duration(),
82 std::chrono::nanoseconds(config.message().max_out_of_order_duration()));
83 EXPECT_EQ(reader.newest_timestamp(), monotonic_clock::min_time);
84 EXPECT_TRUE(reader.ReadMessage());
85 EXPECT_EQ(reader.newest_timestamp(),
86 monotonic_clock::time_point(chrono::nanoseconds(1)));
87 EXPECT_TRUE(reader.ReadMessage());
88 EXPECT_EQ(reader.newest_timestamp(),
89 monotonic_clock::time_point(chrono::nanoseconds(2)));
90 EXPECT_FALSE(reader.ReadMessage());
91}
92
Austin Schuh32f68492020-11-08 21:45:51 -080093// Tests that we explode when messages are too far out of order.
94TEST(PartsMessageReaderDeathTest, TooFarOutOfOrder) {
95 const std::string logfile0 = aos::testing::TestTmpDir() + "/log0.bfbs";
96 unlink(logfile0.c_str());
97
98 const aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> config0 =
99 JsonToSizedFlatbuffer<LogFileHeader>(
100 R"({
101 "max_out_of_order_duration": 100000000,
102 "log_event_uuid": "30ef1283-81d7-4004-8c36-1c162dbcb2b2",
103 "parts_uuid": "2a05d725-5d5c-4c0b-af42-88de2f3c3876",
104 "parts_index": 0
105})");
106
107 const aos::SizePrefixedFlatbufferDetachedBuffer<MessageHeader> m1 =
108 JsonToSizedFlatbuffer<MessageHeader>(
109 R"({ "channel_index": 0, "monotonic_sent_time": 100000000 })");
110 const aos::SizePrefixedFlatbufferDetachedBuffer<MessageHeader> m2 =
111 JsonToSizedFlatbuffer<MessageHeader>(
112 R"({ "channel_index": 0, "monotonic_sent_time": 0 })");
113 const aos::SizePrefixedFlatbufferDetachedBuffer<MessageHeader> m3 =
114 JsonToSizedFlatbuffer<MessageHeader>(
115 R"({ "channel_index": 0, "monotonic_sent_time": -1 })");
116
117 {
118 DetachedBufferWriter writer(logfile0, std::make_unique<DummyEncoder>());
Austin Schuhadd6eb32020-11-09 21:24:26 -0800119 writer.QueueSpan(config0.span());
120 writer.QueueSpan(m1.span());
121 writer.QueueSpan(m2.span());
122 writer.QueueSpan(m3.span());
Austin Schuh32f68492020-11-08 21:45:51 -0800123 }
124
125 const std::vector<LogFile> parts = SortParts({logfile0});
126
127 PartsMessageReader reader(parts[0].parts[0]);
128
129 EXPECT_TRUE(reader.ReadMessage());
130 EXPECT_TRUE(reader.ReadMessage());
131 EXPECT_DEATH({ reader.ReadMessage(); }, "-0.000000001sec vs. 0.000000000sec");
132}
133
Austin Schuhc41603c2020-10-11 16:17:37 -0700134// Tests that we can transparently re-assemble part files with a
135// PartsMessageReader.
136TEST(PartsMessageReaderTest, ReadWrite) {
137 const std::string logfile0 = aos::testing::TestTmpDir() + "/log0.bfbs";
138 const std::string logfile1 = aos::testing::TestTmpDir() + "/log1.bfbs";
139 unlink(logfile0.c_str());
140 unlink(logfile1.c_str());
141
142 const aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> config0 =
143 JsonToSizedFlatbuffer<LogFileHeader>(
144 R"({
145 "max_out_of_order_duration": 100000000,
146 "log_event_uuid": "30ef1283-81d7-4004-8c36-1c162dbcb2b2",
147 "parts_uuid": "2a05d725-5d5c-4c0b-af42-88de2f3c3876",
148 "parts_index": 0
149})");
150 const aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> config1 =
151 JsonToSizedFlatbuffer<LogFileHeader>(
152 R"({
153 "max_out_of_order_duration": 200000000,
154 "monotonic_start_time": 0,
155 "realtime_start_time": 0,
156 "log_event_uuid": "30ef1283-81d7-4004-8c36-1c162dbcb2b2",
157 "parts_uuid": "2a05d725-5d5c-4c0b-af42-88de2f3c3876",
158 "parts_index": 1
159})");
160
161 const aos::SizePrefixedFlatbufferDetachedBuffer<MessageHeader> m1 =
162 JsonToSizedFlatbuffer<MessageHeader>(
163 R"({ "channel_index": 0, "monotonic_sent_time": 1 })");
164 const aos::SizePrefixedFlatbufferDetachedBuffer<MessageHeader> m2 =
165 JsonToSizedFlatbuffer<MessageHeader>(
166 R"({ "channel_index": 0, "monotonic_sent_time": 2 })");
167
168 {
169 DetachedBufferWriter writer(logfile0, std::make_unique<DummyEncoder>());
Austin Schuhadd6eb32020-11-09 21:24:26 -0800170 writer.QueueSpan(config0.span());
171 writer.QueueSpan(m1.span());
Austin Schuhc41603c2020-10-11 16:17:37 -0700172 }
173 {
174 DetachedBufferWriter writer(logfile1, std::make_unique<DummyEncoder>());
Austin Schuhadd6eb32020-11-09 21:24:26 -0800175 writer.QueueSpan(config1.span());
176 writer.QueueSpan(m2.span());
Austin Schuhc41603c2020-10-11 16:17:37 -0700177 }
178
179 const std::vector<LogFile> parts = SortParts({logfile0, logfile1});
180
181 PartsMessageReader reader(parts[0].parts[0]);
182
183 EXPECT_EQ(reader.filename(), logfile0);
184
185 // Confirm that the timestamps track, and the filename also updates.
186 // Read the first message.
187 EXPECT_EQ(reader.newest_timestamp(), monotonic_clock::min_time);
188 EXPECT_EQ(
189 reader.max_out_of_order_duration(),
190 std::chrono::nanoseconds(config0.message().max_out_of_order_duration()));
191 EXPECT_TRUE(reader.ReadMessage());
192 EXPECT_EQ(reader.filename(), logfile0);
193 EXPECT_EQ(reader.newest_timestamp(),
194 monotonic_clock::time_point(chrono::nanoseconds(1)));
195 EXPECT_EQ(
196 reader.max_out_of_order_duration(),
197 std::chrono::nanoseconds(config0.message().max_out_of_order_duration()));
198
199 // Read the second message.
200 EXPECT_TRUE(reader.ReadMessage());
201 EXPECT_EQ(reader.filename(), logfile1);
202 EXPECT_EQ(reader.newest_timestamp(),
203 monotonic_clock::time_point(chrono::nanoseconds(2)));
204 EXPECT_EQ(
205 reader.max_out_of_order_duration(),
206 std::chrono::nanoseconds(config1.message().max_out_of_order_duration()));
207
208 // And then confirm that reading again returns no message.
209 EXPECT_FALSE(reader.ReadMessage());
210 EXPECT_EQ(reader.filename(), logfile1);
211 EXPECT_EQ(
212 reader.max_out_of_order_duration(),
213 std::chrono::nanoseconds(config1.message().max_out_of_order_duration()));
Austin Schuh32f68492020-11-08 21:45:51 -0800214 EXPECT_EQ(reader.newest_timestamp(), monotonic_clock::max_time);
Austin Schuhc41603c2020-10-11 16:17:37 -0700215}
Austin Schuh32f68492020-11-08 21:45:51 -0800216
Austin Schuh1be0ce42020-11-29 22:43:26 -0800217// Tests that Message's operator < works as expected.
218TEST(MessageTest, Sorting) {
219 const aos::monotonic_clock::time_point e = monotonic_clock::epoch();
220
221 Message m1{.channel_index = 0,
222 .queue_index = 0,
223 .timestamp = e + chrono::milliseconds(1),
224 .data = SizePrefixedFlatbufferVector<MessageHeader>::Empty()};
225 Message m2{.channel_index = 0,
226 .queue_index = 0,
227 .timestamp = e + chrono::milliseconds(2),
228 .data = SizePrefixedFlatbufferVector<MessageHeader>::Empty()};
229
230 EXPECT_LT(m1, m2);
231 EXPECT_GE(m2, m1);
232
233 m1.timestamp = e;
234 m2.timestamp = e;
235
236 m1.channel_index = 1;
237 m2.channel_index = 2;
238
239 EXPECT_LT(m1, m2);
240 EXPECT_GE(m2, m1);
241
242 m1.channel_index = 0;
243 m2.channel_index = 0;
244 m1.queue_index = 0;
245 m2.queue_index = 1;
246
247 EXPECT_LT(m1, m2);
248 EXPECT_GE(m2, m1);
249}
250
Austin Schuh4b5c22a2020-11-30 22:58:43 -0800251aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> MakeHeader(
252 const aos::FlatbufferDetachedBuffer<Configuration> &config,
253 const std::string_view json) {
254 flatbuffers::FlatBufferBuilder fbb;
255 flatbuffers::Offset<Configuration> config_offset =
256 aos::CopyFlatBuffer(config, &fbb);
257 LogFileHeader::Builder header_builder(fbb);
258 header_builder.add_configuration(config_offset);
259 fbb.Finish(header_builder.Finish());
260 aos::FlatbufferDetachedBuffer<LogFileHeader> config_header(fbb.Release());
261
262 aos::FlatbufferDetachedBuffer<LogFileHeader> header_updates(
263 JsonToFlatbuffer<LogFileHeader>(json));
264 CHECK(header_updates.Verify());
265 flatbuffers::FlatBufferBuilder fbb2;
266 fbb2.FinishSizePrefixed(
267 aos::MergeFlatBuffers(config_header, header_updates, &fbb2));
268 return fbb2.Release();
269}
270
271class SortingElementTest : public ::testing::Test {
272 public:
273 SortingElementTest()
274 : config_(JsonToFlatbuffer<Configuration>(
275 R"({
276 "channels": [
277 {
278 "name": "/a",
279 "type": "aos.logger.testing.TestMessage",
280 "source_node": "pi1",
281 "destination_nodes": [
282 {
283 "name": "pi2"
284 },
285 {
286 "name": "pi3"
287 }
288 ]
289 },
290 {
291 "name": "/b",
292 "type": "aos.logger.testing.TestMessage",
293 "source_node": "pi1"
294 },
295 {
296 "name": "/c",
297 "type": "aos.logger.testing.TestMessage",
298 "source_node": "pi1"
299 }
300 ],
301 "nodes": [
302 {
303 "name": "pi1"
304 },
305 {
306 "name": "pi2"
307 },
308 {
309 "name": "pi3"
310 }
311 ]
312}
313)")),
314 config0_(MakeHeader(config_, R"({
315 /* 100ms */
316 "max_out_of_order_duration": 100000000,
317 "node": {
318 "name": "pi1"
319 },
320 "logger_node": {
321 "name": "pi1"
322 },
323 "monotonic_start_time": 0,
324 "realtime_start_time": 1000000000000,
325 "log_event_uuid": "30ef1283-81d7-4004-8c36-1c162dbcb2b2",
326 "parts_uuid": "2a05d725-5d5c-4c0b-af42-88de2f3c3876",
327 "parts_index": 0
328})")),
329 config1_(MakeHeader(config_,
330 R"({
331 /* 100ms */
332 "max_out_of_order_duration": 100000000,
333 "node": {
334 "name": "pi1"
335 },
336 "logger_node": {
337 "name": "pi1"
338 },
339 "monotonic_start_time": 0,
340 "realtime_start_time": 1000000000000,
341 "log_event_uuid": "d4724d35-a6c6-4a30-8a94-d192f4c18260",
342 "parts_uuid": "bafe9f8e-7dea-4bd9-95f5-3d8390e49208",
343 "parts_index": 0
344})")) {
345 unlink(logfile0_.c_str());
346 unlink(logfile1_.c_str());
347 queue_index_.resize(kChannels);
348 }
349
350 protected:
351 static constexpr size_t kChannels = 3u;
352
353 flatbuffers::DetachedBuffer MakeLogMessage(
354 const aos::monotonic_clock::time_point monotonic_now, int channel_index,
355 int value) {
356 flatbuffers::FlatBufferBuilder message_fbb;
357 message_fbb.ForceDefaults(true);
358 TestMessage::Builder test_message_builder(message_fbb);
359 test_message_builder.add_value(value);
360 message_fbb.Finish(test_message_builder.Finish());
361
362 aos::Context context;
363 context.monotonic_event_time = monotonic_now;
364 context.realtime_event_time = aos::realtime_clock::epoch() +
365 chrono::seconds(1000) +
366 monotonic_now.time_since_epoch();
367 context.queue_index = queue_index_[channel_index];
368 context.size = message_fbb.GetSize();
369 context.data = message_fbb.GetBufferPointer();
370
371 ++queue_index_[channel_index];
372
373 flatbuffers::FlatBufferBuilder fbb;
374 fbb.FinishSizePrefixed(
375 PackMessage(&fbb, context, channel_index, LogType::kLogMessage));
376
377 return fbb.Release();
378 }
379
380 flatbuffers::DetachedBuffer MakeTimestampMessage(
381 const aos::monotonic_clock::time_point sender_monotonic_now,
382 int channel_index, chrono::nanoseconds receiver_monotonic_offset) {
383 aos::Context context;
384 context.monotonic_remote_time = sender_monotonic_now;
385 context.realtime_remote_time = aos::realtime_clock::epoch() +
386 chrono::seconds(1000) +
387 sender_monotonic_now.time_since_epoch();
388 context.remote_queue_index = queue_index_[channel_index] - 1;
389 context.monotonic_event_time =
390 sender_monotonic_now + receiver_monotonic_offset;
391 context.realtime_event_time =
392 aos::realtime_clock::epoch() + chrono::seconds(1000) +
393 context.monotonic_event_time.time_since_epoch();
394 context.queue_index = queue_index_[channel_index] - 1 + 100;
395 context.size = 0;
396 context.data = nullptr;
397
398 flatbuffers::FlatBufferBuilder fbb;
399 fbb.FinishSizePrefixed(PackMessage(&fbb, context, channel_index,
400 LogType::kLogDeliveryTimeOnly));
401 LOG(INFO) << aos::FlatbufferToJson(
402 aos::SizePrefixedFlatbufferSpan<MessageHeader>(
403 absl::Span<uint8_t>(fbb.GetBufferPointer(), fbb.GetSize())));
404
405 return fbb.Release();
406 }
407
408 const std::string logfile0_ = aos::testing::TestTmpDir() + "/log0.bfbs";
409 const std::string logfile1_ = aos::testing::TestTmpDir() + "/log1.bfbs";
410
411 const aos::FlatbufferDetachedBuffer<Configuration> config_;
412 const aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> config0_;
413 const aos::SizePrefixedFlatbufferDetachedBuffer<LogFileHeader> config1_;
414
415 std::vector<uint32_t> queue_index_;
416};
417
418using LogPartsSorterTest = SortingElementTest;
419using LogPartsSorterDeathTest = LogPartsSorterTest;
420
421// Tests that we can pull messages out of a log sorted in order.
422TEST_F(LogPartsSorterTest, Pull) {
423 const aos::monotonic_clock::time_point e = monotonic_clock::epoch();
424 {
425 DetachedBufferWriter writer(logfile0_, std::make_unique<DummyEncoder>());
426 writer.QueueSpan(config0_.span());
427 writer.QueueSizedFlatbuffer(
428 MakeLogMessage(e + chrono::milliseconds(1000), 0, 0x005));
429 writer.QueueSizedFlatbuffer(
430 MakeLogMessage(e + chrono::milliseconds(1000), 1, 0x105));
431 writer.QueueSizedFlatbuffer(
432 MakeLogMessage(e + chrono::milliseconds(2000), 0, 0x006));
433 writer.QueueSizedFlatbuffer(
434 MakeLogMessage(e + chrono::milliseconds(1901), 1, 0x107));
435 }
436
437 const std::vector<LogFile> parts = SortParts({logfile0_});
438
439 LogPartsSorter parts_sorter(parts[0].parts[0]);
440
441 // Confirm we aren't sorted until any time until the message is popped.
442 // Peeking shouldn't change the sorted until time.
443 EXPECT_EQ(parts_sorter.sorted_until(), monotonic_clock::min_time);
444
445 std::deque<Message> output;
446
447 ASSERT_TRUE(parts_sorter.Front() != nullptr);
448 output.emplace_back(std::move(*parts_sorter.Front()));
449 parts_sorter.PopFront();
450 EXPECT_EQ(parts_sorter.sorted_until(), e + chrono::milliseconds(1900));
451
452 ASSERT_TRUE(parts_sorter.Front() != nullptr);
453 output.emplace_back(std::move(*parts_sorter.Front()));
454 parts_sorter.PopFront();
455 EXPECT_EQ(parts_sorter.sorted_until(), e + chrono::milliseconds(1900));
456
457 ASSERT_TRUE(parts_sorter.Front() != nullptr);
458 output.emplace_back(std::move(*parts_sorter.Front()));
459 parts_sorter.PopFront();
460 EXPECT_EQ(parts_sorter.sorted_until(), monotonic_clock::max_time);
461
462 ASSERT_TRUE(parts_sorter.Front() != nullptr);
463 output.emplace_back(std::move(*parts_sorter.Front()));
464 parts_sorter.PopFront();
465 EXPECT_EQ(parts_sorter.sorted_until(), monotonic_clock::max_time);
466
467 ASSERT_TRUE(parts_sorter.Front() == nullptr);
468
469 EXPECT_EQ(output[0].timestamp, e + chrono::milliseconds(1000));
470 EXPECT_EQ(output[1].timestamp, e + chrono::milliseconds(1000));
471 EXPECT_EQ(output[2].timestamp, e + chrono::milliseconds(1901));
472 EXPECT_EQ(output[3].timestamp, e + chrono::milliseconds(2000));
473}
474
475// Tests that messages too far out of order trigger death.
476TEST_F(LogPartsSorterDeathTest, Pull) {
477 const aos::monotonic_clock::time_point e = monotonic_clock::epoch();
478 {
479 DetachedBufferWriter writer(logfile0_, std::make_unique<DummyEncoder>());
480 writer.QueueSpan(config0_.span());
481 writer.QueueSizedFlatbuffer(
482 MakeLogMessage(e + chrono::milliseconds(1000), 0, 0x005));
483 writer.QueueSizedFlatbuffer(
484 MakeLogMessage(e + chrono::milliseconds(1000), 1, 0x105));
485 writer.QueueSizedFlatbuffer(
486 MakeLogMessage(e + chrono::milliseconds(2001), 0, 0x006));
487 // The following message is too far out of order and will trigger the CHECK.
488 writer.QueueSizedFlatbuffer(
489 MakeLogMessage(e + chrono::milliseconds(1900), 1, 0x107));
490 }
491
492 const std::vector<LogFile> parts = SortParts({logfile0_});
493
494 LogPartsSorter parts_sorter(parts[0].parts[0]);
495
496 // Confirm we aren't sorted until any time until the message is popped.
497 // Peeking shouldn't change the sorted until time.
498 EXPECT_EQ(parts_sorter.sorted_until(), monotonic_clock::min_time);
499 std::deque<Message> output;
500
501 ASSERT_TRUE(parts_sorter.Front() != nullptr);
502 parts_sorter.PopFront();
503 ASSERT_TRUE(parts_sorter.Front() != nullptr);
504 ASSERT_TRUE(parts_sorter.Front() != nullptr);
505 parts_sorter.PopFront();
506
507 EXPECT_DEATH({ parts_sorter.Front(); }, "Max out of order exceeded.");
508}
509
Austin Schuhc243b422020-10-11 15:35:08 -0700510} // namespace testing
511} // namespace logger
512} // namespace aos