buffet: Order device state and command updates on the server

Added strict ordering between command and state updates on the cloud
server interface. Command updates are tied to the current device state
and command update requests to the server are not dispatched until the
corresponding device state request finishes successfully.

BUG=brillo:1202
TEST=`FEATURES=test emerge-link buffet`

Change-Id: I23af95ab66b5bca91f637d9886ae234681b67104
Reviewed-on: https://chromium-review.googlesource.com/282261
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
Reviewed-by: Vitaly Buka <vitalybuka@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/buffet/states/state_change_queue_unittest.cc b/buffet/states/state_change_queue_unittest.cc
index 1a30f97..091e5c3 100644
--- a/buffet/states/state_change_queue_unittest.cc
+++ b/buffet/states/state_change_queue_unittest.cc
@@ -5,6 +5,7 @@
 
 #include "buffet/states/state_change_queue.h"
 
+#include <chromeos/bind_lambda.h>
 #include <gtest/gtest.h>
 
 #include "buffet/commands/unittest_utils.h"
@@ -161,4 +162,29 @@
   EXPECT_EQ(expected2, changes[1].changed_properties);
 }
 
+TEST_F(StateChangeQueueTest, ImmediateStateChangeNotification) {
+  // When queue is empty, registering a new callback will trigger it.
+  bool called = false;
+  auto callback = [&called](StateChangeQueueInterface::UpdateID id) {
+    called = true;
+  };
+  queue_->AddOnStateUpdatedCallback(base::Bind(callback));
+  EXPECT_TRUE(called);
+}
+
+TEST_F(StateChangeQueueTest, DelayedStateChangeNotification) {
+  // When queue is not empty, registering a new callback will not trigger it.
+  ASSERT_TRUE(queue_->NotifyPropertiesUpdated(
+      base::Time::Now(),
+      native_types::Object{
+        {"prop.name1", unittests::make_int_prop_value(1)},
+        {"prop.name2", unittests::make_int_prop_value(2)},
+      }));
+
+  auto callback = [](StateChangeQueueInterface::UpdateID id) {
+    FAIL() << "This should not be called";
+  };
+  queue_->AddOnStateUpdatedCallback(base::Bind(callback));
+}
+
 }  // namespace buffet