blob: 3f854fea8b2a00f867cb81abd635752083c91ac8 [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Alex Vakulenko07216fe2014-09-19 15:31:09 -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/states/state_manager.h"
Alex Deymof6cbe322014-11-10 19:55:35 -08006
Alex Vakulenko57123b22014-10-28 13:50:16 -07007#include <cstdlib> // for abs().
8#include <vector>
Alex Vakulenko07216fe2014-09-19 15:31:09 -07009
Vitaly Buka247620b2015-05-26 15:42:20 -070010#include <base/bind.h>
Alex Vakulenko07216fe2014-09-19 15:31:09 -070011#include <base/values.h>
Alex Vakulenko57123b22014-10-28 13:50:16 -070012#include <gmock/gmock.h>
Alex Vakulenko07216fe2014-09-19 15:31:09 -070013#include <gtest/gtest.h>
Vitaly Buka1e363672015-09-25 14:01:16 -070014#include <weave/provider/test/mock_config_store.h>
Alex Vakulenko07216fe2014-09-19 15:31:09 -070015
Stefan Sauer2d16dfa2015-09-25 17:08:35 +020016#include "src/commands/schema_constants.h"
17#include "src/commands/unittest_utils.h"
18#include "src/states/error_codes.h"
19#include "src/states/mock_state_change_queue_interface.h"
Alex Vakulenko07216fe2014-09-19 15:31:09 -070020
Vitaly Bukab6f015a2015-07-09 14:59:23 -070021namespace weave {
Alex Vakulenko07216fe2014-09-19 15:31:09 -070022
Vitaly Buka32005de2015-05-01 12:33:31 -070023using testing::_;
24using testing::Return;
Vitaly Buka0f6b2ec2015-08-20 15:35:19 -070025using test::CreateDictionaryValue;
Vitaly Buka32005de2015-05-01 12:33:31 -070026
Alex Vakulenko07216fe2014-09-19 15:31:09 -070027namespace {
Vitaly Bukae0425e42015-08-18 15:50:24 -070028
29const char kBaseDefinition[] = R"({
30 "base": {
31 "manufacturer":"string",
32 "serialNumber":"string"
33 },
34 "device": {
35 "state_property":"string"
36 }
37})";
38
Alex Vakulenko07216fe2014-09-19 15:31:09 -070039std::unique_ptr<base::DictionaryValue> GetTestSchema() {
Vitaly Bukae0425e42015-08-18 15:50:24 -070040 return CreateDictionaryValue(kBaseDefinition);
Alex Vakulenko07216fe2014-09-19 15:31:09 -070041}
42
Vitaly Bukae0425e42015-08-18 15:50:24 -070043const char kBaseDefaults[] = R"({
44 "base": {
45 "manufacturer":"Test Factory",
46 "serialNumber":"Test Model"
47 }
48})";
49
Alex Vakulenko07216fe2014-09-19 15:31:09 -070050std::unique_ptr<base::DictionaryValue> GetTestValues() {
Vitaly Bukae0425e42015-08-18 15:50:24 -070051 return CreateDictionaryValue(kBaseDefaults);
Alex Vakulenko07216fe2014-09-19 15:31:09 -070052}
Alex Vakulenko57123b22014-10-28 13:50:16 -070053
Alex Vakulenko07216fe2014-09-19 15:31:09 -070054} // anonymous namespace
55
56class StateManagerTest : public ::testing::Test {
57 public:
58 void SetUp() override {
Alex Vakulenko57123b22014-10-28 13:50:16 -070059 // Initial expectations.
60 EXPECT_CALL(mock_state_change_queue_, IsEmpty()).Times(0);
Alex Vakulenkoff73cf22014-10-29 09:53:52 -070061 EXPECT_CALL(mock_state_change_queue_, NotifyPropertiesUpdated(_, _))
Vitaly Buka0ac6ca62015-10-06 19:16:29 -070062 .WillRepeatedly(Return(true));
Alex Vakulenko57123b22014-10-28 13:50:16 -070063 EXPECT_CALL(mock_state_change_queue_, GetAndClearRecordedStateChanges())
Vitaly Buka7c82d292015-05-03 18:08:12 -070064 .Times(0);
Alex Vakulenko57123b22014-10-28 13:50:16 -070065 mgr_.reset(new StateManager(&mock_state_change_queue_));
Vitaly Buka247620b2015-05-26 15:42:20 -070066
Vitaly Buka0ac6ca62015-10-06 19:16:29 -070067 EXPECT_CALL(*this, OnStateChanged()).Times(2);
Vitaly Buka4c981352015-10-01 23:04:24 -070068 mgr_->AddChangedCallback(
Vitaly Buka247620b2015-05-26 15:42:20 -070069 base::Bind(&StateManagerTest::OnStateChanged, base::Unretained(this)));
70
Vitaly Buka64b4f062015-09-30 20:46:23 -070071 LoadStateDefinition(GetTestSchema().get(), nullptr);
Vitaly Buka216e86d2015-10-06 20:23:02 -070072 ASSERT_TRUE(mgr_->SetProperties(*GetTestValues().get(), nullptr));
Alex Vakulenko07216fe2014-09-19 15:31:09 -070073 }
Vitaly Buka7c82d292015-05-03 18:08:12 -070074 void TearDown() override { mgr_.reset(); }
Alex Vakulenko07216fe2014-09-19 15:31:09 -070075
76 void LoadStateDefinition(const base::DictionaryValue* json,
Vitaly Buka0801a1f2015-08-14 10:03:46 -070077 ErrorPtr* error) {
Vitaly Buka64b4f062015-09-30 20:46:23 -070078 ASSERT_TRUE(mgr_->LoadStateDefinition(*json, error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -070079 }
80
Vitaly Buka247620b2015-05-26 15:42:20 -070081 bool SetPropertyValue(const std::string& name,
Vitaly Bukae527a642015-07-28 21:39:45 -070082 const base::Value& value,
Vitaly Buka0801a1f2015-08-14 10:03:46 -070083 ErrorPtr* error) {
Vitaly Buka247620b2015-05-26 15:42:20 -070084 return mgr_->SetPropertyValue(name, value, timestamp_, error);
85 }
86
87 MOCK_CONST_METHOD0(OnStateChanged, void());
88
89 base::Time timestamp_{base::Time::Now()};
Alex Vakulenko07216fe2014-09-19 15:31:09 -070090 std::unique_ptr<StateManager> mgr_;
Vitaly Buka6b61e572015-08-05 23:16:13 -070091 testing::StrictMock<MockStateChangeQueueInterface> mock_state_change_queue_;
Alex Vakulenko07216fe2014-09-19 15:31:09 -070092};
93
94TEST(StateManager, Empty) {
Vitaly Buka6b61e572015-08-05 23:16:13 -070095 testing::StrictMock<MockStateChangeQueueInterface> mock_state_change_queue;
Alex Vakulenko57123b22014-10-28 13:50:16 -070096 StateManager manager(&mock_state_change_queue);
Alex Vakulenko07216fe2014-09-19 15:31:09 -070097}
98
99TEST_F(StateManagerTest, Initialized) {
Vitaly Buka7c82d292015-05-03 18:08:12 -0700100 auto expected = R"({
101 'base': {
Vitaly Buka9df6c102015-07-28 15:43:17 -0700102 'manufacturer': 'Test Factory',
103 'serialNumber': 'Test Model'
Vitaly Buka7c82d292015-05-03 18:08:12 -0700104 },
Vitaly Buka9df6c102015-07-28 15:43:17 -0700105 'device': {
106 'state_property': ''
Vitaly Buka7c82d292015-05-03 18:08:12 -0700107 }
108 })";
Vitaly Buka95d62562015-10-01 22:05:27 -0700109 EXPECT_JSON_EQ(expected, *mgr_->GetState());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700110}
111
112TEST_F(StateManagerTest, LoadStateDefinition) {
113 auto dict = CreateDictionaryValue(R"({
114 'power': {
115 'battery_level':'integer'
116 }
117 })");
Vitaly Buka64b4f062015-09-30 20:46:23 -0700118 LoadStateDefinition(dict.get(), nullptr);
Vitaly Buka7c82d292015-05-03 18:08:12 -0700119
120 auto expected = R"({
121 'base': {
Vitaly Buka9df6c102015-07-28 15:43:17 -0700122 'manufacturer': 'Test Factory',
123 'serialNumber': 'Test Model'
Vitaly Buka7c82d292015-05-03 18:08:12 -0700124 },
125 'power': {
126 'battery_level': 0
127 },
Vitaly Buka9df6c102015-07-28 15:43:17 -0700128 'device': {
129 'state_property': ''
Vitaly Buka7c82d292015-05-03 18:08:12 -0700130 }
131 })";
Vitaly Buka95d62562015-10-01 22:05:27 -0700132 EXPECT_JSON_EQ(expected, *mgr_->GetState());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700133}
134
Vitaly Bukae0425e42015-08-18 15:50:24 -0700135TEST_F(StateManagerTest, Startup) {
Vitaly Bukae0425e42015-08-18 15:50:24 -0700136 StateManager manager(&mock_state_change_queue_);
137
Vitaly Buka68af3872015-10-27 16:19:00 -0700138 auto state_definition = R"({
139 "base": {
140 "firmwareVersion": "string",
141 "localDiscoveryEnabled": "boolean",
142 "localAnonymousAccessMaxRole": [ "none", "viewer", "user" ],
143 "localPairingEnabled": "boolean"
144 },
145 "power": {"battery_level":"integer"}
146 })";
147 ASSERT_TRUE(manager.LoadStateDefinitionFromJson(state_definition, nullptr));
148
149 auto state_values = R"({
150 "base": {
151 "firmwareVersion": "unknown",
152 "localDiscoveryEnabled": false,
153 "localAnonymousAccessMaxRole": "none",
154 "localPairingEnabled": false
155 },
156 "power": {"battery_level":44}
157 })";
158 ASSERT_TRUE(manager.SetPropertiesFromJson(state_values, nullptr));
Vitaly Bukae0425e42015-08-18 15:50:24 -0700159
160 auto expected = R"({
161 'base': {
Vitaly Bukae5b20412015-09-30 15:41:28 -0700162 'firmwareVersion': 'unknown',
163 'localAnonymousAccessMaxRole': 'none',
164 'localDiscoveryEnabled': false,
Vitaly Buka68af3872015-10-27 16:19:00 -0700165 'localPairingEnabled': false
Vitaly Bukae0425e42015-08-18 15:50:24 -0700166 },
167 'power': {
168 'battery_level': 44
Vitaly Bukae0425e42015-08-18 15:50:24 -0700169 }
170 })";
Vitaly Buka95d62562015-10-01 22:05:27 -0700171 EXPECT_JSON_EQ(expected, *manager.GetState());
Vitaly Bukae0425e42015-08-18 15:50:24 -0700172}
173
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700174TEST_F(StateManagerTest, SetPropertyValue) {
Vitaly Buka774cdf52015-07-21 13:55:00 -0700175 ValueMap expected_prop_set{
Vitaly Buka0f6b2ec2015-08-20 15:35:19 -0700176 {"device.state_property", test::make_string_prop_value("Test Value")},
Alex Vakulenko57123b22014-10-28 13:50:16 -0700177 };
178 EXPECT_CALL(mock_state_change_queue_,
Vitaly Buka247620b2015-05-26 15:42:20 -0700179 NotifyPropertiesUpdated(timestamp_, expected_prop_set))
Alex Vakulenko57123b22014-10-28 13:50:16 -0700180 .WillOnce(Return(true));
Vitaly Buka9df6c102015-07-28 15:43:17 -0700181 ASSERT_TRUE(SetPropertyValue("device.state_property",
Vitaly Bukae527a642015-07-28 21:39:45 -0700182 base::StringValue{"Test Value"}, nullptr));
Vitaly Buka7c82d292015-05-03 18:08:12 -0700183 auto expected = R"({
184 'base': {
Vitaly Buka9df6c102015-07-28 15:43:17 -0700185 'manufacturer': 'Test Factory',
186 'serialNumber': 'Test Model'
Vitaly Buka7c82d292015-05-03 18:08:12 -0700187 },
Vitaly Buka9df6c102015-07-28 15:43:17 -0700188 'device': {
189 'state_property': 'Test Value'
Vitaly Buka7c82d292015-05-03 18:08:12 -0700190 }
191 })";
Vitaly Buka95d62562015-10-01 22:05:27 -0700192 EXPECT_JSON_EQ(expected, *mgr_->GetState());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700193}
194
195TEST_F(StateManagerTest, SetPropertyValue_Error_NoName) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700196 ErrorPtr error;
Vitaly Bukae527a642015-07-28 21:39:45 -0700197 ASSERT_FALSE(SetPropertyValue("", base::FundamentalValue{0}, &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700198 EXPECT_EQ(errors::state::kDomain, error->GetDomain());
199 EXPECT_EQ(errors::state::kPropertyNameMissing, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700200}
201
202TEST_F(StateManagerTest, SetPropertyValue_Error_NoPackage) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700203 ErrorPtr error;
Vitaly Bukae527a642015-07-28 21:39:45 -0700204 ASSERT_FALSE(
205 SetPropertyValue("state_property", base::FundamentalValue{0}, &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700206 EXPECT_EQ(errors::state::kDomain, error->GetDomain());
207 EXPECT_EQ(errors::state::kPackageNameMissing, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700208}
209
210TEST_F(StateManagerTest, SetPropertyValue_Error_UnknownPackage) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700211 ErrorPtr error;
Vitaly Bukae527a642015-07-28 21:39:45 -0700212 ASSERT_FALSE(
213 SetPropertyValue("power.level", base::FundamentalValue{0}, &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700214 EXPECT_EQ(errors::state::kDomain, error->GetDomain());
215 EXPECT_EQ(errors::state::kPropertyNotDefined, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700216}
217
218TEST_F(StateManagerTest, SetPropertyValue_Error_UnknownProperty) {
Vitaly Buka0801a1f2015-08-14 10:03:46 -0700219 ErrorPtr error;
Vitaly Bukae527a642015-07-28 21:39:45 -0700220 ASSERT_FALSE(
221 SetPropertyValue("base.level", base::FundamentalValue{0}, &error));
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700222 EXPECT_EQ(errors::state::kDomain, error->GetDomain());
223 EXPECT_EQ(errors::state::kPropertyNotDefined, error->GetCode());
Alex Vakulenko07216fe2014-09-19 15:31:09 -0700224}
225
Alex Vakulenkoff73cf22014-10-29 09:53:52 -0700226TEST_F(StateManagerTest, GetAndClearRecordedStateChanges) {
Vitaly Buka247620b2015-05-26 15:42:20 -0700227 EXPECT_CALL(mock_state_change_queue_, NotifyPropertiesUpdated(timestamp_, _))
Alex Vakulenko57123b22014-10-28 13:50:16 -0700228 .WillOnce(Return(true));
Vitaly Buka9df6c102015-07-28 15:43:17 -0700229 ASSERT_TRUE(SetPropertyValue("device.state_property",
Vitaly Bukae527a642015-07-28 21:39:45 -0700230 base::StringValue{"Test Value"}, nullptr));
Alex Vakulenko57123b22014-10-28 13:50:16 -0700231 std::vector<StateChange> expected_val;
Alex Vakulenkoff73cf22014-10-29 09:53:52 -0700232 expected_val.emplace_back(
Vitaly Buka9df6c102015-07-28 15:43:17 -0700233 timestamp_, ValueMap{{"device.state_property",
Vitaly Buka0f6b2ec2015-08-20 15:35:19 -0700234 test::make_string_prop_value("Test Value")}});
Alex Vakulenko57123b22014-10-28 13:50:16 -0700235 EXPECT_CALL(mock_state_change_queue_, GetAndClearRecordedStateChanges())
236 .WillOnce(Return(expected_val));
Vitaly Buka6b61e572015-08-05 23:16:13 -0700237 EXPECT_CALL(mock_state_change_queue_, GetLastStateChangeId())
238 .WillOnce(Return(0));
Alex Vakulenko57123b22014-10-28 13:50:16 -0700239 auto changes = mgr_->GetAndClearRecordedStateChanges();
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700240 ASSERT_EQ(1, changes.second.size());
241 EXPECT_EQ(expected_val.back().timestamp, changes.second.back().timestamp);
Alex Vakulenkoff73cf22014-10-29 09:53:52 -0700242 EXPECT_EQ(expected_val.back().changed_properties,
Alex Vakulenkobe4254b2015-06-26 11:34:03 -0700243 changes.second.back().changed_properties);
Alex Vakulenko57123b22014-10-28 13:50:16 -0700244}
245
Vitaly Buka247620b2015-05-26 15:42:20 -0700246TEST_F(StateManagerTest, SetProperties) {
Vitaly Buka774cdf52015-07-21 13:55:00 -0700247 ValueMap expected_prop_set{
Vitaly Buka0f6b2ec2015-08-20 15:35:19 -0700248 {"base.manufacturer", test::make_string_prop_value("No Name")},
Vitaly Buka247620b2015-05-26 15:42:20 -0700249 };
250 EXPECT_CALL(mock_state_change_queue_,
251 NotifyPropertiesUpdated(_, expected_prop_set))
252 .WillOnce(Return(true));
253
254 EXPECT_CALL(*this, OnStateChanged()).Times(1);
255 ASSERT_TRUE(mgr_->SetProperties(
Vitaly Buka216e86d2015-10-06 20:23:02 -0700256 *CreateDictionaryValue("{'base':{'manufacturer':'No Name'}}"), nullptr));
Vitaly Buka247620b2015-05-26 15:42:20 -0700257
258 auto expected = R"({
259 'base': {
260 'manufacturer': 'No Name',
Vitaly Buka9df6c102015-07-28 15:43:17 -0700261 'serialNumber': 'Test Model'
Vitaly Buka247620b2015-05-26 15:42:20 -0700262 },
Vitaly Buka9df6c102015-07-28 15:43:17 -0700263 'device': {
264 'state_property': ''
Vitaly Buka247620b2015-05-26 15:42:20 -0700265 }
266 })";
Vitaly Buka95d62562015-10-01 22:05:27 -0700267 EXPECT_JSON_EQ(expected, *mgr_->GetState());
268}
269
270TEST_F(StateManagerTest, GetProperty) {
Vitaly Buka4c981352015-10-01 23:04:24 -0700271 EXPECT_JSON_EQ("'Test Model'", *mgr_->GetProperty("base.serialNumber"));
272 EXPECT_JSON_EQ("''", *mgr_->GetProperty("device.state_property"));
273 EXPECT_EQ(nullptr, mgr_->GetProperty("device.unknown"));
274 EXPECT_EQ(nullptr, mgr_->GetProperty("unknown.state_property"));
Vitaly Buka247620b2015-05-26 15:42:20 -0700275}
276
Vitaly Bukab6f015a2015-07-09 14:59:23 -0700277} // namespace weave