|  | // 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 <gtest/gtest.h> | 
|  | #include <weave/provider/test/fake_task_runner.h> | 
|  | #include <weave/test/mock_device.h> | 
|  | #include <weave/test/unittest_utils.h> | 
|  |  | 
|  | #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<uint8_t>&, | 
|  | const std::vector<uint8_t>&, | 
|  | const base::Time&, | 
|  | const DoneCallback&)); | 
|  | MOCK_METHOD3(Unblock, | 
|  | void(const std::vector<uint8_t>&, | 
|  | const std::vector<uint8_t>&, | 
|  | const DoneCallback&)); | 
|  | MOCK_CONST_METHOD2(IsBlocked, | 
|  | bool(const std::vector<uint8_t>&, | 
|  | const std::vector<uint8_t>&)); | 
|  | MOCK_CONST_METHOD0(GetEntries, std::vector<Entry>()); | 
|  | 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<std::string>& 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<base::DictionaryValue> 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<base::DictionaryValue>{state->DeepCopy()}; | 
|  | } | 
|  |  | 
|  | StrictMock<provider::test::FakeTaskRunner> task_runner_; | 
|  | ComponentManagerImpl component_manager_{&task_runner_}; | 
|  | StrictMock<test::MockDevice> device_; | 
|  | StrictMock<MockAccessBlackListManager> access_manager_; | 
|  | std::unique_ptr<AccessApiHandler> 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<uint8_t>{1, 2, 3}, | 
|  | std::vector<uint8_t>{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<uint8_t>{1, 2, 3}, | 
|  | std::vector<uint8_t>{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<AccessBlackListManager::Entry> 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 |