buffet: Support multiple proxies for a command.

This is necessary to support Cloud API updates on command
changes.

BUG=None
TEST=cros_workon_make buffet --test&&manual

Change-Id: I09149d02c0564aa89c74bd66356b63547c17724f
Reviewed-on: https://chromium-review.googlesource.com/226533
Tested-by: Anton Muhin <antonm@chromium.org>
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Anton Muhin <antonm@chromium.org>
diff --git a/buffet/commands/command_instance.cc b/buffet/commands/command_instance.cc
index 9e1211a..f403630 100644
--- a/buffet/commands/command_instance.cc
+++ b/buffet/commands/command_instance.cc
@@ -137,8 +137,9 @@
   if (progress != progress_) {
     progress_ = progress;
     SetStatus(kStatusInProgress);
-    if (proxy_)
-      proxy_->OnProgressChanged(progress_);
+    for (auto& proxy : proxies_) {
+      proxy->OnProgressChanged(progress_);
+    }
   }
   return true;
 }
@@ -165,8 +166,9 @@
 void CommandInstance::SetStatus(const std::string& status) {
   if (status != status_) {
     status_ = status;
-    if (proxy_)
-      proxy_->OnStatusChanged(status_);
+    for (auto& proxy : proxies_) {
+      proxy->OnStatusChanged(status_);
+    }
   }
 }
 
diff --git a/buffet/commands/command_instance.h b/buffet/commands/command_instance.h
index f8bde2a..e35fd7b 100644
--- a/buffet/commands/command_instance.h
+++ b/buffet/commands/command_instance.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <vector>
 
 #include <base/macros.h>
 #include <chromeos/errors/error.h>
@@ -58,9 +59,11 @@
   // Sets the command ID (normally done by CommandQueue when the command
   // instance is added to it).
   void SetID(const std::string& id) { id_ = id; }
-  // Sets the command proxy for the dispatch technology used.
+  // Adds a proxy for this command.
   // The proxy object is not owned by this class.
-  void SetProxy(CommandProxyInterface* proxy) { proxy_ = proxy; }
+  void AddProxy(CommandProxyInterface* proxy) { proxies_.push_back(proxy); }
+  // Removes all the proxies for this command.
+  void ClearProxies() { proxies_.clear(); }
   // Sets the pointer to queue this command is part of.
   void SetCommandQueue(CommandQueue* queue) { queue_ = queue; }
 
@@ -111,10 +114,8 @@
   std::string status_ = kStatusQueued;
   // Current command execution progress.
   int progress_ = 0;
-  // Command proxy class for the current dispatch technology (e.g. D-Bus).
-  // This is a weak pointer. The proxy's lifetime is managed by the command
-  // dispatcher.
-  CommandProxyInterface* proxy_ = nullptr;
+  // Command proxies for the command.
+  std::vector<CommandProxyInterface*> proxies_;
   // Pointer to the command queue this command instance is added to.
   // The queue owns the command instance, so it outlives this object.
   CommandQueue* queue_ = nullptr;
diff --git a/buffet/commands/dbus_command_dispatcher.cc b/buffet/commands/dbus_command_dispatcher.cc
index e6041d2..591c1cc 100644
--- a/buffet/commands/dbus_command_dispatcher.cc
+++ b/buffet/commands/dbus_command_dispatcher.cc
@@ -24,7 +24,7 @@
 void DBusCommandDispacher::OnCommandAdded(CommandInstance* command_instance) {
   auto proxy = CreateDBusCommandProxy(command_instance);
   proxy->RegisterAsync(AsyncEventSequencer::GetDefaultCompletionAction());
-  command_instance->SetProxy(proxy.get());
+  command_instance->AddProxy(proxy.get());
 
   auto pair = std::make_pair(command_instance, std::move(proxy));
   CHECK(command_map_.insert(std::move(pair)).second)
@@ -32,7 +32,7 @@
 }
 
 void DBusCommandDispacher::OnCommandRemoved(CommandInstance* command_instance) {
-  command_instance->SetProxy(nullptr);
+  command_instance->ClearProxies();
   CHECK_GT(command_map_.erase(command_instance), 0u)
       << "The command instance is not in the dispatcher command map";
 }
diff --git a/buffet/commands/dbus_command_proxy_unittest.cc b/buffet/commands/dbus_command_proxy_unittest.cc
index 34d9f1d..f8fba8d 100644
--- a/buffet/commands/dbus_command_proxy_unittest.cc
+++ b/buffet/commands/dbus_command_proxy_unittest.cc
@@ -92,14 +92,14 @@
 
     command_proxy_.reset(new DBusCommandProxy(nullptr, bus_,
                                               command_instance_.get()));
-    command_instance_->SetProxy(command_proxy_.get());
+    command_instance_->AddProxy(command_proxy_.get());
     command_proxy_->RegisterAsync(
         AsyncEventSequencer::GetDefaultCompletionAction());
   }
 
   void TearDown() override {
     EXPECT_CALL(*mock_exported_object_command_, Unregister()).Times(1);
-    command_instance_->SetProxy(nullptr);
+    command_instance_->ClearProxies();
     command_proxy_.reset();
     command_instance_.reset();
     dict_.Clear();