1 // Copyright 2015 The Weave Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/base_api_handler.h" 6 7 #include <base/strings/string_number_conversions.h> 8 #include <base/time/default_clock.h> 9 #include <base/values.h> 10 #include <gtest/gtest.h> 11 #include <weave/provider/test/fake_task_runner.h> 12 #include <weave/provider/test/mock_config_store.h> 13 #include <weave/provider/test/mock_http_client.h> 14 #include <weave/test/mock_device.h> 15 #include <weave/test/unittest_utils.h> 16 17 #include "src/component_manager_impl.h" 18 #include "src/config.h" 19 #include "src/device_registration_info.h" 20 21 using testing::_; 22 using testing::AnyOf; 23 using testing::Eq; 24 using testing::Invoke; 25 using testing::Return; 26 using testing::ReturnRef; 27 using testing::StrictMock; 28 29 namespace weave { 30 31 class BaseApiHandlerTest : public ::testing::Test { 32 protected: 33 void SetUp() override { 34 EXPECT_CALL(device_, AddTraitDefinitionsFromJson(_)) 35 .WillRepeatedly(Invoke([this](const std::string& json) { 36 EXPECT_TRUE(component_manager_.LoadTraits(json, nullptr)); 37 })); 38 EXPECT_CALL(device_, SetStateProperties(_, _, _)) 39 .WillRepeatedly( 40 Invoke(&component_manager_, &ComponentManager::SetStateProperties)); 41 EXPECT_CALL(device_, SetStateProperty(_, _, _, _)) 42 .WillRepeatedly( 43 Invoke(&component_manager_, &ComponentManager::SetStateProperty)); 44 EXPECT_CALL(device_, AddComponent(_, _, _)) 45 .WillRepeatedly(Invoke([this](const std::string& name, 46 const std::vector<std::string>& traits, 47 ErrorPtr* error) { 48 return component_manager_.AddComponent("", name, traits, error); 49 })); 50 51 EXPECT_CALL(device_, 52 AddCommandHandler(_, AnyOf("base.updateBaseConfiguration", 53 "base.updateDeviceInfo"), 54 _)) 55 .WillRepeatedly( 56 Invoke(&component_manager_, &ComponentManager::AddCommandHandler)); 57 58 dev_reg_.reset(new DeviceRegistrationInfo(&config_, &component_manager_, 59 nullptr, &http_client_, nullptr, 60 nullptr)); 61 62 EXPECT_CALL(device_, GetSettings()) 63 .WillRepeatedly(ReturnRef(dev_reg_->GetSettings())); 64 65 handler_.reset(new BaseApiHandler{dev_reg_.get(), &device_}); 66 } 67 68 void AddCommand(const std::string& command) { 69 std::string id; 70 auto command_instance = component_manager_.ParseCommandInstance( 71 *test::CreateDictionaryValue(command.c_str()), Command::Origin::kLocal, 72 UserRole::kOwner, &id, nullptr); 73 ASSERT_NE(nullptr, command_instance.get()); 74 component_manager_.AddCommand(std::move(command_instance)); 75 EXPECT_EQ(Command::State::kDone, 76 component_manager_.FindCommand(id)->GetState()); 77 } 78 79 std::unique_ptr<base::DictionaryValue> GetBaseState() { 80 std::unique_ptr<base::DictionaryValue> state; 81 std::string path = component_manager_.FindComponentWithTrait("base"); 82 EXPECT_FALSE(path.empty()); 83 const auto* component = component_manager_.FindComponent(path, nullptr); 84 CHECK(component); 85 const base::DictionaryValue* base_state = nullptr; 86 if (component->GetDictionary("state.base", &base_state)) 87 state.reset(base_state->DeepCopy()); 88 else 89 state.reset(new base::DictionaryValue); 90 return state; 91 } 92 93 provider::test::MockConfigStore config_store_; 94 Config config_{&config_store_}; 95 StrictMock<provider::test::MockHttpClient> http_client_; 96 std::unique_ptr<DeviceRegistrationInfo> dev_reg_; 97 StrictMock<provider::test::FakeTaskRunner> task_runner_; 98 ComponentManagerImpl component_manager_{&task_runner_}; 99 std::unique_ptr<BaseApiHandler> handler_; 100 StrictMock<test::MockDevice> device_; 101 }; 102 103 TEST_F(BaseApiHandlerTest, Initialization) { 104 const base::DictionaryValue* trait = nullptr; 105 ASSERT_TRUE(component_manager_.GetTraits().GetDictionary("base", &trait)); 106 107 auto expected = R"({ 108 "commands": { 109 "updateBaseConfiguration": { 110 "minimalRole": "manager", 111 "parameters": { 112 "localAnonymousAccessMaxRole": { 113 "enum": [ "none", "viewer", "user" ], 114 "type": "string" 115 }, 116 "localDiscoveryEnabled": { 117 "type": "boolean" 118 }, 119 "localPairingEnabled": { 120 "type": "boolean" 121 } 122 } 123 }, 124 "updateDeviceInfo": { 125 "minimalRole": "manager", 126 "parameters": { 127 "description": { 128 "type": "string" 129 }, 130 "location": { 131 "type": "string" 132 }, 133 "name": { 134 "type": "string" 135 } 136 } 137 }, 138 "reboot": { 139 "minimalRole": "user", 140 "parameters": {}, 141 "errors": ["notEnoughBattery"] 142 }, 143 "identify": { 144 "minimalRole": "user", 145 "parameters": {} 146 } 147 }, 148 "state": { 149 "firmwareVersion": { 150 "type": "string", 151 "isRequired": true 152 }, 153 "localDiscoveryEnabled": { 154 "type": "boolean", 155 "isRequired": true 156 }, 157 "localAnonymousAccessMaxRole": { 158 "type": "string", 159 "enum": [ "none", "viewer", "user" ], 160 "isRequired": true 161 }, 162 "localPairingEnabled": { 163 "type": "boolean", 164 "isRequired": true 165 }, 166 "connectionStatus": { 167 "type": "string" 168 }, 169 "network": { 170 "type": "object", 171 "additionalProperties": false, 172 "properties": { 173 "name": { "type": "string" } 174 } 175 } 176 } 177 })"; 178 EXPECT_JSON_EQ(expected, *trait); 179 } 180 181 TEST_F(BaseApiHandlerTest, UpdateBaseConfiguration) { 182 const Settings& settings = dev_reg_->GetSettings(); 183 184 AddCommand(R"({ 185 'name' : 'base.updateBaseConfiguration', 186 'component': 'base', 187 'parameters': { 188 'localDiscoveryEnabled': false, 189 'localAnonymousAccessMaxRole': 'none', 190 'localPairingEnabled': false 191 } 192 })"); 193 EXPECT_EQ(AuthScope::kNone, settings.local_anonymous_access_role); 194 EXPECT_FALSE(settings.local_discovery_enabled); 195 EXPECT_FALSE(settings.local_pairing_enabled); 196 197 auto expected = R"({ 198 'firmwareVersion': 'TEST_FIRMWARE', 199 'localAnonymousAccessMaxRole': 'none', 200 'localDiscoveryEnabled': false, 201 'localPairingEnabled': false 202 })"; 203 EXPECT_JSON_EQ(expected, *GetBaseState()); 204 205 AddCommand(R"({ 206 'name' : 'base.updateBaseConfiguration', 207 'component': 'base', 208 'parameters': { 209 'localDiscoveryEnabled': true, 210 'localAnonymousAccessMaxRole': 'user', 211 'localPairingEnabled': true 212 } 213 })"); 214 EXPECT_EQ(AuthScope::kUser, settings.local_anonymous_access_role); 215 EXPECT_TRUE(settings.local_discovery_enabled); 216 EXPECT_TRUE(settings.local_pairing_enabled); 217 expected = R"({ 218 'firmwareVersion': 'TEST_FIRMWARE', 219 'localAnonymousAccessMaxRole': 'user', 220 'localDiscoveryEnabled': true, 221 'localPairingEnabled': true 222 })"; 223 EXPECT_JSON_EQ(expected, *GetBaseState()); 224 225 { 226 Config::Transaction change{dev_reg_->GetMutableConfig()}; 227 change.set_local_anonymous_access_role(AuthScope::kViewer); 228 } 229 expected = R"({ 230 'firmwareVersion': 'TEST_FIRMWARE', 231 'localAnonymousAccessMaxRole': 'viewer', 232 'localDiscoveryEnabled': true, 233 'localPairingEnabled': true 234 })"; 235 EXPECT_JSON_EQ(expected, *GetBaseState()); 236 } 237 238 TEST_F(BaseApiHandlerTest, UpdateDeviceInfo) { 239 AddCommand(R"({ 240 'name' : 'base.updateDeviceInfo', 241 'component': 'base', 242 'parameters': { 243 'name': 'testName', 244 'description': 'testDescription', 245 'location': 'testLocation' 246 } 247 })"); 248 249 const Settings& config = dev_reg_->GetSettings(); 250 EXPECT_EQ("testName", config.name); 251 EXPECT_EQ("testDescription", config.description); 252 EXPECT_EQ("testLocation", config.location); 253 254 AddCommand(R"({ 255 'name' : 'base.updateDeviceInfo', 256 'component': 'base', 257 'parameters': { 258 'location': 'newLocation' 259 } 260 })"); 261 262 EXPECT_EQ("testName", config.name); 263 EXPECT_EQ("testDescription", config.description); 264 EXPECT_EQ("newLocation", config.location); 265 } 266 267 } // namespace weave 268