// Copyright 2016 The Weave Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/access_api_handler.h" #include #include #include #include #include "src/component_manager_impl.h" #include "src/access_black_list_manager.h" #include "src/data_encoding.h" using testing::_; using testing::AnyOf; using testing::Invoke; using testing::Return; using testing::StrictMock; using testing::WithArgs; namespace weave { class MockAccessBlackListManager : public AccessBlackListManager { public: MOCK_METHOD4(Block, void(const std::vector&, const std::vector&, const base::Time&, const DoneCallback&)); MOCK_METHOD3(Unblock, void(const std::vector&, const std::vector&, const DoneCallback&)); MOCK_CONST_METHOD2(IsBlocked, bool(const std::vector&, const std::vector&)); MOCK_CONST_METHOD0(GetEntries, std::vector()); MOCK_CONST_METHOD0(GetSize, size_t()); MOCK_CONST_METHOD0(GetCapacity, size_t()); }; class AccessApiHandlerTest : public ::testing::Test { protected: void SetUp() override { EXPECT_CALL(device_, AddTraitDefinitionsFromJson(_)) .WillRepeatedly(Invoke([this](const std::string& json) { EXPECT_TRUE(component_manager_.LoadTraits(json, nullptr)); })); EXPECT_CALL(device_, SetStateProperties(_, _, _)) .WillRepeatedly( Invoke(&component_manager_, &ComponentManager::SetStateProperties)); EXPECT_CALL(device_, SetStateProperty(_, _, _, _)) .WillRepeatedly( Invoke(&component_manager_, &ComponentManager::SetStateProperty)); EXPECT_CALL(device_, AddComponent(_, _, _)) .WillRepeatedly(Invoke([this](const std::string& name, const std::vector& traits, ErrorPtr* error) { return component_manager_.AddComponent("", name, traits, error); })); EXPECT_CALL(device_, AddCommandHandler(_, AnyOf("_accessControlBlackList.block", "_accessControlBlackList.unblock", "_accessControlBlackList.list"), _)) .WillRepeatedly( Invoke(&component_manager_, &ComponentManager::AddCommandHandler)); EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(0)); EXPECT_CALL(access_manager_, GetCapacity()).WillRepeatedly(Return(10)); handler_.reset(new AccessApiHandler{&device_, &access_manager_}); } const base::DictionaryValue& AddCommand(const std::string& command) { std::string id; auto command_instance = component_manager_.ParseCommandInstance( *test::CreateDictionaryValue(command.c_str()), Command::Origin::kLocal, UserRole::kOwner, &id, nullptr); EXPECT_NE(nullptr, command_instance.get()); component_manager_.AddCommand(std::move(command_instance)); EXPECT_EQ(Command::State::kDone, component_manager_.FindCommand(id)->GetState()); return component_manager_.FindCommand(id)->GetResults(); } std::unique_ptr GetState() { std::string path = component_manager_.FindComponentWithTrait("_accessControlBlackList"); EXPECT_FALSE(path.empty()); const auto* component = component_manager_.FindComponent(path, nullptr); EXPECT_TRUE(component); const base::DictionaryValue* state = nullptr; EXPECT_TRUE( component->GetDictionary("state._accessControlBlackList", &state)); return std::unique_ptr{state->DeepCopy()}; } StrictMock task_runner_; ComponentManagerImpl component_manager_{&task_runner_}; StrictMock device_; StrictMock access_manager_; std::unique_ptr handler_; }; TEST_F(AccessApiHandlerTest, Initialization) { const base::DictionaryValue* trait = nullptr; ASSERT_TRUE(component_manager_.GetTraits().GetDictionary( "_accessControlBlackList", &trait)); auto expected = R"({ "commands": { "block": { "minimalRole": "owner", "parameters": { "userId": { "type": "string" }, "applicationId": { "type": "string" }, "expirationTimeoutSec": { "type": "integer" } } }, "unblock": { "minimalRole": "owner", "parameters": { "userId": { "type": "string" }, "applicationId": { "type": "string" } } }, "list": { "minimalRole": "owner", "parameters": {}, "results": { "blackList": { "type": "array", "items": { "type": "object", "properties": { "userId": { "type": "string" }, "applicationId": { "type": "string" } }, "additionalProperties": false } } } } }, "state": { "size": { "type": "integer", "isRequired": true }, "capacity": { "type": "integer", "isRequired": true } } })"; EXPECT_JSON_EQ(expected, *trait); expected = R"({ "capacity": 10, "size": 0 })"; EXPECT_JSON_EQ(expected, *GetState()); } TEST_F(AccessApiHandlerTest, Block) { EXPECT_CALL(access_manager_, Block(std::vector{1, 2, 3}, std::vector{3, 4, 5}, _, _)) .WillOnce(WithArgs<3>( Invoke([](const DoneCallback& callback) { callback.Run(nullptr); }))); EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(1)); AddCommand(R"({ 'name' : '_accessControlBlackList.block', 'component': 'accessControl', 'parameters': { 'userId': 'AQID', 'applicationId': 'AwQF', 'expirationTimeoutSec': 1234 } })"); auto expected = R"({ "capacity": 10, "size": 1 })"; EXPECT_JSON_EQ(expected, *GetState()); } TEST_F(AccessApiHandlerTest, Unblock) { EXPECT_CALL(access_manager_, Unblock(std::vector{1, 2, 3}, std::vector{3, 4, 5}, _)) .WillOnce(WithArgs<2>( Invoke([](const DoneCallback& callback) { callback.Run(nullptr); }))); EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(4)); AddCommand(R"({ 'name' : '_accessControlBlackList.unblock', 'component': 'accessControl', 'parameters': { 'userId': 'AQID', 'applicationId': 'AwQF', 'expirationTimeoutSec': 1234 } })"); auto expected = R"({ "capacity": 10, "size": 4 })"; EXPECT_JSON_EQ(expected, *GetState()); } TEST_F(AccessApiHandlerTest, List) { std::vector entries{ {{11, 12, 13}, {21, 22, 23}, base::Time::FromTimeT(1410000000)}, {{31, 32, 33}, {41, 42, 43}, base::Time::FromTimeT(1420000000)}, }; EXPECT_CALL(access_manager_, GetEntries()).WillOnce(Return(entries)); EXPECT_CALL(access_manager_, GetSize()).WillRepeatedly(Return(4)); auto expected = R"({ "blackList": [ { "applicationId": "FRYX", "userId": "CwwN" }, { "applicationId": "KSor", "userId": "HyAh" } ] })"; const auto& results = AddCommand(R"({ 'name' : '_accessControlBlackList.list', 'component': 'accessControl', 'parameters': { } })"); EXPECT_JSON_EQ(expected, results); } } // namespace weave