blob: 3c65cd115ff761484884c5a1cd5d8babc9d04c96 [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Alex Vakulenkobe4254b2015-06-26 11:34:03 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Stefan Sauer2d16dfa2015-09-25 17:08:35 +02005#include "src/commands/cloud_command_proxy.h"
Alex Vakulenkobe4254b2015-06-26 11:34:03 -07006
7#include <memory>
8#include <queue>
9
Alex Vakulenkoebfa60b2016-02-01 11:52:30 -080010#include <base/bind.h>
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070011#include <gmock/gmock.h>
12#include <gtest/gtest.h>
Vitaly Buka727f3e62015-09-25 17:33:43 -070013#include <weave/provider/test/fake_task_runner.h>
Alex Vakulenko8a05beb2015-11-24 17:13:20 -080014#include <weave/test/unittest_utils.h>
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070015
Stefan Sauer2d16dfa2015-09-25 17:08:35 +020016#include "src/commands/command_instance.h"
Vitaly Buka012cd982016-02-22 17:18:49 -080017#include "src/test/mock_component_manager.h"
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070018
Vitaly Bukaff1d1862015-10-07 20:40:36 -070019using testing::_;
Alex Vakulenkoebfa60b2016-02-01 11:52:30 -080020using testing::AnyNumber;
Vitaly Bukaff1d1862015-10-07 20:40:36 -070021using testing::DoAll;
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070022using testing::Invoke;
23using testing::Return;
24using testing::ReturnPointee;
Vitaly Bukaff1d1862015-10-07 20:40:36 -070025using testing::SaveArg;
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070026
Vitaly Bukab6f015a2015-07-09 14:59:23 -070027namespace weave {
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070028
Vitaly Buka0f6b2ec2015-08-20 15:35:19 -070029using test::CreateDictionaryValue;
30using test::CreateValue;
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070031
32namespace {
33
34const char kCmdID[] = "abcd";
35
36MATCHER_P(MatchJson, str, "") {
37 return arg.Equals(CreateValue(str).get());
38}
39
40class MockCloudCommandUpdateInterface : public CloudCommandUpdateInterface {
41 public:
Vitaly Buka74763422015-10-11 00:39:52 -070042 MOCK_METHOD3(UpdateCommand,
Vitaly Bukaa647c852015-07-06 14:51:01 -070043 void(const std::string&,
44 const base::DictionaryValue&,
Vitaly Buka74763422015-10-11 00:39:52 -070045 const DoneCallback&));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070046};
47
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070048// Test back-off entry that uses the test clock.
Vitaly Buka0f80f7c2015-08-13 00:57:25 -070049class TestBackoffEntry : public BackoffEntry {
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070050 public:
51 TestBackoffEntry(const Policy* const policy, base::Clock* clock)
Vitaly Buka0f80f7c2015-08-13 00:57:25 -070052 : BackoffEntry{policy}, clock_{clock} {
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070053 creation_time_ = clock->Now();
54 }
55
56 private:
Vitaly Buka0f80f7c2015-08-13 00:57:25 -070057 // Override from BackoffEntry to use the custom test clock for
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070058 // the backoff calculations.
59 base::TimeTicks ImplGetTimeNow() const override {
60 return base::TimeTicks::FromInternalValue(clock_->Now().ToInternalValue());
61 }
62
63 base::Clock* clock_;
64 base::Time creation_time_;
65};
66
Alex Vakulenkoebfa60b2016-02-01 11:52:30 -080067class CloudCommandProxyWrapper : public CloudCommandProxy {
68 public:
69 CloudCommandProxyWrapper(CommandInstance* command_instance,
70 CloudCommandUpdateInterface* cloud_command_updater,
71 ComponentManager* component_manager,
72 std::unique_ptr<BackoffEntry> backoff_entry,
73 provider::TaskRunner* task_runner,
74 const base::Closure& destruct_callback)
75 : CloudCommandProxy{command_instance, cloud_command_updater,
76 component_manager, std::move(backoff_entry),
77 task_runner},
78 destruct_callback_{destruct_callback} {}
79
Vitaly Buka5e94dc82016-03-01 13:03:01 -080080 ~CloudCommandProxyWrapper() { destruct_callback_.Run(); }
Alex Vakulenkoebfa60b2016-02-01 11:52:30 -080081
82 private:
83 base::Closure destruct_callback_;
84};
85
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070086class CloudCommandProxyTest : public ::testing::Test {
87 protected:
88 void SetUp() override {
Alex Vakulenkod91d6252015-12-05 17:14:39 -080089 // Set up the test ComponentManager.
Vitaly Buka34668e72015-12-15 14:46:47 -080090 auto callback = [this](
91 const base::Callback<void(ComponentManager::UpdateID)>& call) {
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070092 return callbacks_.Add(call).release();
93 };
Alex Vakulenkod91d6252015-12-05 17:14:39 -080094 EXPECT_CALL(component_manager_, MockAddServerStateUpdatedCallback(_))
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070095 .WillRepeatedly(Invoke(callback));
Alex Vakulenkod91d6252015-12-05 17:14:39 -080096 EXPECT_CALL(component_manager_, GetLastStateChangeId())
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070097 .WillRepeatedly(testing::ReturnPointee(&current_state_update_id_));
98
Alex Vakulenkobe4254b2015-06-26 11:34:03 -070099 CreateCommandInstance();
100 }
101
102 void CreateCommandInstance() {
103 auto command_json = CreateDictionaryValue(R"({
104 'name': 'calc.add',
105 'id': 'abcd',
106 'parameters': {
107 'value1': 10,
108 'value2': 20
109 }
110 })");
111 CHECK(command_json.get());
112
Alex Vakulenko88f55d82015-12-03 15:30:27 -0800113 command_instance_ = CommandInstance::FromJson(
114 command_json.get(), Command::Origin::kCloud, nullptr, nullptr);
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700115 CHECK(command_instance_.get());
116
117 // Backoff - start at 1s and double with each backoff attempt and no jitter.
Vitaly Buka0f80f7c2015-08-13 00:57:25 -0700118 static const BackoffEntry::Policy policy{0, 1000, 2.0, 0.0,
119 20000, -1, false};
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700120 std::unique_ptr<TestBackoffEntry> backoff{
Vitaly Buka823fdda2015-08-13 00:33:00 -0700121 new TestBackoffEntry{&policy, task_runner_.GetClock()}};
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700122
123 // Finally construct the CloudCommandProxy we are going to test here.
Alex Vakulenkoebfa60b2016-02-01 11:52:30 -0800124 std::unique_ptr<CloudCommandProxy> proxy{new CloudCommandProxyWrapper{
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800125 command_instance_.get(), &cloud_updater_, &component_manager_,
Alex Vakulenkoebfa60b2016-02-01 11:52:30 -0800126 std::move(backoff), &task_runner_,
127 base::Bind(&CloudCommandProxyTest::OnProxyDestroyed,
128 base::Unretained(this))}};
Vitaly Buka157b16a2015-07-31 16:20:48 -0700129 // CloudCommandProxy::CloudCommandProxy() subscribe itself to weave::Command
130 // notifications. When weave::Command is being destroyed it sends
131 // ::OnCommandDestroyed() and CloudCommandProxy deletes itself.
132 proxy.release();
Alex Vakulenkoebfa60b2016-02-01 11:52:30 -0800133
134 EXPECT_CALL(*this, OnProxyDestroyed()).Times(AnyNumber());
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700135 }
136
Alex Vakulenkoebfa60b2016-02-01 11:52:30 -0800137 MOCK_METHOD0(OnProxyDestroyed, void());
138
Alex Vakulenkod91d6252015-12-05 17:14:39 -0800139 ComponentManager::UpdateID current_state_update_id_{0};
140 base::CallbackList<void(ComponentManager::UpdateID)> callbacks_;
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700141 testing::StrictMock<MockCloudCommandUpdateInterface> cloud_updater_;
Vitaly Buka012cd982016-02-22 17:18:49 -0800142 testing::StrictMock<test::MockComponentManager> component_manager_;
Vitaly Buka727f3e62015-09-25 17:33:43 -0700143 testing::StrictMock<provider::test::FakeTaskRunner> task_runner_;
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700144 std::queue<base::Closure> task_queue_;
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700145 std::unique_ptr<CommandInstance> command_instance_;
146};
147
148} // anonymous namespace
149
Alex Vakulenkoebfa60b2016-02-01 11:52:30 -0800150TEST_F(CloudCommandProxyTest, EnsureDestroyed) {
151 EXPECT_CALL(*this, OnProxyDestroyed()).Times(1);
152 command_instance_.reset();
153 // Verify that CloudCommandProxy has been destroyed already and not at some
154 // point during the destruction of CloudCommandProxyTest class.
155 testing::Mock::VerifyAndClearExpectations(this);
156}
157
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700158TEST_F(CloudCommandProxyTest, ImmediateUpdate) {
159 const char expected[] = "{'state':'done'}";
Vitaly Buka74763422015-10-11 00:39:52 -0700160 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expected), _));
Vitaly Buka2f548972015-10-08 19:34:49 -0700161 command_instance_->Complete({}, nullptr);
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700162 task_runner_.RunOnce();
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700163}
164
165TEST_F(CloudCommandProxyTest, DelayedUpdate) {
166 // Simulate that the current device state has changed.
167 current_state_update_id_ = 20;
168 // No command update is expected here.
Vitaly Buka2f548972015-10-08 19:34:49 -0700169 command_instance_->Complete({}, nullptr);
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700170 // Still no command update here...
171 callbacks_.Notify(19);
172 // Now we should get the update...
173 const char expected[] = "{'state':'done'}";
Vitaly Buka74763422015-10-11 00:39:52 -0700174 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expected), _));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700175 callbacks_.Notify(20);
176}
177
178TEST_F(CloudCommandProxyTest, InFlightRequest) {
179 // SetProgress causes two consecutive updates:
180 // state=inProgress
181 // progress={...}
182 // The first state update is sent immediately, the second should be delayed.
Vitaly Buka74763422015-10-11 00:39:52 -0700183 DoneCallback callback;
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700184 EXPECT_CALL(
185 cloud_updater_,
186 UpdateCommand(
187 kCmdID,
Vitaly Buka74763422015-10-11 00:39:52 -0700188 MatchJson("{'state':'inProgress', 'progress':{'status':'ready'}}"),
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700189 _))
Vitaly Buka74763422015-10-11 00:39:52 -0700190 .WillOnce(SaveArg<2>(&callback));
Vitaly Buka4f4e2282015-07-23 17:50:07 -0700191 EXPECT_TRUE(command_instance_->SetProgress(
192 *CreateDictionaryValue("{'status': 'ready'}"), nullptr));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700193
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700194 task_runner_.RunOnce();
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700195}
196
197TEST_F(CloudCommandProxyTest, CombineMultiple) {
198 // Simulate that the current device state has changed.
199 current_state_update_id_ = 20;
200 // SetProgress causes two consecutive updates:
201 // state=inProgress
202 // progress={...}
203 // Both updates will be held until device state is updated.
Vitaly Buka4f4e2282015-07-23 17:50:07 -0700204 EXPECT_TRUE(command_instance_->SetProgress(
205 *CreateDictionaryValue("{'status': 'ready'}"), nullptr));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700206
207 // Now simulate the device state updated. Both updates should come in one
208 // request.
209 const char expected[] = R"({
210 'progress': {'status':'ready'},
211 'state':'inProgress'
212 })";
Vitaly Buka74763422015-10-11 00:39:52 -0700213 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expected), _));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700214 callbacks_.Notify(20);
215}
216
217TEST_F(CloudCommandProxyTest, RetryFailed) {
Vitaly Buka74763422015-10-11 00:39:52 -0700218 DoneCallback callback;
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700219
220 const char expect[] =
221 "{'state':'inProgress', 'progress': {'status': 'ready'}}";
Vitaly Buka74763422015-10-11 00:39:52 -0700222 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expect), _))
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700223 .Times(3)
Vitaly Buka74763422015-10-11 00:39:52 -0700224 .WillRepeatedly(SaveArg<2>(&callback));
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700225 auto started = task_runner_.GetClock()->Now();
Vitaly Buka4f4e2282015-07-23 17:50:07 -0700226 EXPECT_TRUE(command_instance_->SetProgress(
227 *CreateDictionaryValue("{'status': 'ready'}"), nullptr));
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700228 task_runner_.Run();
Vitaly Buka74763422015-10-11 00:39:52 -0700229 ErrorPtr error;
Vitaly Buka48a86692016-01-21 17:15:58 -0800230 Error::AddTo(&error, FROM_HERE, "TEST", "TEST");
Vitaly Buka74763422015-10-11 00:39:52 -0700231 callback.Run(error->Clone());
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700232 task_runner_.Run();
233 EXPECT_GE(task_runner_.GetClock()->Now() - started,
234 base::TimeDelta::FromSecondsD(0.9));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700235
Vitaly Buka74763422015-10-11 00:39:52 -0700236 callback.Run(error->Clone());
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700237 task_runner_.Run();
238 EXPECT_GE(task_runner_.GetClock()->Now() - started,
239 base::TimeDelta::FromSecondsD(2.9));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700240
Vitaly Buka74763422015-10-11 00:39:52 -0700241 callback.Run(nullptr);
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700242 task_runner_.Run();
243 EXPECT_GE(task_runner_.GetClock()->Now() - started,
244 base::TimeDelta::FromSecondsD(2.9));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700245}
246
247TEST_F(CloudCommandProxyTest, GateOnStateUpdates) {
248 current_state_update_id_ = 20;
Vitaly Buka4f4e2282015-07-23 17:50:07 -0700249 EXPECT_TRUE(command_instance_->SetProgress(
250 *CreateDictionaryValue("{'status': 'ready'}"), nullptr));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700251 current_state_update_id_ = 21;
Vitaly Buka4f4e2282015-07-23 17:50:07 -0700252 EXPECT_TRUE(command_instance_->SetProgress(
253 *CreateDictionaryValue("{'status': 'busy'}"), nullptr));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700254 current_state_update_id_ = 22;
Vitaly Buka2f548972015-10-08 19:34:49 -0700255 command_instance_->Complete({}, nullptr);
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700256
257 // Device state #20 updated.
Vitaly Buka74763422015-10-11 00:39:52 -0700258 DoneCallback callback;
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700259 const char expect1[] = R"({
260 'progress': {'status':'ready'},
261 'state':'inProgress'
262 })";
Vitaly Buka74763422015-10-11 00:39:52 -0700263 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expect1), _))
264 .WillOnce(SaveArg<2>(&callback));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700265 callbacks_.Notify(20);
Vitaly Buka74763422015-10-11 00:39:52 -0700266 callback.Run(nullptr);
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700267
268 // Device state #21 updated.
269 const char expect2[] = "{'progress': {'status':'busy'}}";
Vitaly Buka74763422015-10-11 00:39:52 -0700270 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expect2), _))
271 .WillOnce(SaveArg<2>(&callback));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700272 callbacks_.Notify(21);
273
274 // Device state #22 updated. Nothing happens here since the previous command
275 // update request hasn't completed yet.
276 callbacks_.Notify(22);
277
278 // Now the command update is complete, send out the patch that happened after
279 // the state #22 was updated.
280 const char expect3[] = "{'state': 'done'}";
Vitaly Buka74763422015-10-11 00:39:52 -0700281 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expect3), _))
282 .WillOnce(SaveArg<2>(&callback));
283 callback.Run(nullptr);
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700284}
285
286TEST_F(CloudCommandProxyTest, CombineSomeStates) {
287 current_state_update_id_ = 20;
Vitaly Buka4f4e2282015-07-23 17:50:07 -0700288 EXPECT_TRUE(command_instance_->SetProgress(
289 *CreateDictionaryValue("{'status': 'ready'}"), nullptr));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700290 current_state_update_id_ = 21;
Vitaly Buka4f4e2282015-07-23 17:50:07 -0700291 EXPECT_TRUE(command_instance_->SetProgress(
292 *CreateDictionaryValue("{'status': 'busy'}"), nullptr));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700293 current_state_update_id_ = 22;
Vitaly Buka2f548972015-10-08 19:34:49 -0700294 command_instance_->Complete({}, nullptr);
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700295
296 // Device state 20-21 updated.
Vitaly Buka74763422015-10-11 00:39:52 -0700297 DoneCallback callback;
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700298 const char expect1[] = R"({
299 'progress': {'status':'busy'},
300 'state':'inProgress'
301 })";
Vitaly Buka74763422015-10-11 00:39:52 -0700302 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expect1), _))
303 .WillOnce(SaveArg<2>(&callback));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700304 callbacks_.Notify(21);
Vitaly Buka74763422015-10-11 00:39:52 -0700305 callback.Run(nullptr);
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700306
307 // Device state #22 updated.
308 const char expect2[] = "{'state': 'done'}";
Vitaly Buka74763422015-10-11 00:39:52 -0700309 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expect2), _))
310 .WillOnce(SaveArg<2>(&callback));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700311 callbacks_.Notify(22);
Vitaly Buka74763422015-10-11 00:39:52 -0700312 callback.Run(nullptr);
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700313}
314
315TEST_F(CloudCommandProxyTest, CombineAllStates) {
316 current_state_update_id_ = 20;
Vitaly Buka4f4e2282015-07-23 17:50:07 -0700317 EXPECT_TRUE(command_instance_->SetProgress(
318 *CreateDictionaryValue("{'status': 'ready'}"), nullptr));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700319 current_state_update_id_ = 21;
Vitaly Buka4f4e2282015-07-23 17:50:07 -0700320 EXPECT_TRUE(command_instance_->SetProgress(
321 *CreateDictionaryValue("{'status': 'busy'}"), nullptr));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700322 current_state_update_id_ = 22;
Vitaly Buka2f548972015-10-08 19:34:49 -0700323 command_instance_->Complete({}, nullptr);
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700324
325 // Device state 30 updated.
326 const char expected[] = R"({
327 'progress': {'status':'busy'},
328 'state':'done'
329 })";
Vitaly Buka74763422015-10-11 00:39:52 -0700330 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expected), _));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700331 callbacks_.Notify(30);
332}
333
334TEST_F(CloudCommandProxyTest, CoalesceUpdates) {
335 current_state_update_id_ = 20;
Vitaly Buka4f4e2282015-07-23 17:50:07 -0700336 EXPECT_TRUE(command_instance_->SetProgress(
337 *CreateDictionaryValue("{'status': 'ready'}"), nullptr));
338 EXPECT_TRUE(command_instance_->SetProgress(
339 *CreateDictionaryValue("{'status': 'busy'}"), nullptr));
340 EXPECT_TRUE(command_instance_->SetProgress(
341 *CreateDictionaryValue("{'status': 'finished'}"), nullptr));
Vitaly Buka2f548972015-10-08 19:34:49 -0700342 EXPECT_TRUE(command_instance_->Complete(*CreateDictionaryValue("{'sum': 30}"),
343 nullptr));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700344
345 const char expected[] = R"({
346 'progress': {'status':'finished'},
347 'results': {'sum':30},
348 'state':'done'
349 })";
Vitaly Buka74763422015-10-11 00:39:52 -0700350 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expected), _));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700351 callbacks_.Notify(30);
352}
353
354TEST_F(CloudCommandProxyTest, EmptyStateChangeQueue) {
355 // Assume the device state update queue was empty and was at update ID 20.
356 current_state_update_id_ = 20;
357
358 // Recreate the command instance and proxy with the new state change queue.
359 CreateCommandInstance();
360
361 // Empty queue will immediately call back with the state change notification.
362 callbacks_.Notify(20);
363
364 // As soon as we change the command, the update to the server should be sent.
365 const char expected[] = "{'state':'done'}";
Vitaly Buka74763422015-10-11 00:39:52 -0700366 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expected), _));
Vitaly Buka2f548972015-10-08 19:34:49 -0700367 command_instance_->Complete({}, nullptr);
Vitaly Bukaff1d1862015-10-07 20:40:36 -0700368 task_runner_.RunOnce();
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700369}
370
371TEST_F(CloudCommandProxyTest, NonEmptyStateChangeQueue) {
372 // Assume the device state update queue was NOT empty when the command
373 // instance was created.
374 current_state_update_id_ = 20;
375
376 // Recreate the command instance and proxy with the new state change queue.
377 CreateCommandInstance();
378
379 // No command updates right now.
Vitaly Buka2f548972015-10-08 19:34:49 -0700380 command_instance_->Complete({}, nullptr);
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700381
382 // Only when the state #20 is published we should update the command
383 const char expected[] = "{'state':'done'}";
Vitaly Buka74763422015-10-11 00:39:52 -0700384 EXPECT_CALL(cloud_updater_, UpdateCommand(kCmdID, MatchJson(expected), _));
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700385 callbacks_.Notify(20);
386}
387
Vitaly Bukab6f015a2015-07-09 14:59:23 -0700388} // namespace weave