Merge "Fix action_test to not require watchers to watch while not running"
diff --git a/aos/actions/action_test.cc b/aos/actions/action_test.cc
index fa1a347..124b3e4 100644
--- a/aos/actions/action_test.cc
+++ b/aos/actions/action_test.cc
@@ -108,6 +108,11 @@
     ::aos::testing::EnableTestLogging();
   }
 
+  void RunAt(monotonic_clock::time_point exec_time, std::function<void()> fn) {
+    TimerHandler *timer = test_event_loop_->AddTimer(fn);
+    test_event_loop_->OnRun([timer, exec_time]() { timer->Setup(exec_time); });
+  }
+
   FlatbufferDetachedBuffer<Configuration> configuration_;
 
   // Bring up and down Core.
@@ -158,32 +163,35 @@
 
   ASSERT_FALSE(status_fetcher.Fetch());
 
-  event_loop_factory_.RunFor(chrono::seconds(1));
+  RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
+    ASSERT_TRUE(status_fetcher.Fetch());
+    EXPECT_EQ(0u, status_fetcher->running());
+    EXPECT_EQ(0u, status_fetcher->last_running());
 
-  ASSERT_TRUE(status_fetcher.Fetch());
-  EXPECT_EQ(0u, status_fetcher->running());
-  EXPECT_EQ(0u, status_fetcher->last_running());
+    {
+      UIntT uint;
+      uint.val = 0;
+      action_queue.EnqueueAction(nop_actor_factory.Make(uint));
+    }
 
-  {
-    UIntT uint;
-    uint.val = 0;
-    action_queue.EnqueueAction(nop_actor_factory.Make(uint));
-  }
+    // We started an action and it should be running.
+    EXPECT_TRUE(action_queue.Running());
 
-  // We started an action and it should be running.
-  EXPECT_TRUE(action_queue.Running());
+    action_queue.CancelAllActions();
+    action_queue.Tick();
 
-  action_queue.CancelAllActions();
-  action_queue.Tick();
-
-  EXPECT_TRUE(action_queue.Running());
+    EXPECT_TRUE(action_queue.Running());
+  });
 
   // Run the action so it can signal completion.
-  event_loop_factory_.RunFor(chrono::seconds(1));
-  action_queue.Tick();
+  RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
+    action_queue.Tick();
 
-  // Make sure it stopped.
-  EXPECT_FALSE(action_queue.Running());
+    // Make sure it stopped.
+    EXPECT_FALSE(action_queue.Running());
+  });
+
+  event_loop_factory_.RunFor(chrono::seconds(3));
 }
 
 // Tests that an action starts and stops.
@@ -196,29 +204,33 @@
   ActionQueue action_queue;
 
   // Tick an empty queue and make sure it was not running.
-  event_loop_factory_.RunFor(chrono::seconds(1));
-  action_queue.Tick();
-  EXPECT_FALSE(action_queue.Running());
+  RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
+    action_queue.Tick();
+    EXPECT_FALSE(action_queue.Running());
 
-  {
-    UIntT uint;
-    uint.val = 0;
-    action_queue.EnqueueAction(nop_actor_factory.Make(uint));
-  }
+    {
+      UIntT uint;
+      uint.val = 0;
+      action_queue.EnqueueAction(nop_actor_factory.Make(uint));
+    }
 
-  // We started an action and it should be running.
-  EXPECT_TRUE(action_queue.Running());
+    // We started an action and it should be running.
+    EXPECT_TRUE(action_queue.Running());
 
-  // Tick it and make sure it is still running.
-  action_queue.Tick();
-  EXPECT_TRUE(action_queue.Running());
+    // Tick it and make sure it is still running.
+    action_queue.Tick();
+    EXPECT_TRUE(action_queue.Running());
+  });
 
   // Run the action so it can signal completion.
-  event_loop_factory_.RunFor(chrono::seconds(1));
-  action_queue.Tick();
+  RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
+    action_queue.Tick();
 
-  // Make sure it stopped.
-  EXPECT_FALSE(action_queue.Running());
+    // Make sure it stopped.
+    EXPECT_FALSE(action_queue.Running());
+  });
+
+  event_loop_factory_.RunFor(chrono::seconds(3));
 }
 
 // Tests that we can cancel two actions and have them both stop.
@@ -231,52 +243,55 @@
   ActionQueue action_queue;
 
   // Let the actor and action queue start up and confirm nothing is running.
-  event_loop_factory_.RunFor(chrono::seconds(1));
-  action_queue.Tick();
+  RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
+    action_queue.Tick();
 
-  EXPECT_FALSE(action_queue.Running());
+    EXPECT_FALSE(action_queue.Running());
 
-  // Enqueue two actions to test both cancel. We can have an action and a next
-  // action so we want to test that.
-  {
-    UIntT uint;
-    uint.val = 0;
-    action_queue.EnqueueAction(nop_actor_factory.Make(uint));
-    action_queue.EnqueueAction(nop_actor_factory.Make(uint));
-  }
+    // Enqueue two actions to test both cancel. We can have an action and a next
+    // action so we want to test that.
+    {
+      UIntT uint;
+      uint.val = 0;
+      action_queue.EnqueueAction(nop_actor_factory.Make(uint));
+      action_queue.EnqueueAction(nop_actor_factory.Make(uint));
+    }
 
-  action_queue.Tick();
+    action_queue.Tick();
 
-  // Check that current and next exist.
-  EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, nullptr, nullptr,
+    // Check that current and next exist.
+    EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, nullptr, nullptr,
+                                                   nullptr, nullptr, nullptr));
+    EXPECT_TRUE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
+                                                nullptr, nullptr, nullptr));
+
+    action_queue.CancelAllActions();
+    action_queue.Tick();
+
+    // It should still be running as the actor could not have signaled.
+    EXPECT_TRUE(action_queue.Running());
+
+    bool sent_started, sent_cancel, interrupted;
+    EXPECT_TRUE(action_queue.GetCurrentActionState(
+        nullptr, &sent_started, &sent_cancel, &interrupted, nullptr, nullptr));
+    EXPECT_TRUE(sent_started);
+    EXPECT_TRUE(sent_cancel);
+    EXPECT_FALSE(interrupted);
+
+    EXPECT_FALSE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
                                                  nullptr, nullptr, nullptr));
-  EXPECT_TRUE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
-                                              nullptr, nullptr, nullptr));
-
-  action_queue.CancelAllActions();
-  action_queue.Tick();
-
-  // It should still be running as the actor could not have signaled.
-  EXPECT_TRUE(action_queue.Running());
-
-  bool sent_started, sent_cancel, interrupted;
-  EXPECT_TRUE(action_queue.GetCurrentActionState(
-      nullptr, &sent_started, &sent_cancel, &interrupted, nullptr, nullptr));
-  EXPECT_TRUE(sent_started);
-  EXPECT_TRUE(sent_cancel);
-  EXPECT_FALSE(interrupted);
-
-  EXPECT_FALSE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
-                                               nullptr, nullptr, nullptr));
+  });
 
   // Run the action so it can signal completion.
-  event_loop_factory_.RunFor(chrono::seconds(1));
+  RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
+    action_queue.Tick();
 
-  action_queue.Tick();
+    // Make sure it stopped.
+    EXPECT_FALSE(action_queue.Running());
+    EXPECT_EQ(1, nop_act.running_count());
+  });
 
-  // Make sure it stopped.
-  EXPECT_FALSE(action_queue.Running());
-  EXPECT_EQ(1, nop_act.running_count());
+  event_loop_factory_.RunFor(chrono::seconds(3));
 }
 
 // Tests that an action that would block forever stops when canceled.
@@ -289,30 +304,34 @@
   ActionQueue action_queue;
 
   // Let the actor and action queue start up.
-  event_loop_factory_.RunFor(chrono::seconds(1));
-  action_queue.Tick();
+  RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
+    action_queue.Tick();
 
-  // Enqueue blocking action.
-  {
-    UIntT uint;
-    uint.val = 0;
-    action_queue.EnqueueAction(cancel_action_factory.Make(uint));
-  }
+    // Enqueue blocking action.
+    {
+      UIntT uint;
+      uint.val = 0;
+      action_queue.EnqueueAction(cancel_action_factory.Make(uint));
+    }
 
-  action_queue.Tick();
-  EXPECT_TRUE(action_queue.Running());
+    action_queue.Tick();
+    EXPECT_TRUE(action_queue.Running());
 
-  // Tell action to cancel.
-  action_queue.CancelCurrentAction();
-  action_queue.Tick();
+    // Tell action to cancel.
+    action_queue.CancelCurrentAction();
+    action_queue.Tick();
+  });
 
   // This will block forever on failure.
   // TODO(ben): prolly a bad way to fail
-  event_loop_factory_.RunFor(chrono::seconds(1));
-  action_queue.Tick();
+  RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
+    action_queue.Tick();
 
-  // It should still be running as the actor could not have signalled.
-  EXPECT_FALSE(action_queue.Running());
+    // It should still be running as the actor could not have signalled.
+    EXPECT_FALSE(action_queue.Running());
+  });
+
+  event_loop_factory_.RunFor(chrono::seconds(3));
 }
 
 // Tests that 2 actions in a row causes the second one to cancel the first one.
@@ -323,78 +342,84 @@
       TestActorNOP::MakeFactory(test_event_loop_.get());
 
   ActionQueue action_queue;
-  // Tick an empty queue and make sure it was not running.
-  event_loop_factory_.RunFor(chrono::seconds(1));
-  action_queue.Tick();
-  EXPECT_FALSE(action_queue.Running());
-
-  // Enqueue action to be canceled.
-  {
-    UIntT uint;
-    uint.val = 0;
-    action_queue.EnqueueAction(nop_actor_factory.Make(uint));
-  }
-  action_queue.Tick();
-
-  // Should still be running as the actor could not have signalled.
-  EXPECT_TRUE(action_queue.Running());
 
   // id for the first time run.
   uint32_t nop_actor_id = 0;
   // Check the internal state and write down id for later use.
   bool sent_started, sent_cancel, interrupted;
-  EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, &sent_started,
-                                                 &sent_cancel, &interrupted,
-                                                 &nop_actor_id, nullptr));
-  EXPECT_TRUE(sent_started);
-  EXPECT_FALSE(sent_cancel);
-  EXPECT_FALSE(interrupted);
-  ASSERT_NE(0u, nop_actor_id);
-
-  // Add the next action which should ensure the first stopped.
-  {
-    UIntT uint;
-    uint.val = 0;
-    action_queue.EnqueueAction(nop_actor_factory.Make(uint));
-  }
-
   // id for the second run.
   uint32_t nop_actor2_id = 0;
-  // Check the internal state and write down id for later use.
-  EXPECT_TRUE(action_queue.GetNextActionState(nullptr, &sent_started,
-                                              &sent_cancel, &interrupted,
-                                              &nop_actor2_id, nullptr));
-  EXPECT_NE(nop_actor_id, nop_actor2_id);
-  EXPECT_FALSE(sent_started);
-  EXPECT_FALSE(sent_cancel);
-  EXPECT_FALSE(interrupted);
-  ASSERT_NE(0u, nop_actor2_id);
 
-  action_queue.Tick();
+  // Tick an empty queue and make sure it was not running.
+  RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
+    action_queue.Tick();
+    EXPECT_FALSE(action_queue.Running());
+
+    // Enqueue action to be canceled.
+    {
+      UIntT uint;
+      uint.val = 0;
+      action_queue.EnqueueAction(nop_actor_factory.Make(uint));
+    }
+    action_queue.Tick();
+
+    // Should still be running as the actor could not have signalled.
+    EXPECT_TRUE(action_queue.Running());
+
+    EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, &sent_started,
+                                                   &sent_cancel, &interrupted,
+                                                   &nop_actor_id, nullptr));
+    EXPECT_TRUE(sent_started);
+    EXPECT_FALSE(sent_cancel);
+    EXPECT_FALSE(interrupted);
+    ASSERT_NE(0u, nop_actor_id);
+
+    // Add the next action which should ensure the first stopped.
+    {
+      UIntT uint;
+      uint.val = 0;
+      action_queue.EnqueueAction(nop_actor_factory.Make(uint));
+    }
+
+    // Check the internal state and write down id for later use.
+    EXPECT_TRUE(action_queue.GetNextActionState(nullptr, &sent_started,
+                                                &sent_cancel, &interrupted,
+                                                &nop_actor2_id, nullptr));
+    EXPECT_NE(nop_actor_id, nop_actor2_id);
+    EXPECT_FALSE(sent_started);
+    EXPECT_FALSE(sent_cancel);
+    EXPECT_FALSE(interrupted);
+    ASSERT_NE(0u, nop_actor2_id);
+
+    action_queue.Tick();
+  });
 
   // Run the action so it can signal completion.
-  event_loop_factory_.RunFor(chrono::seconds(1));
+  RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
+    action_queue.Tick();
 
-  action_queue.Tick();
+    // Check the new action is the right one.
+    uint32_t test_id = 0;
+    EXPECT_TRUE(action_queue.GetCurrentActionState(
+        nullptr, &sent_started, &sent_cancel, &interrupted, &test_id, nullptr));
+    EXPECT_TRUE(sent_started);
+    EXPECT_FALSE(sent_cancel);
+    EXPECT_FALSE(interrupted);
+    EXPECT_EQ(nop_actor2_id, test_id);
 
-  // Check the new action is the right one.
-  uint32_t test_id = 0;
-  EXPECT_TRUE(action_queue.GetCurrentActionState(
-      nullptr, &sent_started, &sent_cancel, &interrupted, &test_id, nullptr));
-  EXPECT_TRUE(sent_started);
-  EXPECT_FALSE(sent_cancel);
-  EXPECT_FALSE(interrupted);
-  EXPECT_EQ(nop_actor2_id, test_id);
-
-  // Make sure it is still going.
-  EXPECT_TRUE(action_queue.Running());
+    // Make sure it is still going.
+    EXPECT_TRUE(action_queue.Running());
+  });
 
   // Now let everything finish.
-  event_loop_factory_.RunFor(chrono::seconds(1));
-  action_queue.Tick();
+  RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
+    action_queue.Tick();
 
-  // Make sure it stopped.
-  EXPECT_FALSE(action_queue.Running());
+    // Make sure it stopped.
+    EXPECT_FALSE(action_queue.Running());
+  });
+
+  event_loop_factory_.RunFor(chrono::seconds(4));
 }
 
 // Tests that we do get an index with our goal
@@ -403,51 +428,53 @@
 
   TestActorIndex::Factory test_actor_index_factory =
       TestActorIndex::MakeFactory(test_event_loop_.get());
+  ::aos::Fetcher<actions::TestActionGoal> goal_fetcher_ =
+      test_event_loop_->MakeFetcher<actions::TestActionGoal>("/test_action");
 
   ActionQueue action_queue;
   // Tick an empty queue and make sure it was not running.  Also tick the
   // factory to allow it to send out the initial cancel message.
-  event_loop_factory_.RunFor(chrono::seconds(1));
-  action_queue.Tick();
+  RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
+    action_queue.Tick();
 
-  EXPECT_FALSE(action_queue.Running());
+    EXPECT_FALSE(action_queue.Running());
 
-  // Enqueue action to post index.
-  {
-    UIntT uint;
-    uint.val = 5;
-    action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
-  }
-  ::aos::Fetcher<actions::TestActionGoal> goal_fetcher_ =
-      test_event_loop_->MakeFetcher<actions::TestActionGoal>(
-          "/test_action");
+    // Enqueue action to post index.
+    {
+      UIntT uint;
+      uint.val = 5;
+      action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
+    }
 
-  ASSERT_TRUE(goal_fetcher_.Fetch());
-  EXPECT_EQ(5u, goal_fetcher_->params()->val());
-  EXPECT_EQ(0u, idx_actor.index);
+    ASSERT_TRUE(goal_fetcher_.Fetch());
+    EXPECT_EQ(5u, goal_fetcher_->params()->val());
+    EXPECT_EQ(0u, idx_actor.index);
 
-  action_queue.Tick();
+    action_queue.Tick();
+  });
 
   // Run the next action so it can accomplish signal completion.
-  event_loop_factory_.RunFor(chrono::seconds(1));
+  RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
+    action_queue.Tick();
+    EXPECT_EQ(5u, idx_actor.index);
 
-  action_queue.Tick();
-  EXPECT_EQ(5u, idx_actor.index);
-
-  // Enqueue action to post index.
-  {
-    UIntT uint;
-    uint.val = 3;
-    action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
-  }
-  ASSERT_TRUE(goal_fetcher_.Fetch());
-  EXPECT_EQ(3u, goal_fetcher_->params()->val());
+    // Enqueue action to post index.
+    {
+      UIntT uint;
+      uint.val = 3;
+      action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
+    }
+    ASSERT_TRUE(goal_fetcher_.Fetch());
+    EXPECT_EQ(3u, goal_fetcher_->params()->val());
+  });
 
   // Run the next action so it can accomplish signal completion.
-  event_loop_factory_.RunFor(chrono::seconds(1));
+  RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
+    action_queue.Tick();
+    EXPECT_EQ(3u, idx_actor.index);
+  });
 
-  action_queue.Tick();
-  EXPECT_EQ(3u, idx_actor.index);
+  event_loop_factory_.RunFor(chrono::seconds(3));
 }
 
 // Tests that an action with a structure params works.
@@ -458,32 +485,37 @@
       TestActor2Nop::MakeFactory(test_event_loop_.get());
 
   ActionQueue action_queue;
-  // Tick an empty queue and make sure it was not running.
-  action_queue.Tick();
-  EXPECT_FALSE(action_queue.Running());
 
-  actions::MyParamsT p;
-  p.param1 = 5.0;
-  p.param2 = 7;
+  RunAt(monotonic_clock::time_point(chrono::seconds(0)), [&]() {
+    // Tick an empty queue and make sure it was not running.
+    action_queue.Tick();
+    EXPECT_FALSE(action_queue.Running());
 
-  action_queue.EnqueueAction(test_action_2_nop_factory.Make(p));
+    actions::MyParamsT p;
+    p.param1 = 5.0;
+    p.param2 = 7;
 
-  // We started an action and it should be running.
-  EXPECT_TRUE(action_queue.Running());
+    action_queue.EnqueueAction(test_action_2_nop_factory.Make(p));
 
-  // Tick it and make sure it is still running.
-  action_queue.Tick();
-  EXPECT_TRUE(action_queue.Running());
+    // We started an action and it should be running.
+    EXPECT_TRUE(action_queue.Running());
+
+    // Tick it and make sure it is still running.
+    action_queue.Tick();
+    EXPECT_TRUE(action_queue.Running());
+  });
 
   // Run the action so it can signal completion.
   // The actor takes no time, but running for a second is the best way to get it
   // to go.
-  event_loop_factory_.RunFor(chrono::seconds(1));
+  RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
+    action_queue.Tick();
 
-  action_queue.Tick();
+    // Make sure it stopped.
+    EXPECT_FALSE(action_queue.Running());
+  });
 
-  // Make sure it stopped.
-  EXPECT_FALSE(action_queue.Running());
+  event_loop_factory_.RunFor(chrono::seconds(2));
 }
 
 }  // namespace testing