buffet: Delay removal of completed command

User will need check status of the command.
Processed which handle commands execution needs to check
state of a command to avoid execution of commands in terminal
states.

TEST=unittest
BUG=brillo:431

Change-Id: I72dc65f824bee200ee81a1970330b6e8f2d08fc2
Reviewed-on: https://chromium-review.googlesource.com/263498
Tested-by: Vitaly Buka <vitalybuka@chromium.org>
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Vitaly Buka <vitalybuka@chromium.org>
diff --git a/buffet/commands/command_queue.cc b/buffet/commands/command_queue.cc
index d660a1d..62d8c20 100644
--- a/buffet/commands/command_queue.cc
+++ b/buffet/commands/command_queue.cc
@@ -4,10 +4,16 @@
 
 #include "buffet/commands/command_queue.h"
 
+#include <base/time/time.h>
+
 #include "buffet/commands/command_dispatch_interface.h"
 
 namespace buffet {
 
+namespace {
+const int kRemoveCommandDelayMin = 5;
+}
+
 void CommandQueue::Add(std::unique_ptr<CommandInstance> instance) {
   std::string id = instance->GetID();
   LOG_IF(FATAL, id.empty()) << "Command has no ID";
@@ -17,20 +23,44 @@
                               << "' is already in the queue";
   if (dispatch_interface_)
     dispatch_interface_->OnCommandAdded(pair.first->second.get());
+  Cleanup();
 }
 
-std::unique_ptr<CommandInstance> CommandQueue::Remove(
-    const std::string& id) {
-  std::unique_ptr<CommandInstance> instance;
+void CommandQueue::DelayedRemove(const std::string& id) {
   auto p = map_.find(id);
-  if (p != map_.end()) {
-    instance = std::move(p->second);
-    instance->SetCommandQueue(nullptr);
-    map_.erase(p);
-    if (dispatch_interface_)
-      dispatch_interface_->OnCommandRemoved(instance.get());
+  if (p == map_.end())
+    return;
+  remove_queue_.push(std::make_pair(
+      base::Time::Now() + base::TimeDelta::FromMinutes(kRemoveCommandDelayMin),
+      id));
+  Cleanup();
+}
+
+bool CommandQueue::Remove(const std::string& id) {
+  auto p = map_.find(id);
+  if (p == map_.end())
+    return false;
+  std::unique_ptr<CommandInstance> instance{std::move(p->second)};
+  instance->SetCommandQueue(nullptr);
+  map_.erase(p);
+  if (dispatch_interface_)
+    dispatch_interface_->OnCommandRemoved(instance.get());
+  return true;
+}
+
+void CommandQueue::Cleanup() {
+  while (!remove_queue_.empty() && remove_queue_.front().first < Now()) {
+    Remove(remove_queue_.front().second);
+    remove_queue_.pop();
   }
-  return instance;
+}
+
+void CommandQueue::SetNowForTest(base::Time now) {
+  test_now_ = now;
+}
+
+base::Time CommandQueue::Now() const {
+  return test_now_.is_null() ? base::Time::Now() : test_now_;
 }
 
 CommandInstance* CommandQueue::Find(const std::string& id) const {