Merge remote-tracking branch 'weave/master' into 'weave/dev' ec47eb0 examples/provider/wifi_manager: find iface name 43bf6b7 Update gtest e03c094 Include of gtest_prod.h only building unittests 0dbbf60 AddTo will return AddToTypeProxy for convenience 48a8669 Remove domain from weave::Error 50a147a Enforce printf format literals checking
diff --git a/examples/daemon/common/daemon.h b/examples/daemon/common/daemon.h index 4cccff3..6dc021d 100644 --- a/examples/daemon/common/daemon.h +++ b/examples/daemon/common/daemon.h
@@ -69,10 +69,11 @@ }; Daemon(const Options& opts) - : config_store_{new weave::examples::FileConfigStore( - opts.disable_security_, - opts.model_id_)}, - task_runner_{new weave::examples::EventTaskRunner}, + : task_runner_{new weave::examples::EventTaskRunner}, + config_store_{ + new weave::examples::FileConfigStore(opts.disable_security_, + opts.model_id_, + task_runner_.get())}, http_client_{new weave::examples::CurlHttpClient(task_runner_.get())}, network_{new weave::examples::EventNetworkImpl(task_runner_.get())}, bluetooth_{new weave::examples::BluetoothImpl} { @@ -114,8 +115,8 @@ LOG(INFO) << "Device registered: " << device->GetSettings().cloud_id; } - std::unique_ptr<weave::examples::FileConfigStore> config_store_; std::unique_ptr<weave::examples::EventTaskRunner> task_runner_; + std::unique_ptr<weave::examples::FileConfigStore> config_store_; std::unique_ptr<weave::examples::CurlHttpClient> http_client_; std::unique_ptr<weave::examples::EventNetworkImpl> network_; std::unique_ptr<weave::examples::BluetoothImpl> bluetooth_;
diff --git a/examples/provider/file_config_store.cc b/examples/provider/file_config_store.cc index 6faa242..31efaa7 100644 --- a/examples/provider/file_config_store.cc +++ b/examples/provider/file_config_store.cc
@@ -12,16 +12,27 @@ #include <string> #include <vector> +#include <base/bind.h> + namespace weave { namespace examples { const char kSettingsDir[] = "/var/lib/weave/"; FileConfigStore::FileConfigStore(bool disable_security, - const std::string& model_id) + const std::string& model_id, + provider::TaskRunner* task_runner) : disable_security_{disable_security}, model_id_{model_id}, - settings_path_{"/var/lib/weave/weave_settings_" + model_id + ".json"} {} + task_runner_{task_runner} {} + +std::string FileConfigStore::GetPath(const std::string& name) const { + std::string path{kSettingsDir}; + path += path + "weave_settings_" + model_id_; + if (!name.empty()) + path += "_" + name; + return path + ".json"; +} bool FileConfigStore::LoadDefaults(Settings* settings) { char host_name[HOST_NAME_MAX] = {}; @@ -55,17 +66,25 @@ } std::string FileConfigStore::LoadSettings() { - LOG(INFO) << "Loading settings from " << settings_path_; - std::ifstream str(settings_path_); + return LoadSettings(""); +} + +std::string FileConfigStore::LoadSettings(const std::string& name) { + LOG(INFO) << "Loading settings from " << GetPath(name); + std::ifstream str(GetPath(name)); return std::string(std::istreambuf_iterator<char>(str), std::istreambuf_iterator<char>()); } -void FileConfigStore::SaveSettings(const std::string& settings) { +void FileConfigStore::SaveSettings(const std::string& name, + const std::string& settings, + const DoneCallback& callback) { CHECK(mkdir(kSettingsDir, S_IRWXU) == 0 || errno == EEXIST); - LOG(INFO) << "Saving settings to " << settings_path_; - std::ofstream str(settings_path_); + LOG(INFO) << "Saving settings to " << GetPath(name); + std::ofstream str(GetPath(name)); str << settings; + if (!callback.is_null()) + task_runner_->PostDelayedTask(FROM_HERE, base::Bind(callback, nullptr), {}); } } // namespace examples
diff --git a/examples/provider/file_config_store.h b/examples/provider/file_config_store.h index 578f940..e7398d1 100644 --- a/examples/provider/file_config_store.h +++ b/examples/provider/file_config_store.h
@@ -10,22 +10,30 @@ #include <vector> #include <weave/provider/config_store.h> +#include <weave/provider/task_runner.h> namespace weave { namespace examples { class FileConfigStore : public provider::ConfigStore { public: - FileConfigStore(bool disable_security, const std::string& model_id); + FileConfigStore(bool disable_security, + const std::string& model_id, + provider::TaskRunner* task_runner); bool LoadDefaults(Settings* settings) override; + std::string LoadSettings(const std::string& name) override; + void SaveSettings(const std::string& name, + const std::string& settings, + const DoneCallback& callback) override; + std::string LoadSettings() override; - void SaveSettings(const std::string& settings) override; private: + std::string GetPath(const std::string& name) const; const bool disable_security_; const std::string model_id_; - const std::string settings_path_; + provider::TaskRunner* task_runner_{nullptr}; }; } // namespace examples
diff --git a/file_lists.mk b/file_lists.mk index a018178..8dccd9c 100644 --- a/file_lists.mk +++ b/file_lists.mk
@@ -3,6 +3,8 @@ # found in the LICENSE file. WEAVE_SRC_FILES := \ + src/access_api_handler.cc \ + src/access_black_list_manager_impl.cc \ src/backoff_entry.cc \ src/base_api_handler.cc \ src/commands/cloud_command_proxy.cc \ @@ -48,6 +50,8 @@ src/test/unittest_utils.cc WEAVE_UNITTEST_SRC_FILES := \ + src/access_api_handler_unittest.cc \ + src/access_black_list_manager_impl_unittest.cc \ src/backoff_entry_unittest.cc \ src/base_api_handler_unittest.cc \ src/commands/cloud_command_proxy_unittest.cc \ @@ -162,4 +166,3 @@ third_party/libuweave/src/macaroon_caveat.c \ third_party/libuweave/src/macaroon_context.c \ third_party/libuweave/src/macaroon_encoding.c -
diff --git a/include/weave/provider/config_store.h b/include/weave/provider/config_store.h index 1b7988f..128eccc 100644 --- a/include/weave/provider/config_store.h +++ b/include/weave/provider/config_store.h
@@ -13,6 +13,7 @@ #include <base/callback.h> #include <base/time/time.h> #include <weave/enum_to_string.h> +#include <weave/error.h> #include <weave/settings.h> namespace weave { @@ -36,8 +37,8 @@ // Implementation of LoadSettings() method should load previously // stored settings from the persistent storage (file, flash, etc). // For example: -// std::string FileConfigStore::LoadSettings() { -// std::ifstream str("/var/lib/weave/weave_settings.json"); +// std::string FileConfigStore::LoadSettings(const std::string& name) { +// std::ifstream str("/var/lib/weave/weave_" + name + ".json"); // return std::string(std::istreambuf_iterator<char>(str), // std::istreambuf_iterator<char>()); // } @@ -47,9 +48,14 @@ // Implementation of SaveSettings(...) method should store data in the // persistent storage (file, flash, etc). // For example: -// void FileConfigStore::SaveSettings(const std::string& settings) { -// std::ofstream str(kSettingsPath); +// void FileConfigStore::SaveSettings(const std::string& name, +// const std::string& settings, +// const DoneCallback& callback) { +// std::ofstream str("/var/lib/weave/weave_" + name + ".json"); // str << settings; +// if (!callback.is_null()) +// task_runner_->PostDelayedTask(FROM_HERE, base::Bind(callback, nullptr), +// {}); // } // It is highly recommended to protected data using encryption with // hardware backed key. @@ -67,12 +73,20 @@ // Returns settings saved by SaveSettings during last run of libweave. // Implementation should return data as-is without parsing or modifications. - virtual std::string LoadSettings() = 0; + // |name| is the name of settings blob. Could be used as filename. + virtual std::string LoadSettings(const std::string& name) = 0; // Saves settings. Implementation should save data as-is without parsing or // modifications. Data stored in settings can be sensitive, so it's highly // recommended to protect data, e.g. using encryption. - virtual void SaveSettings(const std::string& settings) = 0; + // |name| is the name of settings blob. Could be used as filename. + // Implementation must call or post callback + virtual void SaveSettings(const std::string& name, + const std::string& settings, + const DoneCallback& callback) = 0; + + // Deprecated: only for migration of old configs to version with |name|. + virtual std::string LoadSettings() = 0; protected: virtual ~ConfigStore() {}
diff --git a/include/weave/provider/test/mock_config_store.h b/include/weave/provider/test/mock_config_store.h index 3873251..a7eb374 100644 --- a/include/weave/provider/test/mock_config_store.h +++ b/include/weave/provider/test/mock_config_store.h
@@ -18,10 +18,13 @@ class MockConfigStore : public ConfigStore { public: - MockConfigStore() { + explicit MockConfigStore(bool set_expectations = true) { using testing::_; using testing::Return; + if (!set_expectations) + return; + EXPECT_CALL(*this, LoadDefaults(_)) .WillRepeatedly(testing::Invoke([](Settings* settings) { settings->firmware_version = "TEST_FIRMWARE"; @@ -39,11 +42,21 @@ "version": 1, "device_id": "TEST_DEVICE_ID" })")); - EXPECT_CALL(*this, SaveSettings(_)).WillRepeatedly(Return()); + EXPECT_CALL(*this, LoadSettings(_)).WillRepeatedly(Return("")); + EXPECT_CALL(*this, SaveSettings(_, _, _)) + .WillRepeatedly(testing::WithArgs<1, 2>(testing::Invoke( + [](const std::string& json, const DoneCallback& callback) { + if (!callback.is_null()) + callback.Run(nullptr); + }))); } MOCK_METHOD1(LoadDefaults, bool(Settings*)); + MOCK_METHOD1(LoadSettings, std::string(const std::string&)); + MOCK_METHOD3(SaveSettings, + void(const std::string&, + const std::string&, + const DoneCallback&)); MOCK_METHOD0(LoadSettings, std::string()); - MOCK_METHOD1(SaveSettings, void(const std::string&)); }; } // namespace test
diff --git a/src/access_api_handler.cc b/src/access_api_handler.cc new file mode 100644 index 0000000..9fa6df2 --- /dev/null +++ b/src/access_api_handler.cc
@@ -0,0 +1,229 @@ +// 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 <base/bind.h> +#include <weave/device.h> + +#include "src/access_black_list_manager.h" +#include "src/commands/schema_constants.h" +#include "src/data_encoding.h" +#include "src/json_error_codes.h" + +namespace weave { + +namespace { + +const char kComponent[] = "accessControl"; +const char kTrait[] = "_accessControlBlackList"; +const char kStateSize[] = "_accessControlBlackList.size"; +const char kStateCapacity[] = "_accessControlBlackList.capacity"; +const char kUserId[] = "userId"; +const char kApplicationId[] = "applicationId"; +const char kExpirationTimeout[] = "expirationTimeoutSec"; +const char kBlackList[] = "blackList"; + +bool GetIds(const base::DictionaryValue& parameters, + std::vector<uint8_t>* user_id_decoded, + std::vector<uint8_t>* app_id_decoded, + ErrorPtr* error) { + std::string user_id; + parameters.GetString(kUserId, &user_id); + if (!Base64Decode(user_id, user_id_decoded)) { + Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain, + errors::commands::kInvalidPropValue, + "Invalid user id '%s'", user_id.c_str()); + return false; + } + + std::string app_id; + parameters.GetString(kApplicationId, &app_id); + if (!Base64Decode(app_id, app_id_decoded)) { + Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain, + errors::commands::kInvalidPropValue, + "Invalid app id '%s'", user_id.c_str()); + return false; + } + + return true; +} + +} // namespace + +AccessApiHandler::AccessApiHandler(Device* device, + AccessBlackListManager* manager) + : device_{device}, manager_{manager} { + device_->AddTraitDefinitionsFromJson(R"({ + "_accessControlBlackList": { + "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 + } + } + } + })"); + CHECK(device_->AddComponent(kComponent, {kTrait}, nullptr)); + UpdateState(); + + device_->AddCommandHandler( + kComponent, "_accessControlBlackList.block", + base::Bind(&AccessApiHandler::Block, weak_ptr_factory_.GetWeakPtr())); + device_->AddCommandHandler( + kComponent, "_accessControlBlackList.unblock", + base::Bind(&AccessApiHandler::Unblock, weak_ptr_factory_.GetWeakPtr())); + device_->AddCommandHandler( + kComponent, "_accessControlBlackList.list", + base::Bind(&AccessApiHandler::List, weak_ptr_factory_.GetWeakPtr())); +} + +void AccessApiHandler::Block(const std::weak_ptr<Command>& cmd) { + auto command = cmd.lock(); + if (!command) + return; + + CHECK(command->GetState() == Command::State::kQueued) + << EnumToString(command->GetState()); + command->SetProgress(base::DictionaryValue{}, nullptr); + + const auto& parameters = command->GetParameters(); + std::vector<uint8_t> user_id; + std::vector<uint8_t> app_id; + ErrorPtr error; + if (!GetIds(parameters, &user_id, &app_id, &error)) { + command->Abort(error.get(), nullptr); + return; + } + + int timeout_sec = 0; + parameters.GetInteger(kExpirationTimeout, &timeout_sec); + + base::Time expiration = + base::Time::Now() + base::TimeDelta::FromSeconds(timeout_sec); + + manager_->Block(user_id, app_id, expiration, + base::Bind(&AccessApiHandler::OnCommandDone, + weak_ptr_factory_.GetWeakPtr(), cmd)); +} + +void AccessApiHandler::Unblock(const std::weak_ptr<Command>& cmd) { + auto command = cmd.lock(); + if (!command) + return; + + CHECK(command->GetState() == Command::State::kQueued) + << EnumToString(command->GetState()); + command->SetProgress(base::DictionaryValue{}, nullptr); + + const auto& parameters = command->GetParameters(); + std::vector<uint8_t> user_id; + std::vector<uint8_t> app_id; + ErrorPtr error; + if (!GetIds(parameters, &user_id, &app_id, &error)) { + command->Abort(error.get(), nullptr); + return; + } + + manager_->Unblock(user_id, app_id, + base::Bind(&AccessApiHandler::OnCommandDone, + weak_ptr_factory_.GetWeakPtr(), cmd)); +} + +void AccessApiHandler::List(const std::weak_ptr<Command>& cmd) { + auto command = cmd.lock(); + if (!command) + return; + + CHECK(command->GetState() == Command::State::kQueued) + << EnumToString(command->GetState()); + command->SetProgress(base::DictionaryValue{}, nullptr); + + std::unique_ptr<base::ListValue> entries{new base::ListValue}; + for (const auto& e : manager_->GetEntries()) { + std::unique_ptr<base::DictionaryValue> entry{new base::DictionaryValue}; + entry->SetString(kUserId, Base64Encode(e.user_id)); + entry->SetString(kApplicationId, Base64Encode(e.app_id)); + entries->Append(entry.release()); + } + + base::DictionaryValue result; + result.Set(kBlackList, entries.release()); + + command->Complete(result, nullptr); +} + +void AccessApiHandler::OnCommandDone(const std::weak_ptr<Command>& cmd, + ErrorPtr error) { + auto command = cmd.lock(); + if (!command) + return; + UpdateState(); + if (error) { + command->Abort(error.get(), nullptr); + return; + } + command->Complete({}, nullptr); +} + +void AccessApiHandler::UpdateState() { + base::DictionaryValue state; + state.SetInteger(kStateSize, manager_->GetSize()); + state.SetInteger(kStateCapacity, manager_->GetCapacity()); + device_->SetStateProperties(kComponent, state, nullptr); +} + +} // namespace weave
diff --git a/src/access_api_handler.h b/src/access_api_handler.h new file mode 100644 index 0000000..821ce02 --- /dev/null +++ b/src/access_api_handler.h
@@ -0,0 +1,47 @@ +// 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. + +#ifndef LIBWEAVE_SRC_ACCESS_API_HANDLER_H_ +#define LIBWEAVE_SRC_ACCESS_API_HANDLER_H_ + +#include <memory> + +#include <base/memory/weak_ptr.h> +#include <weave/error.h> + +namespace weave { + +class AccessBlackListManager; +class Command; +class Device; + +// Handles commands for 'accessControlBlackList' trait. +// Objects of the class subscribe for notification from CommandManager and +// execute incoming commands. +// Handled commands: +// accessControlBlackList.block +// accessControlBlackList.unblock +// accessControlBlackList.list +class AccessApiHandler final { + public: + AccessApiHandler(Device* device, AccessBlackListManager* manager); + + private: + void Block(const std::weak_ptr<Command>& command); + void Unblock(const std::weak_ptr<Command>& command); + void List(const std::weak_ptr<Command>& command); + void UpdateState(); + + void OnCommandDone(const std::weak_ptr<Command>& command, ErrorPtr error); + + Device* device_{nullptr}; + AccessBlackListManager* manager_{nullptr}; + + base::WeakPtrFactory<AccessApiHandler> weak_ptr_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(AccessApiHandler); +}; + +} // namespace weave + +#endif // LIBWEAVE_SRC_ACCESS_API_HANDLER_H_
diff --git a/src/access_api_handler_unittest.cc b/src/access_api_handler_unittest.cc new file mode 100644 index 0000000..a142735 --- /dev/null +++ b/src/access_api_handler_unittest.cc
@@ -0,0 +1,257 @@ +// 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/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()}; + } + + ComponentManagerImpl component_manager_; + 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
diff --git a/src/access_black_list_manager.h b/src/access_black_list_manager.h new file mode 100644 index 0000000..b56226a --- /dev/null +++ b/src/access_black_list_manager.h
@@ -0,0 +1,56 @@ +// 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. + +#ifndef LIBWEAVE_SRC_ACCESS_BLACK_LIST_H_ +#define LIBWEAVE_SRC_ACCESS_BLACK_LIST_H_ + +#include <vector> + +#include <base/time/time.h> + +namespace weave { + +class AccessBlackListManager { + public: + struct Entry { + // user_id is empty, app_id is empty: block everything. + // user_id is not empty, app_id is empty: block if user_id matches. + // user_id is empty, app_id is not empty: block if app_id matches. + // user_id is not empty, app_id is not empty: block if both match. + std::vector<uint8_t> user_id; + std::vector<uint8_t> app_id; + + // Time after which to discard the rule. + base::Time expiration; + }; + virtual ~AccessBlackListManager() = default; + + virtual void Block(const std::vector<uint8_t>& user_id, + const std::vector<uint8_t>& app_id, + const base::Time& expiration, + const DoneCallback& callback) = 0; + virtual void Unblock(const std::vector<uint8_t>& user_id, + const std::vector<uint8_t>& app_id, + const DoneCallback& callback) = 0; + virtual bool IsBlocked(const std::vector<uint8_t>& user_id, + const std::vector<uint8_t>& app_id) const = 0; + virtual std::vector<Entry> GetEntries() const = 0; + virtual size_t GetSize() const = 0; + virtual size_t GetCapacity() const = 0; +}; + +inline bool operator==(const AccessBlackListManager::Entry& l, + const AccessBlackListManager::Entry& r) { + return l.user_id == r.user_id && l.app_id == r.app_id && + l.expiration == r.expiration; +} + +inline bool operator!=(const AccessBlackListManager::Entry& l, + const AccessBlackListManager::Entry& r) { + return !(l == r); +} + +} // namespace weave + +#endif // LIBWEAVE_SRC_ACCESS_BLACK_LIST_H_
diff --git a/src/access_black_list_manager_impl.cc b/src/access_black_list_manager_impl.cc new file mode 100644 index 0000000..e6897ba --- /dev/null +++ b/src/access_black_list_manager_impl.cc
@@ -0,0 +1,164 @@ +// 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_black_list_manager_impl.h" + +#include <base/json/json_reader.h> +#include <base/json/json_writer.h> +#include <base/values.h> + +#include "src/commands/schema_constants.h" +#include "src/data_encoding.h" + +namespace weave { + +namespace { +const char kConfigFileName[] = "black_list"; + +const char kUser[] = "user"; +const char kApp[] = "app"; +const char kExpiration[] = "expiration"; +} + +AccessBlackListManagerImpl::AccessBlackListManagerImpl( + provider::ConfigStore* store, + size_t capacity, + base::Clock* clock) + : capacity_{capacity}, clock_{clock}, store_{store} { + Load(); +} + +void AccessBlackListManagerImpl::Load() { + if (!store_) + return; + if (auto list = base::ListValue::From( + base::JSONReader::Read(store_->LoadSettings(kConfigFileName)))) { + for (const auto& e : *list) { + const base::DictionaryValue* entry{nullptr}; + std::string user; + std::string app; + decltype(entries_)::key_type key; + int expiration; + if (e->GetAsDictionary(&entry) && entry->GetString(kUser, &user) && + Base64Decode(user, &key.first) && entry->GetString(kApp, &app) && + Base64Decode(app, &key.second) && + entry->GetInteger(kExpiration, &expiration)) { + base::Time expiration_time = base::Time::FromTimeT(expiration); + if (expiration_time > clock_->Now()) + entries_[key] = expiration_time; + } + } + if (entries_.size() < list->GetSize()) { + // Save some storage space by saving without expired entries. + Save({}); + } + } +} + +void AccessBlackListManagerImpl::Save(const DoneCallback& callback) { + if (!store_) { + if (!callback.is_null()) + callback.Run(nullptr); + return; + } + + base::ListValue list; + for (const auto& e : entries_) { + scoped_ptr<base::DictionaryValue> entry{new base::DictionaryValue}; + entry->SetString(kUser, Base64Encode(e.first.first)); + entry->SetString(kApp, Base64Encode(e.first.second)); + entry->SetInteger(kExpiration, e.second.ToTimeT()); + list.Append(std::move(entry)); + } + + std::string json; + base::JSONWriter::Write(list, &json); + store_->SaveSettings(kConfigFileName, json, callback); +} + +void AccessBlackListManagerImpl::RemoveExpired() { + for (auto i = begin(entries_); i != end(entries_);) { + if (i->second <= clock_->Now()) + i = entries_.erase(i); + else + ++i; + } +} + +void AccessBlackListManagerImpl::Block(const std::vector<uint8_t>& user_id, + const std::vector<uint8_t>& app_id, + const base::Time& expiration, + const DoneCallback& callback) { + // Iterating is OK as Save below is more expensive. + RemoveExpired(); + if (expiration <= clock_->Now()) { + if (!callback.is_null()) { + ErrorPtr error; + Error::AddTo(&error, FROM_HERE, errors::commands::kDomain, + "aleady_expired", "Entry already expired"); + callback.Run(std::move(error)); + } + return; + } + if (entries_.size() >= capacity_) { + if (!callback.is_null()) { + ErrorPtr error; + Error::AddTo(&error, FROM_HERE, errors::commands::kDomain, + "blacklist_is_full", "Unable to store more entries"); + callback.Run(std::move(error)); + } + return; + } + auto& value = entries_[std::make_pair(user_id, app_id)]; + value = std::max(value, expiration); + Save(callback); +} + +void AccessBlackListManagerImpl::Unblock(const std::vector<uint8_t>& user_id, + const std::vector<uint8_t>& app_id, + const DoneCallback& callback) { + if (!entries_.erase(std::make_pair(user_id, app_id))) { + if (!callback.is_null()) { + ErrorPtr error; + Error::AddTo(&error, FROM_HERE, errors::commands::kDomain, + "entry_not_found", "Unknown entry"); + callback.Run(std::move(error)); + } + return; + } + // Iterating is OK as Save below is more expensive. + RemoveExpired(); + Save(callback); +} + +bool AccessBlackListManagerImpl::IsBlocked( + const std::vector<uint8_t>& user_id, + const std::vector<uint8_t>& app_id) const { + for (const auto& user : {{}, user_id}) { + for (const auto& app : {{}, app_id}) { + auto both = entries_.find(std::make_pair(user, app)); + if (both != end(entries_) && both->second > clock_->Now()) + return true; + } + } + return false; +} + +std::vector<AccessBlackListManager::Entry> +AccessBlackListManagerImpl::GetEntries() const { + std::vector<Entry> result; + for (const auto& e : entries_) + result.push_back({e.first.first, e.first.second, e.second}); + return result; +} + +size_t AccessBlackListManagerImpl::GetSize() const { + return entries_.size(); +} + +size_t AccessBlackListManagerImpl::GetCapacity() const { + return capacity_; +} + +} // namespace weave
diff --git a/src/access_black_list_manager_impl.h b/src/access_black_list_manager_impl.h new file mode 100644 index 0000000..1c175db --- /dev/null +++ b/src/access_black_list_manager_impl.h
@@ -0,0 +1,58 @@ +// 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. + +#ifndef LIBWEAVE_SRC_ACCESS_BLACK_LIST_IMPL_H_ +#define LIBWEAVE_SRC_ACCESS_BLACK_LIST_IMPL_H_ + +#include <map> +#include <utility> + +#include <base/time/default_clock.h> +#include <base/time/time.h> +#include <weave/error.h> +#include <weave/provider/config_store.h> + +#include "src/access_black_list_manager.h" + +namespace weave { + +class AccessBlackListManagerImpl : public AccessBlackListManager { + public: + explicit AccessBlackListManagerImpl(provider::ConfigStore* store, + size_t capacity = 1024, + base::Clock* clock = nullptr); + + // AccessBlackListManager implementation. + void Block(const std::vector<uint8_t>& user_id, + const std::vector<uint8_t>& app_id, + const base::Time& expiration, + const DoneCallback& callback) override; + void Unblock(const std::vector<uint8_t>& user_id, + const std::vector<uint8_t>& app_id, + const DoneCallback& callback) override; + bool IsBlocked(const std::vector<uint8_t>& user_id, + const std::vector<uint8_t>& app_id) const override; + std::vector<Entry> GetEntries() const override; + size_t GetSize() const override; + size_t GetCapacity() const override; + + private: + void Load(); + void Save(const DoneCallback& callback); + void RemoveExpired(); + + const size_t capacity_{0}; + base::DefaultClock default_clock_; + base::Clock* clock_{&default_clock_}; + + provider::ConfigStore* store_{nullptr}; + std::map<std::pair<std::vector<uint8_t>, std::vector<uint8_t>>, base::Time> + entries_; + + DISALLOW_COPY_AND_ASSIGN(AccessBlackListManagerImpl); +}; + +} // namespace weave + +#endif // LIBWEAVE_SRC_ACCESS_BLACK_LIST_IMPL_H_
diff --git a/src/access_black_list_manager_impl_unittest.cc b/src/access_black_list_manager_impl_unittest.cc new file mode 100644 index 0000000..2b6d66e --- /dev/null +++ b/src/access_black_list_manager_impl_unittest.cc
@@ -0,0 +1,167 @@ +// 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_black_list_manager_impl.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <weave/provider/test/mock_config_store.h> +#include <weave/test/unittest_utils.h> + +#include "src/test/mock_clock.h" +#include "src/bind_lambda.h" + +using testing::_; +using testing::Return; +using testing::StrictMock; + +namespace weave { + +class AccessBlackListManagerImplTest : public testing::Test { + protected: + void SetUp() { + std::string to_load = R"([{ + "user": "BQID", + "app": "BwQF", + "expiration": 1410000000 + }, { + "user": "AQID", + "app": "AwQF", + "expiration": 1419999999 + }])"; + + EXPECT_CALL(config_store_, LoadSettings("black_list")) + .WillOnce(Return(to_load)); + + EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) + .WillOnce(testing::WithArgs<1, 2>(testing::Invoke( + [](const std::string& json, const DoneCallback& callback) { + std::string to_save = R"([{ + "user": "AQID", + "app": "AwQF", + "expiration": 1419999999 + }])"; + EXPECT_JSON_EQ(to_save, *test::CreateValue(json)); + if (!callback.is_null()) + callback.Run(nullptr); + }))); + + EXPECT_CALL(clock_, Now()) + .WillRepeatedly(Return(base::Time::FromTimeT(1412121212))); + manager_.reset(new AccessBlackListManagerImpl{&config_store_, 10, &clock_}); + } + StrictMock<test::MockClock> clock_; + StrictMock<provider::test::MockConfigStore> config_store_{false}; + std::unique_ptr<AccessBlackListManagerImpl> manager_; +}; + +TEST_F(AccessBlackListManagerImplTest, Init) { + EXPECT_EQ(1u, manager_->GetSize()); + EXPECT_EQ(10u, manager_->GetCapacity()); + EXPECT_EQ((std::vector<AccessBlackListManagerImpl::Entry>{{ + {1, 2, 3}, {3, 4, 5}, base::Time::FromTimeT(1419999999), + }}), + manager_->GetEntries()); +} + +TEST_F(AccessBlackListManagerImplTest, Block) { + EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) + .WillOnce(testing::WithArgs<1, 2>(testing::Invoke( + [](const std::string& json, const DoneCallback& callback) { + std::string to_save = R"([{ + "user": "AQID", + "app": "AwQF", + "expiration": 1419999999 + }, { + "app": "CAgI", + "user": "BwcH", + "expiration": 1419990000 + }])"; + EXPECT_JSON_EQ(to_save, *test::CreateValue(json)); + if (!callback.is_null()) + callback.Run(nullptr); + }))); + manager_->Block({7, 7, 7}, {8, 8, 8}, base::Time::FromTimeT(1419990000), {}); +} + +TEST_F(AccessBlackListManagerImplTest, BlockExpired) { + manager_->Block( + {}, {}, base::Time::FromTimeT(1400000000), base::Bind([](ErrorPtr error) { + EXPECT_TRUE(error->HasError("command_schema", "aleady_expired")); + })); +} + +TEST_F(AccessBlackListManagerImplTest, BlockListIsFull) { + EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) + .WillRepeatedly(testing::WithArgs<1, 2>(testing::Invoke( + [](const std::string& json, const DoneCallback& callback) { + if (!callback.is_null()) + callback.Run(nullptr); + }))); + for (size_t i = manager_->GetSize(); i < manager_->GetCapacity(); ++i) { + manager_->Block( + {99, static_cast<uint8_t>(i / 256), static_cast<uint8_t>(i % 256)}, + {8, 8, 8}, base::Time::FromTimeT(1419990000), {}); + EXPECT_EQ(i + 1, manager_->GetSize()); + } + manager_->Block( + {99}, {8, 8, 8}, base::Time::FromTimeT(1419990000), + base::Bind([](ErrorPtr error) { + EXPECT_TRUE(error->HasError("command_schema", "blacklist_is_full")); + })); +} + +TEST_F(AccessBlackListManagerImplTest, Unblock) { + EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) + .WillOnce(testing::WithArgs<1, 2>(testing::Invoke( + [](const std::string& json, const DoneCallback& callback) { + EXPECT_JSON_EQ("[]", *test::CreateValue(json)); + if (!callback.is_null()) + callback.Run(nullptr); + }))); + manager_->Unblock({1, 2, 3}, {3, 4, 5}, {}); +} + +TEST_F(AccessBlackListManagerImplTest, UnblockNotFound) { + manager_->Unblock( + {5, 2, 3}, {5, 4, 5}, base::Bind([](ErrorPtr error) { + EXPECT_TRUE(error->HasError("command_schema", "entry_not_found")); + })); +} + +TEST_F(AccessBlackListManagerImplTest, IsBlockedFalse) { + EXPECT_FALSE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8})); +} + +class AccessBlackListManagerImplIsBlockedTest + : public AccessBlackListManagerImplTest, + public testing::WithParamInterface< + std::tuple<std::vector<uint8_t>, std::vector<uint8_t>>> { + public: + void SetUp() override { + AccessBlackListManagerImplTest::SetUp(); + EXPECT_CALL(config_store_, SaveSettings("black_list", _, _)) + .WillOnce(testing::WithArgs<2>( + testing::Invoke([](const DoneCallback& callback) { + if (!callback.is_null()) + callback.Run(nullptr); + }))); + manager_->Block(std::get<0>(GetParam()), std::get<1>(GetParam()), + base::Time::FromTimeT(1419990000), {}); + } +}; + +TEST_P(AccessBlackListManagerImplIsBlockedTest, IsBlocked) { + EXPECT_TRUE(manager_->IsBlocked({7, 7, 7}, {8, 8, 8})); +} + +INSTANTIATE_TEST_CASE_P( + Filters, + AccessBlackListManagerImplIsBlockedTest, + testing::Combine(testing::Values(std::vector<uint8_t>{}, + std::vector<uint8_t>{7, 7, 7}), + testing::Values(std::vector<uint8_t>{}, + std::vector<uint8_t>{8, 8, 8}))); + +} // namespace weave
diff --git a/src/base_api_handler.h b/src/base_api_handler.h index 1dbbac8..6eebfca 100644 --- a/src/base_api_handler.h +++ b/src/base_api_handler.h
@@ -33,7 +33,7 @@ void OnConfigChanged(const Settings& settings); DeviceRegistrationInfo* device_info_; - Device* device_; + Device* device_{nullptr}; base::WeakPtrFactory<BaseApiHandler> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(BaseApiHandler);
diff --git a/src/config.cc b/src/config.cc index 76be205..44d20dd 100644 --- a/src/config.cc +++ b/src/config.cc
@@ -18,9 +18,12 @@ #include "src/data_encoding.h" #include "src/privet/privet_types.h" #include "src/string_utils.h" +#include "src/bind_lambda.h" namespace weave { +const char kConfigName[] = "config"; + namespace config_keys { const char kVersion[] = "version"; @@ -139,9 +142,12 @@ void Config::Transaction::LoadState() { if (!config_->config_store_) return; - std::string json_string = config_->config_store_->LoadSettings(); - if (json_string.empty()) - return; + std::string json_string = config_->config_store_->LoadSettings(kConfigName); + if (json_string.empty()) { + json_string = config_->config_store_->LoadSettings(); + if (json_string.empty()) + return; + } auto value = base::JSONReader::Read(json_string); base::DictionaryValue* dict = nullptr; @@ -266,7 +272,9 @@ base::JSONWriter::WriteWithOptions( dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string); - config_store_->SaveSettings(json_string); + config_store_->SaveSettings( + kConfigName, json_string, + base::Bind([](ErrorPtr error) { CHECK(!error); })); } Config::Transaction::~Transaction() {
diff --git a/src/config_unittest.cc b/src/config_unittest.cc index 0367516..fbb558a 100644 --- a/src/config_unittest.cc +++ b/src/config_unittest.cc
@@ -17,18 +17,20 @@ using testing::_; using testing::Invoke; using testing::Return; +using testing::WithArgs; namespace weave { +const char kConfigName[] = "config"; + class ConfigTest : public ::testing::Test { protected: void SetUp() override { - EXPECT_CALL(*this, OnConfigChanged(_)) - .Times(1); // Called from AddOnChangedCallback Reload(); } void Reload() { + EXPECT_CALL(*this, OnConfigChanged(_)).Times(1); config_.reset(new Config{&config_store_}); config_->AddOnChangedCallback( base::Bind(&ConfigTest::OnConfigChanged, base::Unretained(this))); @@ -86,31 +88,45 @@ } TEST_F(ConfigTest, LoadStateV0) { - EXPECT_CALL(config_store_, LoadSettings()) + EXPECT_CALL(config_store_, LoadSettings(kConfigName)) .WillOnce(Return(R"({ "device_id": "state_device_id" })")); - EXPECT_CALL(*this, OnConfigChanged(_)).Times(1); Reload(); EXPECT_EQ("state_device_id", GetSettings().cloud_id); EXPECT_FALSE(GetSettings().device_id.empty()); EXPECT_NE(GetSettings().cloud_id, GetSettings().device_id); - EXPECT_CALL(config_store_, LoadSettings()) + EXPECT_CALL(config_store_, LoadSettings(kConfigName)) .WillOnce(Return(R"({ "device_id": "state_device_id", "cloud_id": "state_cloud_id" })")); - EXPECT_CALL(*this, OnConfigChanged(_)).Times(1); Reload(); EXPECT_EQ("state_cloud_id", GetSettings().cloud_id); EXPECT_EQ("state_device_id", GetSettings().device_id); } +TEST_F(ConfigTest, LoadStateUnnamed) { + EXPECT_CALL(config_store_, LoadSettings(kConfigName)).WillOnce(Return("")); + + EXPECT_CALL(config_store_, LoadSettings()).Times(1); + + Reload(); +} + +TEST_F(ConfigTest, LoadStateNamed) { + EXPECT_CALL(config_store_, LoadSettings(kConfigName)).WillOnce(Return("{}")); + + EXPECT_CALL(config_store_, LoadSettings()).Times(0); + + Reload(); +} + TEST_F(ConfigTest, LoadState) { auto state = R"({ "version": 1, @@ -133,9 +149,8 @@ "secret": "c3RhdGVfc2VjcmV0", "service_url": "state_service_url" })"; - EXPECT_CALL(config_store_, LoadSettings()).WillOnce(Return(state)); + EXPECT_CALL(config_store_, LoadSettings(kConfigName)).WillOnce(Return(state)); - EXPECT_CALL(*this, OnConfigChanged(_)).Times(1); Reload(); EXPECT_EQ("state_client_id", GetSettings().client_id); @@ -243,9 +258,10 @@ EXPECT_CALL(*this, OnConfigChanged(_)).Times(1); - EXPECT_CALL(config_store_, SaveSettings(_)) - .WillOnce(Invoke([](const std::string& json) { - auto expected = R"({ + EXPECT_CALL(config_store_, SaveSettings(kConfigName, _, _)) + .WillOnce(WithArgs<1, 2>( + Invoke([](const std::string& json, const DoneCallback& callback) { + auto expected = R"({ 'version': 1, 'api_key': 'set_api_key', 'client_id': 'set_client_id', @@ -266,8 +282,9 @@ 'secret': 'AQIDBAU=', 'service_url': 'set_service_url' })"; - EXPECT_JSON_EQ(expected, *test::CreateValue(json)); - })); + EXPECT_JSON_EQ(expected, *test::CreateValue(json)); + callback.Run(nullptr); + }))); change.Commit(); }
diff --git a/src/device_manager.cc b/src/device_manager.cc index 04d7a6b..8eed558 100644 --- a/src/device_manager.cc +++ b/src/device_manager.cc
@@ -8,6 +8,8 @@ #include <base/bind.h> +#include "src/access_api_handler.h" +#include "src/access_black_list_manager_impl.h" #include "src/base_api_handler.h" #include "src/commands/schema_constants.h" #include "src/component_manager_impl.h" @@ -40,6 +42,10 @@ network, auth_manager_.get())); base_api_handler_.reset(new BaseApiHandler{device_info_.get(), this}); + black_list_manager_.reset(new AccessBlackListManagerImpl{config_store}); + access_api_handler_.reset( + new AccessApiHandler{this, black_list_manager_.get()}); + device_info_->Start(); if (http_server) {
diff --git a/src/device_manager.h b/src/device_manager.h index d40ba8e..d77bacc 100644 --- a/src/device_manager.h +++ b/src/device_manager.h
@@ -10,6 +10,8 @@ namespace weave { +class AccessApiHandler; +class AccessBlackListManager; class BaseApiHandler; class Config; class ComponentManager; @@ -107,6 +109,8 @@ std::unique_ptr<ComponentManager> component_manager_; std::unique_ptr<DeviceRegistrationInfo> device_info_; std::unique_ptr<BaseApiHandler> base_api_handler_; + std::unique_ptr<AccessBlackListManager> black_list_manager_; + std::unique_ptr<AccessApiHandler> access_api_handler_; std::unique_ptr<privet::Manager> privet_; base::WeakPtrFactory<DeviceManager> weak_ptr_factory_{this};
diff --git a/src/weave_unittest.cc b/src/weave_unittest.cc index 5bef931..ebc66cd 100644 --- a/src/weave_unittest.cc +++ b/src/weave_unittest.cc
@@ -204,10 +204,6 @@ }))); } - void InitConfigStore() { - EXPECT_CALL(config_store_, SaveSettings("")).WillRepeatedly(Return()); - } - void InitNetwork() { EXPECT_CALL(network_, AddConnectionChangedCallback(_)) .WillRepeatedly(Invoke( @@ -267,7 +263,6 @@ } void InitDefaultExpectations() { - InitConfigStore(); InitNetwork(); EXPECT_CALL(wifi_, StartAccessPoint(MatchesRegex("TEST_NAME.*prv"))) .WillOnce(Return()); @@ -360,13 +355,11 @@ } TEST_F(WeaveTest, StartMinimal) { - InitConfigStore(); device_ = weave::Device::Create(&config_store_, &task_runner_, &http_client_, &network_, nullptr, nullptr, &wifi_, nullptr); } TEST_F(WeaveTest, StartNoWifi) { - InitConfigStore(); InitNetwork(); InitHttpServer(); InitDnsSd(); @@ -450,7 +443,6 @@ void SetUp() override { WeaveTest::SetUp(); - InitConfigStore(); InitHttpServer(); InitNetwork(); InitDnsSd();