Post error patches to the server

BUG:23906692

Change-Id: Ibca7c7b77b6fba4a69d9f50a18260cfed61e7a8c
Reviewed-on: https://weave-review.googlesource.com/1260
Reviewed-by: Alex Vakulenko <avakulenko@google.com>
diff --git a/libweave/examples/ubuntu/main.cc b/libweave/examples/ubuntu/main.cc
index ff0d450..179c5d3 100644
--- a/libweave/examples/ubuntu/main.cc
+++ b/libweave/examples/ubuntu/main.cc
@@ -51,7 +51,7 @@
       "_greeter": {
         "_greet": {
           "minimalRole": "user",
-          "parameters": { "_name": "string", "_count": "integer"},
+          "parameters": { "_name": "string", "_count": {"minimum": 1, "maximum": 100}},
           "progress": { "_todo": "integer"},
           "results": { "_greeting": "string" }
         }
@@ -92,10 +92,15 @@
       return;
 
     std::string name;
-    if (!cmd->GetParameters()->GetString("_name", &name))
-      name = "anonymous";
+    if (!cmd->GetParameters()->GetString("_name", &name)) {
+      weave::ErrorPtr error;
+      weave::Error::AddTo(&error, FROM_HERE, "example",
+                          "invalid_parameter_value", "Name is missing");
+      cmd->Abort(error.get(), nullptr);
+      return;
+    }
 
-    if (todo > 0) {
+    if (todo-- > 0) {
       LOG(INFO) << "Hello " << name;
 
       base::DictionaryValue progress;
@@ -107,7 +112,7 @@
       device_->SetStateProperties(state, nullptr);
     }
 
-    if (--todo > 0) {
+    if (todo > 0) {
       task_runner_->PostDelayedTask(
           FROM_HERE, base::Bind(&CommandHandler::DoGreet,
                                 weak_ptr_factory_.GetWeakPtr(), command, todo),
diff --git a/libweave/src/commands/cloud_command_proxy.cc b/libweave/src/commands/cloud_command_proxy.cc
index 9f6ada3..931e3e4 100644
--- a/libweave/src/commands/cloud_command_proxy.cc
+++ b/libweave/src/commands/cloud_command_proxy.cc
@@ -12,6 +12,7 @@
 #include "src/commands/prop_constraints.h"
 #include "src/commands/prop_types.h"
 #include "src/commands/schema_constants.h"
+#include "src/utils.h"
 
 namespace weave {
 
@@ -32,6 +33,15 @@
   observer_.Add(command_instance);
 }
 
+void CloudCommandProxy::OnErrorChanged() {
+  std::unique_ptr<base::DictionaryValue> patch{new base::DictionaryValue};
+  patch->Set(commands::attributes::kCommand_Error,
+             command_instance_->GetError()
+                 ? ErrorInfoToJson(*command_instance_->GetError()).release()
+                 : base::Value::CreateNullValue().release());
+  QueueCommandUpdate(std::move(patch));
+}
+
 void CloudCommandProxy::OnResultsChanged() {
   std::unique_ptr<base::DictionaryValue> patch{new base::DictionaryValue};
   patch->Set(commands::attributes::kCommand_Results,
diff --git a/libweave/src/commands/cloud_command_proxy.h b/libweave/src/commands/cloud_command_proxy.h
index 711befa..12432df 100644
--- a/libweave/src/commands/cloud_command_proxy.h
+++ b/libweave/src/commands/cloud_command_proxy.h
@@ -39,10 +39,11 @@
   ~CloudCommandProxy() override = default;
 
   // CommandProxyInterface implementation/overloads.
+  void OnCommandDestroyed() override;
+  void OnErrorChanged() override;
+  void OnProgressChanged() override;
   void OnResultsChanged() override;
   void OnStatusChanged() override;
-  void OnProgressChanged() override;
-  void OnCommandDestroyed() override;
 
  private:
   using UpdateID = StateChangeQueueInterface::UpdateID;
diff --git a/libweave/src/commands/command_instance.cc b/libweave/src/commands/command_instance.cc
index 4701bb6..e15b1b7 100644
--- a/libweave/src/commands/command_instance.cc
+++ b/libweave/src/commands/command_instance.cc
@@ -159,6 +159,7 @@
 
 bool CommandInstance::SetError(const Error* command_error, ErrorPtr* error) {
   error_ = command_error ? command_error->Clone() : nullptr;
+  FOR_EACH_OBSERVER(Observer, observers_, OnErrorChanged());
   return SetStatus(CommandStatus::kError, error);
 }
 
@@ -296,6 +297,7 @@
 
 bool CommandInstance::Abort(const Error* command_error, ErrorPtr* error) {
   error_ = command_error ? command_error->Clone() : nullptr;
+  FOR_EACH_OBSERVER(Observer, observers_, OnErrorChanged());
   bool result = SetStatus(CommandStatus::kAborted, error);
   RemoveFromQueue();
   // The command will be destroyed after that, so do not access any members.
diff --git a/libweave/src/commands/command_instance.h b/libweave/src/commands/command_instance.h
index e8a838d..843087c 100644
--- a/libweave/src/commands/command_instance.h
+++ b/libweave/src/commands/command_instance.h
@@ -33,10 +33,11 @@
  public:
   class Observer {
    public:
+    virtual void OnCommandDestroyed() = 0;
+    virtual void OnErrorChanged() = 0;
+    virtual void OnProgressChanged() = 0;
     virtual void OnResultsChanged() = 0;
     virtual void OnStatusChanged() = 0;
-    virtual void OnProgressChanged() = 0;
-    virtual void OnCommandDestroyed() = 0;
 
    protected:
     virtual ~Observer() = default;