Add a sent too fast check for simulation and shm

Returns an error if more than queue_size (frequency *
channel_storage_duration) messages were sent in one
channel_storage_duration.

Signed-off-by: Eric Schmiedeberg <eric.schmiedeberg@bluerivertech.com>
Change-Id: Ie41205ba37b66930d8a9082f2d85d7dc3388e3bf
diff --git a/aos/events/simulated_event_loop_test.cc b/aos/events/simulated_event_loop_test.cc
index 09202ff..a83243d 100644
--- a/aos/events/simulated_event_loop_test.cc
+++ b/aos/events/simulated_event_loop_test.cc
@@ -1,6 +1,7 @@
 #include "aos/events/simulated_event_loop.h"
 
 #include <chrono>
+#include <functional>
 #include <string_view>
 
 #include "aos/events/event_loop_param_test.h"
@@ -139,13 +140,13 @@
 };
 
 class FunctionEvent : public EventScheduler::Event {
-  public:
-   FunctionEvent(std::function<void()> fn) : fn_(fn) {}
+ public:
+  FunctionEvent(std::function<void()> fn) : fn_(fn) {}
 
-   void Handle() noexcept override { fn_(); }
+  void Handle() noexcept override { fn_(); }
 
-  private:
-   std::function<void()> fn_;
+ private:
+  std::function<void()> fn_;
 };
 
 // Test that creating an event and running the scheduler runs the event.
@@ -204,14 +205,6 @@
   EXPECT_EQ(counter, 1);
 }
 
-void SendTestMessage(aos::Sender<TestMessage> *sender, int value) {
-  aos::Sender<TestMessage>::Builder builder = sender->MakeBuilder();
-  TestMessage::Builder test_message_builder =
-      builder.MakeBuilder<TestMessage>();
-  test_message_builder.add_value(value);
-  ASSERT_EQ(builder.Send(test_message_builder.Finish()), RawSender::Error::kOk);
-}
-
 // Test that sending a message after running gets properly notified.
 TEST(SimulatedEventLoopTest, SendAfterRunFor) {
   SimulatedEventLoopTestFactory factory;
@@ -223,7 +216,7 @@
       simulated_event_loop_factory.MakeEventLoop("ping");
   aos::Sender<TestMessage> test_message_sender =
       ping_event_loop->MakeSender<TestMessage>("/test");
-  SendTestMessage(&test_message_sender, 1);
+  ASSERT_EQ(SendTestMessage(test_message_sender), RawSender::Error::kOk);
 
   std::unique_ptr<EventLoop> pong1_event_loop =
       simulated_event_loop_factory.MakeEventLoop("pong");
@@ -243,7 +236,7 @@
 
   // Pauses in the middle don't count though, so this should be counted.
   // But, the fresh watcher shouldn't pick it up yet.
-  SendTestMessage(&test_message_sender, 2);
+  ASSERT_EQ(SendTestMessage(test_message_sender), RawSender::Error::kOk);
 
   EXPECT_EQ(test_message_counter1.count(), 0u);
   EXPECT_EQ(test_message_counter2.count(), 0u);
@@ -253,6 +246,63 @@
   EXPECT_EQ(test_message_counter2.count(), 0u);
 }
 
+void TestSentTooFastCheckEdgeCase(
+    const std::function<RawSender::Error(int, int)> expected_err,
+    const bool send_twice_at_end) {
+  SimulatedEventLoopTestFactory factory;
+
+  auto event_loop = factory.MakePrimary("primary");
+
+  auto sender = event_loop->MakeSender<TestMessage>("/test");
+
+  const int queue_size = TestChannelQueueSize(event_loop.get());
+  int msgs_sent = 0;
+  event_loop->AddPhasedLoop(
+      [&](int) {
+        EXPECT_EQ(SendTestMessage(sender), expected_err(msgs_sent, queue_size));
+        msgs_sent++;
+
+        // If send_twice_at_end, send the last two messages (message
+        // queue_size and queue_size + 1) in the same iteration, meaning that
+        // we would be sending very slightly too fast. Otherwise, we will send
+        // message queue_size + 1 in the next iteration and we will continue
+        // to be sending exactly at the channel frequency.
+        if (send_twice_at_end && (msgs_sent == queue_size)) {
+          EXPECT_EQ(SendTestMessage(sender),
+                    expected_err(msgs_sent, queue_size));
+          msgs_sent++;
+        }
+
+        if (msgs_sent > queue_size) {
+          factory.Exit();
+        }
+      },
+      std::chrono::duration_cast<std::chrono::nanoseconds>(
+          std::chrono::duration<double>(
+              1.0 / TestChannelFrequency(event_loop.get()))));
+
+  factory.Run();
+}
+
+// Tests that RawSender::Error::kMessagesSentTooFast is not returned
+// when messages are sent at the exact frequency of the channel.
+TEST(SimulatedEventLoopTest, SendingAtExactlyChannelFrequency) {
+  TestSentTooFastCheckEdgeCase([](int, int) { return RawSender::Error::kOk; },
+                               false);
+}
+
+// Tests that RawSender::Error::kMessagesSentTooFast is returned
+// when sending exactly one more message than allowed in a channel storage
+// duration.
+TEST(SimulatedEventLoopTest, SendingSlightlyTooFast) {
+  TestSentTooFastCheckEdgeCase(
+      [](const int msgs_sent, const int queue_size) {
+        return (msgs_sent == queue_size ? RawSender::Error::kMessagesSentTooFast
+                                        : RawSender::Error::kOk);
+      },
+      true);
+}
+
 // Test that creating an event loop while running dies.
 TEST(SimulatedEventLoopDeathTest, MakeEventLoopWhileRunning) {
   SimulatedEventLoopTestFactory factory;
@@ -1338,7 +1388,6 @@
   EXPECT_EQ(ConnectedCount(pi3_client_statistics_fetcher.get(), "pi1"), 2u)
       << " : " << aos::FlatbufferToJson(pi3_client_statistics_fetcher.get());
 
-
   EXPECT_EQ(pi1_pong_counter.count(), 601u);
   EXPECT_EQ(pi2_pong_counter.count(), 601u);
 
@@ -1707,18 +1756,17 @@
       });
 
   // Confirm that reboot changes the UUID.
-  pi2->OnShutdown(
-      [&expected_boot_uuid, &boot_number, &expected_connection_time, pi1, pi2,
-       pi2_boot1]() {
-        expected_boot_uuid = pi2_boot1;
-        ++boot_number;
-        LOG(INFO) << "OnShutdown triggered for pi2";
-        pi2->OnStartup(
-            [&expected_boot_uuid, &expected_connection_time, pi1, pi2]() {
-              EXPECT_EQ(expected_boot_uuid, pi2->boot_uuid());
-              expected_connection_time = pi1->monotonic_now();
-            });
-      });
+  pi2->OnShutdown([&expected_boot_uuid, &boot_number, &expected_connection_time,
+                   pi1, pi2, pi2_boot1]() {
+    expected_boot_uuid = pi2_boot1;
+    ++boot_number;
+    LOG(INFO) << "OnShutdown triggered for pi2";
+    pi2->OnStartup(
+        [&expected_boot_uuid, &expected_connection_time, pi1, pi2]() {
+          EXPECT_EQ(expected_boot_uuid, pi2->boot_uuid());
+          expected_connection_time = pi1->monotonic_now();
+        });
+  });
 
   // Let a couple of ServerStatistics messages show up before rebooting.
   factory.RunFor(chrono::milliseconds(2002));