Home | History | Annotate | Download | only in src
      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