Fix simulation sent_time and add a test

It was hard-coded to the actual monotonic_clock::now() call, which
doesn't work well with actual simulation when you don't use fake time.
And we want to kill fake time.

Change-Id: If5785679d54100e5021bea86df763d98d44f7c3d
diff --git a/aos/events/BUILD b/aos/events/BUILD
index e0e6bad..dc5ac9c 100644
--- a/aos/events/BUILD
+++ b/aos/events/BUILD
@@ -56,20 +56,21 @@
 )
 
 cc_test(
-    name = "simulated-event-loop_test",
+    name = "simulated_event_loop_test",
     testonly = True,
     srcs = ["simulated-event-loop_test.cc"],
     deps = [
         ":event-loop_param_test",
-        ":simulated-event-loop",
+        ":simulated_event_loop",
         "//aos/testing:googletest",
     ],
 )
 
 cc_library(
-    name = "simulated-event-loop",
+    name = "simulated_event_loop",
     srcs = ["simulated-event-loop.cc"],
     hdrs = ["simulated-event-loop.h"],
+    visibility = ["//visibility:public"],
     deps = [
         ":event-loop",
         "//aos:queues",
diff --git a/aos/events/event-loop.h b/aos/events/event-loop.h
index 908718d..2a3673e 100644
--- a/aos/events/event-loop.h
+++ b/aos/events/event-loop.h
@@ -67,9 +67,6 @@
     // if the message was successfully sent, and false otherwise.
     bool Send() {
       RawSender *sender = &msg_.get_deleter();
-      // TODO(austin): This lets multiple senders reorder messages since time
-      // isn't acquired with a lock held.
-      msg_->SetTimeToNow();
       return sender->Send(
           reinterpret_cast<RawSender::SendContext *>(msg_.release()));
     }
diff --git a/aos/events/event-loop_param_test.cc b/aos/events/event-loop_param_test.cc
index efac8f9..aa03643 100644
--- a/aos/events/event-loop_param_test.cc
+++ b/aos/events/event-loop_param_test.cc
@@ -7,7 +7,10 @@
   enum { kQueueLength = 100, kHash = 0x696c0cdc };
   int msg_value;
 
-  void Zero() { msg_value = 0; }
+  void Zero() {
+    ::aos::Message::Zero();
+    msg_value = 0;
+  }
   static size_t Size() { return 1 + ::aos::Message::Size(); }
   size_t Print(char *buffer, size_t length) const;
   TestMessage() { Zero(); }
@@ -168,5 +171,37 @@
 
   EXPECT_EQ(iteration_list.size(), 3);
 }
+
+// Verify that the send time on a message is roughly right.
+TEST_P(AbstractEventLoopTest, MessageSendTime) {
+  auto loop1 = Make();
+  auto loop2 = Make();
+  auto sender = loop1->MakeSender<TestMessage>("/test");
+  auto fetcher = loop2->MakeFetcher<TestMessage>("/test");
+
+  auto test_timer = loop1->AddTimer([&sender]() {
+    auto msg = sender.MakeMessage();
+    msg->msg_value = 200;
+    msg.Send();
+  });
+
+  test_timer->Setup(loop1->monotonic_now() + ::std::chrono::seconds(1));
+
+  EndEventLoop(loop1.get(), ::std::chrono::seconds(2));
+  loop1->Run();
+
+  EXPECT_TRUE(fetcher.Fetch());
+
+  monotonic_clock::duration time_offset =
+      fetcher->sent_time - (loop1->monotonic_now() - ::std::chrono::seconds(1));
+
+  EXPECT_TRUE(time_offset > ::std::chrono::milliseconds(-500))
+      << ": Got " << fetcher->sent_time.time_since_epoch().count() << " expected "
+      << loop1->monotonic_now().time_since_epoch().count();
+  EXPECT_TRUE(time_offset < ::std::chrono::milliseconds(500))
+      << ": Got " << fetcher->sent_time.time_since_epoch().count()
+      << " expected " << loop1->monotonic_now().time_since_epoch().count();
+}
+
 }  // namespace testing
 }  // namespace aos
diff --git a/aos/events/shm-event-loop.cc b/aos/events/shm-event-loop.cc
index a70d6f3..c9ff6fd 100644
--- a/aos/events/shm-event-loop.cc
+++ b/aos/events/shm-event-loop.cc
@@ -71,6 +71,14 @@
 
   bool Send(SendContext *msg) override {
     assert(queue_ != NULL);
+    {
+      ::aos::Message *aos_msg = reinterpret_cast<Message *>(msg);
+      // TODO(austin): This lets multiple senders reorder messages since time
+      // isn't acquired with a lock held.
+      if (aos_msg->sent_time == monotonic_clock::min_time) {
+        aos_msg->sent_time = monotonic_clock::now();
+      }
+    }
     return queue_->WriteMessage(msg, RawQueue::kOverride);
   }
 
diff --git a/aos/events/simulated-event-loop.cc b/aos/events/simulated-event-loop.cc
index 5fe1bf5..02d15a6 100644
--- a/aos/events/simulated-event-loop.cc
+++ b/aos/events/simulated-event-loop.cc
@@ -35,7 +35,8 @@
 
 class SimulatedSender : public RawSender {
  public:
-  SimulatedSender(SimulatedQueue *queue) : queue_(queue) {}
+  SimulatedSender(SimulatedQueue *queue, EventLoop *event_loop)
+      : queue_(queue), event_loop_(event_loop) {}
   ~SimulatedSender() {}
 
   SendContext *GetContext() override {
@@ -48,6 +49,12 @@
   }
 
   bool Send(SendContext *context) override {
+    {
+      ::aos::Message *aos_msg = reinterpret_cast<Message *>(context);
+      if (aos_msg->sent_time == monotonic_clock::min_time) {
+        aos_msg->sent_time = event_loop_->monotonic_now();
+      }
+    }
     queue_->Send(RefCountedBuffer(reinterpret_cast<aos::Message *>(context)));
     return true;  // Maybe false instead? :)
   }
@@ -56,9 +63,114 @@
 
  private:
   SimulatedQueue *queue_;
+  EventLoop *event_loop_;
 };
 }  // namespace
 
+class SimulatedTimerHandler : public TimerHandler {
+ public:
+  explicit SimulatedTimerHandler(EventScheduler *scheduler,
+                                 ::std::function<void()> fn)
+      : scheduler_(scheduler), fn_(fn) {}
+  ~SimulatedTimerHandler() {}
+
+  void Setup(monotonic_clock::time_point base,
+             monotonic_clock::duration repeat_offset) override {
+    Disable();
+    const ::aos::monotonic_clock::time_point monotonic_now =
+        scheduler_->monotonic_now();
+    base_ = base;
+    repeat_offset_ = repeat_offset;
+    if (base < monotonic_now) {
+      token_ = scheduler_->Schedule(monotonic_now, [this]() { HandleEvent(); });
+    } else {
+      token_ = scheduler_->Schedule(base, [this]() { HandleEvent(); });
+    }
+  }
+
+  void HandleEvent() {
+    const ::aos::monotonic_clock::time_point monotonic_now =
+        scheduler_->monotonic_now();
+    if (repeat_offset_ != ::aos::monotonic_clock::zero()) {
+      // Reschedule.
+      while (base_ <= monotonic_now) base_ += repeat_offset_;
+      token_ = scheduler_->Schedule(base_, [this]() { HandleEvent(); });
+    } else {
+      token_ = EventScheduler::Token();
+    }
+    fn_();
+  }
+
+  void Disable() override {
+    if (token_ != EventScheduler::Token()) {
+      scheduler_->Deschedule(token_);
+      token_ = EventScheduler::Token();
+    }
+  }
+
+ private:
+  EventScheduler *scheduler_;
+  EventScheduler::Token token_;
+  // Function to be run on the thread
+  ::std::function<void()> fn_;
+  monotonic_clock::time_point base_;
+  monotonic_clock::duration repeat_offset_;
+};
+
+
+class SimulatedEventLoop : public EventLoop {
+ public:
+  explicit SimulatedEventLoop(
+      EventScheduler *scheduler,
+      ::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue>
+          *queues)
+      : scheduler_(scheduler), queues_(queues) {}
+  ~SimulatedEventLoop() override {};
+
+  ::aos::monotonic_clock::time_point monotonic_now() override {
+    return scheduler_->monotonic_now();
+  }
+
+  ::std::unique_ptr<RawSender> MakeRawSender(
+      const ::std::string &path, const QueueTypeInfo &type) override;
+
+  ::std::unique_ptr<RawFetcher> MakeRawFetcher(
+      const ::std::string &path, const QueueTypeInfo &type) override;
+
+  void MakeRawWatcher(
+      const ::std::string &path, const QueueTypeInfo &type,
+      ::std::function<void(const ::aos::Message *message)> watcher) override;
+
+  TimerHandler *AddTimer(::std::function<void()> callback) override {
+    timers_.emplace_back(new SimulatedTimerHandler(scheduler_, callback));
+    return timers_.back().get();
+  }
+
+  void OnRun(::std::function<void()> on_run) override {
+    scheduler_->Schedule(scheduler_->monotonic_now(), on_run);
+  }
+  void Run() override {
+    set_is_running(true);
+    scheduler_->Run();
+  }
+  void Exit() override {
+    set_is_running(false);
+    scheduler_->Exit();
+  }
+
+  SimulatedQueue *GetSimulatedQueue(
+      const ::std::pair<::std::string, QueueTypeInfo> &);
+
+  void Take(const ::std::string &path);
+
+ private:
+  EventScheduler *scheduler_;
+  ::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue>
+      *queues_;
+  ::std::vector<std::string> taken_;
+  ::std::vector<std::unique_ptr<TimerHandler>> timers_;
+};
+
 EventScheduler::Token EventScheduler::Schedule(
     ::aos::monotonic_clock::time_point time, ::std::function<void()> callback) {
   return events_list_.emplace(time, callback);
@@ -91,7 +203,7 @@
     const std::string &path, const QueueTypeInfo &type) {
   Take(path);
   ::std::pair<::std::string, QueueTypeInfo> key(path, type);
-  return GetSimulatedQueue(key)->MakeRawSender();
+  return GetSimulatedQueue(key)->MakeRawSender(this);
 }
 
 std::unique_ptr<RawFetcher> SimulatedEventLoop::MakeRawFetcher(
@@ -117,8 +229,9 @@
   watchers_.push_back(watcher);
 }
 
-std::unique_ptr<RawSender> SimulatedQueue::MakeRawSender() {
-  return std::unique_ptr<RawSender>(new SimulatedSender(this));
+std::unique_ptr<RawSender> SimulatedQueue::MakeRawSender(
+    EventLoop *event_loop) {
+  return std::unique_ptr<RawSender>(new SimulatedSender(this, event_loop));
 }
 
 std::unique_ptr<RawFetcher> SimulatedQueue::MakeRawFetcher() {
@@ -136,4 +249,10 @@
     taken_.emplace_back(path);
   }
 }
+
+::std::unique_ptr<EventLoop> SimulatedEventLoopFactory::MakeEventLoop() {
+  return ::std::unique_ptr<EventLoop>(
+      new SimulatedEventLoop(&scheduler_, &queues_));
+}
+
 }  // namespace aos
diff --git a/aos/events/simulated-event-loop.h b/aos/events/simulated-event-loop.h
index b5c94bf..9a0aa6e 100644
--- a/aos/events/simulated-event-loop.h
+++ b/aos/events/simulated-event-loop.h
@@ -95,7 +95,7 @@
 
   void Exit() { is_running_ = false; }
 
-  ::aos::monotonic_clock::time_point now() { return now_; }
+  ::aos::monotonic_clock::time_point monotonic_now() const { return now_; }
 
  private:
   ::aos::monotonic_clock::time_point now_ = ::aos::monotonic_clock::epoch();
@@ -109,17 +109,18 @@
                           EventScheduler *scheduler)
       : type_(type), name_(name), scheduler_(scheduler){};
 
-  std::unique_ptr<RawSender> MakeRawSender();
+  ::std::unique_ptr<RawSender> MakeRawSender(EventLoop *event_loop);
 
-  std::unique_ptr<RawFetcher> MakeRawFetcher();
+  ::std::unique_ptr<RawFetcher> MakeRawFetcher();
 
-  void MakeRawWatcher(std::function<void(const aos::Message *message)> watcher);
+  void MakeRawWatcher(
+      ::std::function<void(const ::aos::Message *message)> watcher);
 
   void Send(RefCountedBuffer message) {
     index_++;
     latest_message_ = message;
     for (auto &watcher : watchers_) {
-      scheduler_->Schedule(scheduler_->now(),
+      scheduler_->Schedule(scheduler_->monotonic_now(),
                            [watcher, message]() { watcher(message.get()); });
     }
   }
@@ -141,116 +142,21 @@
   EventScheduler *scheduler_;
 };
 
-class SimulatedTimerHandler : public TimerHandler {
- public:
-  explicit SimulatedTimerHandler(EventScheduler *scheduler,
-                                 ::std::function<void()> fn)
-      : scheduler_(scheduler), fn_(fn) {}
-  ~SimulatedTimerHandler() {}
-
-  void Setup(monotonic_clock::time_point base,
-             monotonic_clock::duration repeat_offset) override {
-    Disable();
-    auto now = scheduler_->now();
-    base_ = base;
-    repeat_offset_ = repeat_offset;
-    if (base < now) {
-      token_ = scheduler_->Schedule(now, [this]() { HandleEvent(); });
-    } else {
-      token_ = scheduler_->Schedule(base, [this]() { HandleEvent(); });
-    }
-  }
-
-  void HandleEvent() {
-    auto now = scheduler_->now();
-    if (repeat_offset_ != ::aos::monotonic_clock::zero()) {
-      // Reschedule.
-      while (base_ <= now) base_ += repeat_offset_;
-      token_ = scheduler_->Schedule(base_, [this]() { HandleEvent(); });
-    } else {
-      token_ = EventScheduler::Token();
-    }
-    fn_();
-  }
-
-  void Disable() override {
-    if (token_ != EventScheduler::Token()) {
-      scheduler_->Deschedule(token_);
-      token_ = EventScheduler::Token();
-    }
-  }
-
- private:
-  EventScheduler *scheduler_;
-  EventScheduler::Token token_;
-  // Function to be run on the thread
-  ::std::function<void()> fn_;
-  monotonic_clock::time_point base_;
-  monotonic_clock::duration repeat_offset_;
-};
-
-class SimulatedEventLoop : public EventLoop {
- public:
-  explicit SimulatedEventLoop(
-      EventScheduler *scheduler,
-      ::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue>
-          *queues) : scheduler_(scheduler), queues_(queues){};
-  ~SimulatedEventLoop() override{};
-
-  ::aos::monotonic_clock::time_point monotonic_now() override {
-    return scheduler_->now();
-  }
-
-  std::unique_ptr<RawSender> MakeRawSender(const std::string &path,
-                                           const QueueTypeInfo &type) override;
-
-  std::unique_ptr<RawFetcher> MakeRawFetcher(
-      const std::string &path, const QueueTypeInfo &type) override;
-
-  void MakeRawWatcher(
-      const std::string &path, const QueueTypeInfo &type,
-      std::function<void(const aos::Message *message)> watcher) override;
-
-  TimerHandler *AddTimer(::std::function<void()> callback) override {
-    timers_.emplace_back(new SimulatedTimerHandler(scheduler_, callback));
-    return timers_.back().get();
-  }
-
-  void OnRun(std::function<void()> on_run) override {
-    scheduler_->Schedule(scheduler_->now(), on_run);
-  }
-  void Run() override {
-    set_is_running(true);
-    scheduler_->Run();
-  }
-  void Exit() override {
-    set_is_running(false);
-    scheduler_->Exit();
-  }
-
-  SimulatedQueue *GetSimulatedQueue(
-      const ::std::pair<::std::string, QueueTypeInfo> &);
-
-  void Take(const ::std::string &path);
-
- private:
-  EventScheduler *scheduler_;
-  ::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue>
-      *queues_;
-  ::std::vector<std::string> taken_;
-  ::std::vector<std::unique_ptr<TimerHandler>> timers_;
-};
-
 class SimulatedEventLoopFactory {
  public:
-  ::std::unique_ptr<EventLoop> CreateEventLoop() {
-    return ::std::unique_ptr<EventLoop>(
-        new SimulatedEventLoop(&scheduler_, &queues_));
+  ::std::unique_ptr<EventLoop> MakeEventLoop();
+
+  void Run() { scheduler_.Run(); }
+
+  monotonic_clock::time_point monotonic_now() const {
+    return scheduler_.monotonic_now();
   }
 
  private:
   EventScheduler scheduler_;
   ::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue> queues_;
 };
+
 }  // namespace aos
+
 #endif  //_AOS_EVENTS_TEST_EVENT_LOOP_H_
diff --git a/aos/events/simulated-event-loop_test.cc b/aos/events/simulated-event-loop_test.cc
index 7c11b4a..f652fd9 100644
--- a/aos/events/simulated-event-loop_test.cc
+++ b/aos/events/simulated-event-loop_test.cc
@@ -5,10 +5,12 @@
 namespace aos {
 namespace testing {
 
+namespace chrono = ::std::chrono;
+
 class SimulatedEventLoopTestFactory : public EventLoopTestFactory {
  public:
-  std::unique_ptr<EventLoop> Make() override {
-    return event_loop.CreateEventLoop();
+  ::std::unique_ptr<EventLoop> Make() override {
+    return event_loop.MakeEventLoop();
   }
  private:
    SimulatedEventLoopFactory event_loop;