Merge remote-tracking branch 'weave/master' into merge
diff --git a/examples/daemon/light/light.cc b/examples/daemon/light/light.cc
index 611a37d..eaf9392 100644
--- a/examples/daemon/light/light.cc
+++ b/examples/daemon/light/light.cc
@@ -283,6 +283,7 @@
int main(int argc, char** argv) {
Daemon::Options opts;
+ opts.model_id_ = "AIAAA";
if (!opts.Parse(argc, argv)) {
Daemon::Options::ShowUsage(argv[0]);
return 1;
diff --git a/examples/daemon/lock/lock.cc b/examples/daemon/lock/lock.cc
index a4bd213..61961f0 100644
--- a/examples/daemon/lock/lock.cc
+++ b/examples/daemon/lock/lock.cc
@@ -129,6 +129,7 @@
int main(int argc, char** argv) {
Daemon::Options opts;
+ opts.model_id_ = "AOAAA";
if (!opts.Parse(argc, argv)) {
Daemon::Options::ShowUsage(argv[0]);
return 1;
diff --git a/examples/daemon/sample/sample.cc b/examples/daemon/sample/sample.cc
index 97cef61..2ab4b27 100644
--- a/examples/daemon/sample/sample.cc
+++ b/examples/daemon/sample/sample.cc
@@ -104,7 +104,7 @@
device_->SetStateProperty(kComponent, "_sample._ping_count",
base::FundamentalValue{++ping_count_}, nullptr);
- LOG(INFO) << "New state: " << device_->GetState();
+ LOG(INFO) << "New component state: " << device_->GetComponents();
base::DictionaryValue result;
cmd->Complete(result, nullptr);
diff --git a/examples/provider/file_config_store.cc b/examples/provider/file_config_store.cc
index 7d4e31b..2214be8 100644
--- a/examples/provider/file_config_store.cc
+++ b/examples/provider/file_config_store.cc
@@ -16,11 +16,10 @@
namespace examples {
const char kSettingsDir[] = "/var/lib/weave/";
-const char kSettingsPath[] = "/var/lib/weave/weave_settings.json";
-const char kCategory[] = "example";
FileConfigStore::FileConfigStore(bool disable_security, const std::string& model_id)
- : disable_security_{disable_security}, model_id_{model_id} {}
+ : disable_security_{disable_security}, model_id_{model_id},
+ settings_path_{"/var/lib/weave/weave_settings_" + model_id + ".json"} {}
bool FileConfigStore::LoadDefaults(Settings* settings) {
char host_name[HOST_NAME_MAX] = {};
@@ -54,16 +53,16 @@
}
std::string FileConfigStore::LoadSettings() {
- LOG(INFO) << "Loading settings from " << kSettingsPath;
- std::ifstream str(kSettingsPath);
+ LOG(INFO) << "Loading settings from " << settings_path_;
+ std::ifstream str(settings_path_);
return std::string(std::istreambuf_iterator<char>(str),
std::istreambuf_iterator<char>());
}
void FileConfigStore::SaveSettings(const std::string& settings) {
CHECK(mkdir(kSettingsDir, S_IRWXU) == 0 || errno == EEXIST);
- LOG(INFO) << "Saving settings to " << kSettingsPath;
- std::ofstream str(kSettingsPath);
+ LOG(INFO) << "Saving settings to " << settings_path_;
+ std::ofstream str(settings_path_);
str << settings;
}
diff --git a/examples/provider/file_config_store.h b/examples/provider/file_config_store.h
index 8764cc5..578f940 100644
--- a/examples/provider/file_config_store.h
+++ b/examples/provider/file_config_store.h
@@ -16,15 +16,16 @@
class FileConfigStore : public provider::ConfigStore {
public:
- explicit FileConfigStore(bool disable_security, const std::string& model_id);
+ FileConfigStore(bool disable_security, const std::string& model_id);
bool LoadDefaults(Settings* settings) override;
std::string LoadSettings() override;
void SaveSettings(const std::string& settings) override;
private:
- bool disable_security_{false};
- std::string model_id_{"AAAAA"};
+ const bool disable_security_;
+ const std::string model_id_;
+ const std::string settings_path_;
};
} // namespace examples
diff --git a/include/weave/device.h b/include/weave/device.h
index 2d7aaff..99035f4 100644
--- a/include/weave/device.h
+++ b/include/weave/device.h
@@ -53,6 +53,10 @@
// Returns the full JSON dictionary containing trait definitions.
virtual const base::DictionaryValue& GetTraits() const = 0;
+ // Sets callback which is called when new trait definitions are added.
+ virtual void AddTraitDefsChangedCallback(
+ const base::Closure& callback) = 0;
+
// Adds a new component instance to device. Traits used by this component
// must be already defined.
virtual bool AddComponent(const std::string& name,
@@ -172,6 +176,7 @@
// Adds provided commands definitions. Can be called multiple times with
// condition that definitions do not conflict.
// Invalid value is fatal.
+ // DO NOT USE IN YOUR CODE: use AddTraitDefinitions() instead.
LIBWEAVE_DEPRECATED virtual void AddCommandDefinitionsFromJson(
const std::string& json) = 0;
LIBWEAVE_DEPRECATED virtual void AddCommandDefinitions(
@@ -182,6 +187,7 @@
// "base.reboot". Each command can have no more than one handler.
// Empty |command_name| sets default handler for all unhanded commands.
// No new command handlers can be set after default handler was set.
+ // DO NOT USE IN YOUR CODE: use AddCommandHandler() with component parameter.
LIBWEAVE_DEPRECATED virtual void AddCommandHandler(
const std::string& command_name,
const CommandHandlerCallback& callback) = 0;
@@ -189,6 +195,7 @@
// Adds provided state definitions. Can be called multiple times with
// condition that definitions do not conflict.
// Invalid value is fatal.
+ // DO NOT USE IN YOUR CODE: use AddTraitDefinitions() instead.
LIBWEAVE_DEPRECATED virtual void AddStateDefinitionsFromJson(
const std::string& json) = 0;
LIBWEAVE_DEPRECATED virtual void AddStateDefinitions(
@@ -201,6 +208,7 @@
// device->SetStatePropertiesFromJson("{'base':{'firmwareVersion':'123'}}")
// Method completely replaces properties included |json| or |dict|.
// Properties of the state not included |json| or |dict| will stay unchanged.
+ // DO NOT USE IN YOUR CODE: use SetStateProperties() with component parameter.
LIBWEAVE_DEPRECATED virtual bool SetStatePropertiesFromJson(
const std::string& json,
ErrorPtr* error) = 0;
@@ -210,19 +218,21 @@
// Returns value of the single property.
// |name| is full property name, including package name. e.g. "base.network".
+ // DO NOT USE IN YOUR CODE: use GetStateProperty() with component parameter.
LIBWEAVE_DEPRECATED virtual const base::Value* GetStateProperty(
const std::string& name) const = 0;
// Sets value of the single property.
// |name| is full property name, including package name. e.g. "base.network".
+ // DO NOT USE IN YOUR CODE: use SetStateProperty() with component parameter.
LIBWEAVE_DEPRECATED virtual bool SetStateProperty(
const std::string& name,
const base::Value& value,
ErrorPtr* error) = 0;
// Returns aggregated state properties across all registered packages.
+ // DO NOT USE IN YOUR CODE: use GetComponents() instead.
LIBWEAVE_DEPRECATED virtual const base::DictionaryValue& GetState() const = 0;
-
};
} // namespace weave
diff --git a/include/weave/export.h b/include/weave/export.h
index f698176..6a658f9 100644
--- a/include/weave/export.h
+++ b/include/weave/export.h
@@ -8,8 +8,6 @@
#define LIBWEAVE_EXPORT __attribute__((__visibility__("default")))
#define LIBWEAVE_PRIVATE __attribute__((__visibility__("hidden")))
-// TODO(avakulenko): Once all the sample clients are migrated to new APIs,
-// mark the old one officially deprecated by uncomment the following attribute.
-#define LIBWEAVE_DEPRECATED // __attribute__((deprecated))
+#define LIBWEAVE_DEPRECATED __attribute__((deprecated))
#endif // LIBWEAVE_INCLUDE_WEAVE_EXPORT_H_
diff --git a/include/weave/test/mock_device.h b/include/weave/test/mock_device.h
index 88cc5e0..612afb9 100644
--- a/include/weave/test/mock_device.h
+++ b/include/weave/test/mock_device.h
@@ -24,6 +24,8 @@
MOCK_METHOD1(AddTraitDefinitionsFromJson, void(const std::string& json));
MOCK_METHOD1(AddTraitDefinitions, void(const base::DictionaryValue& dict));
MOCK_CONST_METHOD0(GetTraits, const base::DictionaryValue&());
+ MOCK_METHOD1(AddTraitDefsChangedCallback,
+ void(const base::Closure& callback));
MOCK_METHOD3(AddComponent, bool(const std::string& name,
const std::vector<std::string>& traits,
ErrorPtr* error));
diff --git a/libweave.gypi b/libweave.gypi
index b529add..6f64c89 100644
--- a/libweave.gypi
+++ b/libweave.gypi
@@ -115,6 +115,7 @@
'third_party/chromium/base/third_party/dmg_fp/dtoa.cc',
'third_party/chromium/base/third_party/icu/icu_utf.cc',
'third_party/chromium/base/time/clock.cc',
+ 'third_party/chromium/base/time/default_clock.cc',
'third_party/chromium/base/time/time.cc',
'third_party/chromium/base/time/time_posix.cc',
'third_party/chromium/base/values.cc',
diff --git a/src/base_api_handler_unittest.cc b/src/base_api_handler_unittest.cc
index 23ef95e..14421b0 100644
--- a/src/base_api_handler_unittest.cc
+++ b/src/base_api_handler_unittest.cc
@@ -5,6 +5,7 @@
#include "src/base_api_handler.h"
#include <base/strings/string_number_conversions.h>
+#include <base/time/default_clock.h>
#include <base/values.h>
#include <gtest/gtest.h>
#include <weave/provider/test/mock_config_store.h>
@@ -53,11 +54,10 @@
.WillRepeatedly(Invoke(&component_manager_,
&ComponentManager::AddCommandHandler));
- std::unique_ptr<Config> config{new Config{&config_store_}};
- config->Load();
- dev_reg_.reset(new DeviceRegistrationInfo(&component_manager_,
- std::move(config), nullptr,
- &http_client_, nullptr));
+ config_.Load();
+ dev_reg_.reset(new DeviceRegistrationInfo(&config_, &component_manager_,
+ nullptr, &http_client_, nullptr,
+ nullptr));
EXPECT_CALL(device_, GetSettings())
.WillRepeatedly(ReturnRef(dev_reg_->GetSettings()));
@@ -91,6 +91,7 @@
}
provider::test::MockConfigStore config_store_;
+ Config config_{&config_store_};
StrictMock<provider::test::MockHttpClient> http_client_;
std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
ComponentManagerImpl component_manager_;
diff --git a/src/component_manager_impl.cc b/src/component_manager_impl.cc
index a23f34d..89ca0cd 100644
--- a/src/component_manager_impl.cc
+++ b/src/component_manager_impl.cc
@@ -31,10 +31,8 @@
LIBWEAVE_EXPORT EnumToStringMap<UserRole>::EnumToStringMap()
: EnumToStringMap(kMap) {}
-ComponentManagerImpl::ComponentManagerImpl() {}
-
-ComponentManagerImpl::ComponentManagerImpl(base::Clock* clock) : clock_{clock} {
-}
+ComponentManagerImpl::ComponentManagerImpl(base::Clock* clock)
+ : clock_{clock ? clock : &default_clock_} {}
ComponentManagerImpl::~ComponentManagerImpl() {}
@@ -343,7 +341,7 @@
auto& queue = state_change_queues_[component_path];
if (!queue)
queue.reset(new StateChangeQueue{kMaxStateChangeQueueSize});
- base::Time timestamp = clock_ ? clock_->Now() : base::Time::Now();
+ base::Time timestamp = clock_->Now();
queue->NotifyPropertiesUpdated(timestamp, dict);
for (const auto& cb : on_state_changed_)
cb.Run();
diff --git a/src/component_manager_impl.h b/src/component_manager_impl.h
index c59c6d9..6b8ff13 100644
--- a/src/component_manager_impl.h
+++ b/src/component_manager_impl.h
@@ -5,6 +5,8 @@
#ifndef LIBWEAVE_SRC_COMPONENT_MANAGER_IMPL_H_
#define LIBWEAVE_SRC_COMPONENT_MANAGER_IMPL_H_
+#include <base/time/default_clock.h>
+
#include "src/commands/command_queue.h"
#include "src/component_manager.h"
#include "src/states/state_change_queue.h"
@@ -13,8 +15,7 @@
class ComponentManagerImpl final : public ComponentManager {
public:
- ComponentManagerImpl();
- explicit ComponentManagerImpl(base::Clock* clock);
+ explicit ComponentManagerImpl(base::Clock* clock = nullptr);
~ComponentManagerImpl() override;
// Loads trait definition schema.
@@ -188,7 +189,9 @@
const std::string& path,
ErrorPtr* error);
+ base::DefaultClock default_clock_;
base::Clock* clock_{nullptr};
+
// An ID of last state change update. Each NotifyPropertiesUpdated()
// invocation increments this value by 1.
UpdateID last_state_change_id_{0};
diff --git a/src/component_manager_unittest.cc b/src/component_manager_unittest.cc
index 902ee15..c63d2dd 100644
--- a/src/component_manager_unittest.cc
+++ b/src/component_manager_unittest.cc
@@ -12,10 +12,12 @@
#include "src/bind_lambda.h"
#include "src/commands/schema_constants.h"
#include "src/mock_component_manager.h"
+#include "src/test/mock_clock.h"
namespace weave {
using test::CreateDictionaryValue;
+using testing::Return;
namespace {
@@ -65,47 +67,36 @@
// }
// }
// }
-void CreateTestComponentTree(ComponentManager* manager) {
- const char kTraits[] = R"({"t1":{},"t2":{},"t3":{},"t4":{},"t5":{},"t6":{}})";
- auto json = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager->LoadTraits(*json, nullptr));
- EXPECT_TRUE(manager->AddComponent("", "comp1", {"t1"}, nullptr));
- EXPECT_TRUE(manager->AddComponentArrayItem("comp1", "comp2", {"t2"},
- nullptr));
- EXPECT_TRUE(manager->AddComponentArrayItem("comp1", "comp2", {"t3"},
- nullptr));
- EXPECT_TRUE(manager->AddComponent("comp1.comp2[1]", "comp3", {"t4"},
- nullptr));
- EXPECT_TRUE(manager->AddComponent("comp1.comp2[1].comp3", "comp4",
- {"t5", "t6"}, nullptr));
-}
+class ComponentManagerTest : public ::testing::Test {
+ protected:
+ void CreateTestComponentTree(ComponentManager* manager) {
+ const char kTraits[] =
+ R"({"t1":{},"t2":{},"t3":{},"t4":{},"t5":{},"t6":{}})";
+ auto json = CreateDictionaryValue(kTraits);
+ ASSERT_TRUE(manager->LoadTraits(*json, nullptr));
+ EXPECT_TRUE(manager->AddComponent("", "comp1", {"t1"}, nullptr));
+ EXPECT_TRUE(
+ manager->AddComponentArrayItem("comp1", "comp2", {"t2"}, nullptr));
+ EXPECT_TRUE(
+ manager->AddComponentArrayItem("comp1", "comp2", {"t3"}, nullptr));
+ EXPECT_TRUE(
+ manager->AddComponent("comp1.comp2[1]", "comp3", {"t4"}, nullptr));
+ EXPECT_TRUE(manager->AddComponent("comp1.comp2[1].comp3", "comp4",
+ {"t5", "t6"}, nullptr));
+ }
-// Test clock class to record predefined time intervals.
-// Implementation from base/test/simple_test_clock.{h|cc}
-class SimpleTestClock : public base::Clock {
- public:
- base::Time Now() override { return now_; }
-
- // Advances the clock by |delta|.
- void Advance(base::TimeDelta delta) { now_ += delta; }
-
- // Sets the clock to the given time.
- void SetNow(base::Time now) { now_ = now; }
-
- private:
- base::Time now_;
+ test::MockClock clock_;
+ ComponentManagerImpl manager_{&clock_};
};
} // anonymous namespace
-TEST(ComponentManager, Empty) {
- ComponentManagerImpl manager;
- EXPECT_TRUE(manager.GetTraits().empty());
- EXPECT_TRUE(manager.GetComponents().empty());
+TEST_F(ComponentManagerTest, Empty) {
+ EXPECT_TRUE(manager_.GetTraits().empty());
+ EXPECT_TRUE(manager_.GetComponents().empty());
}
-TEST(ComponentManager, LoadTraits) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, LoadTraits) {
const char kTraits[] = R"({
"trait1": {
"commands": {
@@ -125,13 +116,12 @@
}
})";
auto json = CreateDictionaryValue(kTraits);
- EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
- EXPECT_JSON_EQ(kTraits, manager.GetTraits());
- EXPECT_TRUE(manager.GetComponents().empty());
+ EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
+ EXPECT_JSON_EQ(kTraits, manager_.GetTraits());
+ EXPECT_TRUE(manager_.GetComponents().empty());
}
-TEST(ComponentManager, LoadTraitsDuplicateIdentical) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, LoadTraitsDuplicateIdentical) {
const char kTraits1[] = R"({
"trait1": {
"commands": {
@@ -151,7 +141,7 @@
}
})";
auto json = CreateDictionaryValue(kTraits1);
- EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
+ EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
const char kTraits2[] = R"({
"trait1": {
"commands": {
@@ -171,7 +161,7 @@
}
})";
json = CreateDictionaryValue(kTraits2);
- EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
+ EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
const char kExpected[] = R"({
"trait1": {
"commands": {
@@ -195,11 +185,10 @@
}
}
})";
- EXPECT_JSON_EQ(kExpected, manager.GetTraits());
+ EXPECT_JSON_EQ(kExpected, manager_.GetTraits());
}
-TEST(ComponentManager, LoadTraitsDuplicateOverride) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, LoadTraitsDuplicateOverride) {
const char kTraits1[] = R"({
"trait1": {
"commands": {
@@ -219,7 +208,7 @@
}
})";
auto json = CreateDictionaryValue(kTraits1);
- EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
+ EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
const char kTraits2[] = R"({
"trait1": {
"commands": {
@@ -239,15 +228,14 @@
}
})";
json = CreateDictionaryValue(kTraits2);
- EXPECT_FALSE(manager.LoadTraits(*json, nullptr));
+ EXPECT_FALSE(manager_.LoadTraits(*json, nullptr));
}
-TEST(ComponentManager, AddTraitDefChangedCallback) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, AddTraitDefChangedCallback) {
int count = 0;
int count2 = 0;
- manager.AddTraitDefChangedCallback(base::Bind([&count]() { count++; }));
- manager.AddTraitDefChangedCallback(base::Bind([&count2]() { count2++; }));
+ manager_.AddTraitDefChangedCallback(base::Bind([&count]() { count++; }));
+ manager_.AddTraitDefChangedCallback(base::Bind([&count2]() { count2++; }));
EXPECT_EQ(1, count);
EXPECT_EQ(1, count2);
// New definitions.
@@ -264,7 +252,7 @@
}
})";
auto json = CreateDictionaryValue(kTraits1);
- EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
+ EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
EXPECT_EQ(2, count);
// Duplicate definition, shouldn't call the callback.
const char kTraits2[] = R"({
@@ -275,7 +263,7 @@
}
})";
json = CreateDictionaryValue(kTraits2);
- EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
+ EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
EXPECT_EQ(2, count);
// New definition, should call the callback now.
const char kTraits3[] = R"({
@@ -286,30 +274,28 @@
}
})";
json = CreateDictionaryValue(kTraits3);
- EXPECT_TRUE(manager.LoadTraits(*json, nullptr));
+ EXPECT_TRUE(manager_.LoadTraits(*json, nullptr));
EXPECT_EQ(3, count);
// Wrong definition, shouldn't call the callback.
const char kTraits4[] = R"({
"trait4": "foo"
})";
json = CreateDictionaryValue(kTraits4);
- EXPECT_FALSE(manager.LoadTraits(*json, nullptr));
+ EXPECT_FALSE(manager_.LoadTraits(*json, nullptr));
EXPECT_EQ(3, count);
// Make sure both callbacks were called the same number of times.
EXPECT_EQ(count2, count);
}
-TEST(ComponentManager, LoadTraitsNotAnObject) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, LoadTraitsNotAnObject) {
const char kTraits1[] = R"({"trait1": 0})";
auto json = CreateDictionaryValue(kTraits1);
ErrorPtr error;
- EXPECT_FALSE(manager.LoadTraits(*json, &error));
+ EXPECT_FALSE(manager_.LoadTraits(*json, &error));
EXPECT_EQ(errors::commands::kTypeMismatch, error->GetCode());
}
-TEST(ComponentManager, FindTraitDefinition) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, FindTraitDefinition) {
const char kTraits[] = R"({
"trait1": {
"commands": {
@@ -329,9 +315,9 @@
}
})";
auto json = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*json, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
- const base::DictionaryValue* trait = manager.FindTraitDefinition("trait1");
+ const base::DictionaryValue* trait = manager_.FindTraitDefinition("trait1");
ASSERT_NE(nullptr, trait);
const char kExpected1[] = R"({
"commands": {
@@ -346,7 +332,7 @@
})";
EXPECT_JSON_EQ(kExpected1, *trait);
- trait = manager.FindTraitDefinition("trait2");
+ trait = manager_.FindTraitDefinition("trait2");
ASSERT_NE(nullptr, trait);
const char kExpected2[] = R"({
"state": {
@@ -355,11 +341,10 @@
})";
EXPECT_JSON_EQ(kExpected2, *trait);
- EXPECT_EQ(nullptr, manager.FindTraitDefinition("trait3"));
+ EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait3"));
}
-TEST(ComponentManager, FindCommandDefinition) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, FindCommandDefinition) {
const char kTraits[] = R"({
"trait1": {
"commands": {
@@ -381,9 +366,9 @@
}
})";
auto json = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*json, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
- const auto* cmd_def = manager.FindCommandDefinition("trait1.command1");
+ const auto* cmd_def = manager_.FindCommandDefinition("trait1.command1");
ASSERT_NE(nullptr, cmd_def);
const char kExpected1[] = R"({
"minimalRole": "user",
@@ -391,28 +376,28 @@
})";
EXPECT_JSON_EQ(kExpected1, *cmd_def);
- cmd_def = manager.FindCommandDefinition("trait2.command1");
+ cmd_def = manager_.FindCommandDefinition("trait2.command1");
ASSERT_NE(nullptr, cmd_def);
const char kExpected2[] = R"({
"minimalRole": "manager"
})";
EXPECT_JSON_EQ(kExpected2, *cmd_def);
- cmd_def = manager.FindCommandDefinition("trait2.command2");
+ cmd_def = manager_.FindCommandDefinition("trait2.command2");
ASSERT_NE(nullptr, cmd_def);
const char kExpected3[] = R"({
"minimalRole": "owner"
})";
EXPECT_JSON_EQ(kExpected3, *cmd_def);
- EXPECT_EQ(nullptr, manager.FindTraitDefinition("trait1.command2"));
- EXPECT_EQ(nullptr, manager.FindTraitDefinition("trait3.command1"));
- EXPECT_EQ(nullptr, manager.FindTraitDefinition("trait"));
- EXPECT_EQ(nullptr, manager.FindTraitDefinition("trait1.command1.parameters"));
+ EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait1.command2"));
+ EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait3.command1"));
+ EXPECT_EQ(nullptr, manager_.FindTraitDefinition("trait"));
+ EXPECT_EQ(nullptr,
+ manager_.FindTraitDefinition("trait1.command1.parameters"));
}
-TEST(ComponentManager, GetMinimalRole) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, GetMinimalRole) {
const char kTraits[] = R"({
"trait1": {
"commands": {
@@ -428,31 +413,31 @@
}
})";
auto json = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*json, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
UserRole role;
- ASSERT_TRUE(manager.GetMinimalRole("trait1.command1", &role, nullptr));
+ ASSERT_TRUE(manager_.GetMinimalRole("trait1.command1", &role, nullptr));
EXPECT_EQ(UserRole::kUser, role);
- ASSERT_TRUE(manager.GetMinimalRole("trait1.command2", &role, nullptr));
+ ASSERT_TRUE(manager_.GetMinimalRole("trait1.command2", &role, nullptr));
EXPECT_EQ(UserRole::kViewer, role);
- ASSERT_TRUE(manager.GetMinimalRole("trait2.command1", &role, nullptr));
+ ASSERT_TRUE(manager_.GetMinimalRole("trait2.command1", &role, nullptr));
EXPECT_EQ(UserRole::kManager, role);
- ASSERT_TRUE(manager.GetMinimalRole("trait2.command2", &role, nullptr));
+ ASSERT_TRUE(manager_.GetMinimalRole("trait2.command2", &role, nullptr));
EXPECT_EQ(UserRole::kOwner, role);
- EXPECT_FALSE(manager.GetMinimalRole("trait1.command3", &role, nullptr));
+ EXPECT_FALSE(manager_.GetMinimalRole("trait1.command3", &role, nullptr));
}
-TEST(ComponentManager, AddComponent) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, AddComponent) {
const char kTraits[] = R"({"trait1": {}, "trait2": {}, "trait3": {}})";
auto json = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*json, nullptr));
- EXPECT_TRUE(manager.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
- EXPECT_TRUE(manager.AddComponent("", "comp2", {"trait3"}, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
+ EXPECT_TRUE(
+ manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
+ EXPECT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
const char kExpected[] = R"({
"comp1": {
"traits": ["trait1", "trait2"]
@@ -461,18 +446,17 @@
"traits": ["trait3"]
}
})";
- EXPECT_JSON_EQ(kExpected, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
// 'trait4' is undefined, so can't add a component referring to it.
- EXPECT_FALSE(manager.AddComponent("", "comp3", {"trait4"}, nullptr));
+ EXPECT_FALSE(manager_.AddComponent("", "comp3", {"trait4"}, nullptr));
}
-TEST(ComponentManager, AddSubComponent) {
- ComponentManagerImpl manager;
- EXPECT_TRUE(manager.AddComponent("", "comp1", {}, nullptr));
- EXPECT_TRUE(manager.AddComponent("comp1", "comp2", {}, nullptr));
- EXPECT_TRUE(manager.AddComponent("comp1", "comp3", {}, nullptr));
- EXPECT_TRUE(manager.AddComponent("comp1.comp2", "comp4", {}, nullptr));
+TEST_F(ComponentManagerTest, AddSubComponent) {
+ EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
+ EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
+ EXPECT_TRUE(manager_.AddComponent("comp1", "comp3", {}, nullptr));
+ EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
const char kExpected[] = R"({
"comp1": {
"traits": [],
@@ -491,23 +475,22 @@
}
}
})";
- EXPECT_JSON_EQ(kExpected, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
}
-TEST(ComponentManager, AddComponentArrayItem) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, AddComponentArrayItem) {
const char kTraits[] = R"({"foo": {}, "bar": {}})";
auto json = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*json, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*json, nullptr));
- EXPECT_TRUE(manager.AddComponent("", "comp1", {}, nullptr));
- EXPECT_TRUE(manager.AddComponentArrayItem("comp1", "comp2", {"foo"},
- nullptr));
- EXPECT_TRUE(manager.AddComponentArrayItem("comp1", "comp2", {"bar"},
- nullptr));
- EXPECT_TRUE(manager.AddComponent("comp1.comp2[1]", "comp3", {}, nullptr));
- EXPECT_TRUE(manager.AddComponent("comp1.comp2[1].comp3", "comp4", {},
- nullptr));
+ EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
+ EXPECT_TRUE(
+ manager_.AddComponentArrayItem("comp1", "comp2", {"foo"}, nullptr));
+ EXPECT_TRUE(
+ manager_.AddComponentArrayItem("comp1", "comp2", {"bar"}, nullptr));
+ EXPECT_TRUE(manager_.AddComponent("comp1.comp2[1]", "comp3", {}, nullptr));
+ EXPECT_TRUE(
+ manager_.AddComponent("comp1.comp2[1].comp3", "comp4", {}, nullptr));
const char kExpected[] = R"({
"comp1": {
"traits": [],
@@ -533,96 +516,91 @@
}
}
})";
- EXPECT_JSON_EQ(kExpected, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
}
-TEST(ComponentManager, AddComponentExist) {
- ComponentManagerImpl manager;
- EXPECT_TRUE(manager.AddComponent("", "comp1", {}, nullptr));
- EXPECT_FALSE(manager.AddComponent("", "comp1", {}, nullptr));
- EXPECT_TRUE(manager.AddComponent("comp1", "comp2", {}, nullptr));
- EXPECT_FALSE(manager.AddComponent("comp1", "comp2", {}, nullptr));
+TEST_F(ComponentManagerTest, AddComponentExist) {
+ EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
+ EXPECT_FALSE(manager_.AddComponent("", "comp1", {}, nullptr));
+ EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
+ EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
}
-TEST(ComponentManager, AddComponentDoesNotExist) {
- ComponentManagerImpl manager;
- EXPECT_FALSE(manager.AddComponent("comp1", "comp2", {}, nullptr));
+TEST_F(ComponentManagerTest, AddComponentDoesNotExist) {
+ EXPECT_FALSE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
}
-TEST(ComponentManager, AddComponentTreeChangedCallback) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, AddComponentTreeChangedCallback) {
int count = 0;
int count2 = 0;
- manager.AddComponentTreeChangedCallback(base::Bind([&count]() { count++; }));
- manager.AddComponentTreeChangedCallback(
+ manager_.AddComponentTreeChangedCallback(base::Bind([&count]() { count++; }));
+ manager_.AddComponentTreeChangedCallback(
base::Bind([&count2]() { count2++; }));
EXPECT_EQ(1, count);
EXPECT_EQ(1, count2);
- EXPECT_TRUE(manager.AddComponent("", "comp1", {}, nullptr));
+ EXPECT_TRUE(manager_.AddComponent("", "comp1", {}, nullptr));
EXPECT_EQ(2, count);
- EXPECT_TRUE(manager.AddComponent("comp1", "comp2", {}, nullptr));
+ EXPECT_TRUE(manager_.AddComponent("comp1", "comp2", {}, nullptr));
EXPECT_EQ(3, count);
- EXPECT_TRUE(manager.AddComponent("comp1.comp2", "comp4", {}, nullptr));
+ EXPECT_TRUE(manager_.AddComponent("comp1.comp2", "comp4", {}, nullptr));
EXPECT_EQ(4, count);
- EXPECT_TRUE(manager.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
+ EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
EXPECT_EQ(5, count);
- EXPECT_TRUE(manager.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
+ EXPECT_TRUE(manager_.AddComponentArrayItem("comp1", "comp3", {}, nullptr));
EXPECT_EQ(6, count);
// Make sure both callbacks were called the same number of times.
EXPECT_EQ(count2, count);
}
-TEST(ComponentManager, FindComponent) {
- ComponentManagerImpl manager;
- CreateTestComponentTree(&manager);
+TEST_F(ComponentManagerTest, FindComponent) {
+ CreateTestComponentTree(&manager_);
- const base::DictionaryValue* comp = manager.FindComponent("comp1", nullptr);
+ const base::DictionaryValue* comp = manager_.FindComponent("comp1", nullptr);
ASSERT_NE(nullptr, comp);
EXPECT_TRUE(HasTrait(*comp, "t1"));
- comp = manager.FindComponent("comp1.comp2[0]", nullptr);
+ comp = manager_.FindComponent("comp1.comp2[0]", nullptr);
ASSERT_NE(nullptr, comp);
EXPECT_TRUE(HasTrait(*comp, "t2"));
- comp = manager.FindComponent("comp1.comp2[1]", nullptr);
+ comp = manager_.FindComponent("comp1.comp2[1]", nullptr);
ASSERT_NE(nullptr, comp);
EXPECT_TRUE(HasTrait(*comp, "t3"));
- comp = manager.FindComponent("comp1.comp2[1].comp3", nullptr);
+ comp = manager_.FindComponent("comp1.comp2[1].comp3", nullptr);
ASSERT_NE(nullptr, comp);
EXPECT_TRUE(HasTrait(*comp, "t4"));
- comp = manager.FindComponent("comp1.comp2[1].comp3.comp4", nullptr);
+ comp = manager_.FindComponent("comp1.comp2[1].comp3.comp4", nullptr);
ASSERT_NE(nullptr, comp);
EXPECT_TRUE(HasTrait(*comp, "t5"));
// Some whitespaces don't hurt.
- comp = manager.FindComponent(" comp1 . comp2 [ \t 1 ] . comp3.comp4 ",
- nullptr);
+ comp = manager_.FindComponent(" comp1 . comp2 [ \t 1 ] . comp3.comp4 ",
+ nullptr);
EXPECT_NE(nullptr, comp);
// Now check some failure cases.
ErrorPtr error;
- EXPECT_EQ(nullptr, manager.FindComponent("", &error));
+ EXPECT_EQ(nullptr, manager_.FindComponent("", &error));
EXPECT_NE(nullptr, error.get());
// 'comp2' doesn't exist:
- EXPECT_EQ(nullptr, manager.FindComponent("comp2", nullptr));
+ EXPECT_EQ(nullptr, manager_.FindComponent("comp2", nullptr));
// 'comp1.comp2' is an array, not a component:
- EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2", nullptr));
+ EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2", nullptr));
// 'comp1.comp2[3]' doesn't exist:
- EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2[3]", nullptr));
+ EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[3]", nullptr));
// Empty component names:
- EXPECT_EQ(nullptr, manager.FindComponent(".comp2[1]", nullptr));
- EXPECT_EQ(nullptr, manager.FindComponent("comp1.[1]", nullptr));
+ EXPECT_EQ(nullptr, manager_.FindComponent(".comp2[1]", nullptr));
+ EXPECT_EQ(nullptr, manager_.FindComponent("comp1.[1]", nullptr));
// Invalid array indices:
- EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2[s]", nullptr));
- EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2[-2]", nullptr));
- EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2[1e1]", nullptr));
- EXPECT_EQ(nullptr, manager.FindComponent("comp1.comp2[1", nullptr));
+ EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[s]", nullptr));
+ EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[-2]", nullptr));
+ EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1e1]", nullptr));
+ EXPECT_EQ(nullptr, manager_.FindComponent("comp1.comp2[1", nullptr));
}
-TEST(ComponentManager, ParseCommandInstance) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, ParseCommandInstance) {
const char kTraits[] = R"({
"trait1": {
"commands": {
@@ -644,9 +622,9 @@
}
})";
auto traits = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1"}, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp2", {"trait2"}, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
+ ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
+ ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
std::string id;
const char kCommand1[] = R"({
@@ -657,13 +635,15 @@
})";
auto command1 = CreateDictionaryValue(kCommand1);
EXPECT_NE(nullptr,
- manager.ParseCommandInstance(*command1, Command::Origin::kLocal,
- UserRole::kUser, &id, nullptr).get());
+ manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
+ UserRole::kUser, &id, nullptr)
+ .get());
EXPECT_EQ("1234-12345", id);
// Not enough access rights
EXPECT_EQ(nullptr,
- manager.ParseCommandInstance(*command1, Command::Origin::kLocal,
- UserRole::kViewer, &id, nullptr).get());
+ manager_.ParseCommandInstance(*command1, Command::Origin::kLocal,
+ UserRole::kViewer, &id, nullptr)
+ .get());
const char kCommand2[] = R"({
"name": "trait1.command3",
@@ -673,8 +653,9 @@
auto command2 = CreateDictionaryValue(kCommand2);
// trait1.command3 doesn't exist
EXPECT_EQ(nullptr,
- manager.ParseCommandInstance(*command2, Command::Origin::kLocal,
- UserRole::kOwner, &id, nullptr).get());
+ manager_.ParseCommandInstance(*command2, Command::Origin::kLocal,
+ UserRole::kOwner, &id, nullptr)
+ .get());
EXPECT_TRUE(id.empty());
const char kCommand3[] = R"({
@@ -685,8 +666,9 @@
auto command3 = CreateDictionaryValue(kCommand3);
// Component comp1 doesn't have trait2.
EXPECT_EQ(nullptr,
- manager.ParseCommandInstance(*command3, Command::Origin::kLocal,
- UserRole::kOwner, &id, nullptr).get());
+ manager_.ParseCommandInstance(*command3, Command::Origin::kLocal,
+ UserRole::kOwner, &id, nullptr)
+ .get());
// No component specified, find the suitable component
const char kCommand4[] = R"({
@@ -694,7 +676,7 @@
"parameters": {}
})";
auto command4 = CreateDictionaryValue(kCommand4);
- auto command_instance = manager.ParseCommandInstance(
+ auto command_instance = manager_.ParseCommandInstance(
*command4, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
EXPECT_NE(nullptr, command_instance.get());
EXPECT_EQ("comp1", command_instance->GetComponent());
@@ -704,7 +686,7 @@
"parameters": {}
})";
auto command5 = CreateDictionaryValue(kCommand5);
- command_instance = manager.ParseCommandInstance(
+ command_instance = manager_.ParseCommandInstance(
*command5, Command::Origin::kLocal, UserRole::kOwner, &id, nullptr);
EXPECT_NE(nullptr, command_instance.get());
EXPECT_EQ("comp2", command_instance->GetComponent());
@@ -716,12 +698,12 @@
})";
auto command6 = CreateDictionaryValue(kCommand6);
EXPECT_EQ(nullptr,
- manager.ParseCommandInstance(*command6, Command::Origin::kLocal,
- UserRole::kOwner, &id, nullptr).get());
+ manager_.ParseCommandInstance(*command6, Command::Origin::kLocal,
+ UserRole::kOwner, &id, nullptr)
+ .get());
}
-TEST(ComponentManager, AddCommand) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, AddCommand) {
const char kTraits[] = R"({
"trait1": {
"commands": {
@@ -730,8 +712,8 @@
}
})";
auto traits = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1"}, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
+ ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
std::string id;
const char kCommand[] = R"({
@@ -741,17 +723,16 @@
"parameters": {}
})";
auto command = CreateDictionaryValue(kCommand);
- auto command_instance = manager.ParseCommandInstance(
+ auto command_instance = manager_.ParseCommandInstance(
*command, Command::Origin::kLocal, UserRole::kUser, &id, nullptr);
ASSERT_NE(nullptr, command_instance.get());
- manager.AddCommand(std::move(command_instance));
- const auto* queued_command = manager.FindCommand(id);
+ manager_.AddCommand(std::move(command_instance));
+ const auto* queued_command = manager_.FindCommand(id);
ASSERT_NE(nullptr, queued_command);
EXPECT_EQ("trait1.command1", queued_command->GetName());
}
-TEST(ComponentManager, AddCommandHandler) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, AddCommandHandler) {
const char kTraits[] = R"({
"trait1": {
"commands": {
@@ -765,9 +746,10 @@
}
})";
auto traits = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1"}, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
+ ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
+ ASSERT_TRUE(
+ manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
std::string last_tags;
auto handler = [&last_tags](int tag, const std::weak_ptr<Command>& command) {
@@ -776,9 +758,12 @@
last_tags += std::to_string(tag);
};
- manager.AddCommandHandler("comp1", "trait1.command1", base::Bind(handler, 1));
- manager.AddCommandHandler("comp2", "trait1.command1", base::Bind(handler, 2));
- manager.AddCommandHandler("comp2", "trait2.command2", base::Bind(handler, 3));
+ manager_.AddCommandHandler("comp1", "trait1.command1",
+ base::Bind(handler, 1));
+ manager_.AddCommandHandler("comp2", "trait1.command1",
+ base::Bind(handler, 2));
+ manager_.AddCommandHandler("comp2", "trait2.command2",
+ base::Bind(handler, 3));
EXPECT_TRUE(last_tags.empty());
const char kCommand1[] = R"({
@@ -786,10 +771,10 @@
"component": "comp1"
})";
auto command1 = CreateDictionaryValue(kCommand1);
- auto command_instance = manager.ParseCommandInstance(
+ auto command_instance = manager_.ParseCommandInstance(
*command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
ASSERT_NE(nullptr, command_instance.get());
- manager.AddCommand(std::move(command_instance));
+ manager_.AddCommand(std::move(command_instance));
EXPECT_EQ("1", last_tags);
last_tags.clear();
@@ -798,10 +783,10 @@
"component": "comp2"
})";
auto command2 = CreateDictionaryValue(kCommand2);
- command_instance = manager.ParseCommandInstance(
+ command_instance = manager_.ParseCommandInstance(
*command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
ASSERT_NE(nullptr, command_instance.get());
- manager.AddCommand(std::move(command_instance));
+ manager_.AddCommand(std::move(command_instance));
EXPECT_EQ("2", last_tags);
last_tags.clear();
@@ -811,16 +796,15 @@
"parameters": {}
})";
auto command3 = CreateDictionaryValue(kCommand3);
- command_instance = manager.ParseCommandInstance(
+ command_instance = manager_.ParseCommandInstance(
*command3, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
ASSERT_NE(nullptr, command_instance.get());
- manager.AddCommand(std::move(command_instance));
+ manager_.AddCommand(std::move(command_instance));
EXPECT_EQ("3", last_tags);
last_tags.clear();
}
-TEST(ComponentManager, AddDefaultCommandHandler) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, AddDefaultCommandHandler) {
const char kTraits[] = R"({
"trait1": {
"commands": {
@@ -834,15 +818,15 @@
}
})";
auto traits = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp", {"trait1", "trait2"}, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
+ ASSERT_TRUE(manager_.AddComponent("", "comp", {"trait1", "trait2"}, nullptr));
int count = 0;
auto handler = [&count](int tag, const std::weak_ptr<Command>& command) {
count++;
};
- manager.AddCommandHandler("", "", base::Bind(handler, 1));
+ manager_.AddCommandHandler("", "", base::Bind(handler, 1));
EXPECT_EQ(0, count);
const char kCommand1[] = R"({
@@ -850,10 +834,10 @@
"component": "comp"
})";
auto command1 = CreateDictionaryValue(kCommand1);
- auto command_instance = manager.ParseCommandInstance(
+ auto command_instance = manager_.ParseCommandInstance(
*command1, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
ASSERT_NE(nullptr, command_instance.get());
- manager.AddCommand(std::move(command_instance));
+ manager_.AddCommand(std::move(command_instance));
EXPECT_EQ(1, count);
const char kCommand2[] = R"({
@@ -861,20 +845,19 @@
"component": "comp"
})";
auto command2 = CreateDictionaryValue(kCommand2);
- command_instance = manager.ParseCommandInstance(
+ command_instance = manager_.ParseCommandInstance(
*command2, Command::Origin::kCloud, UserRole::kUser, nullptr, nullptr);
ASSERT_NE(nullptr, command_instance.get());
- manager.AddCommand(std::move(command_instance));
+ manager_.AddCommand(std::move(command_instance));
EXPECT_EQ(2, count);
}
-TEST(ComponentManager, SetStateProperties) {
- ComponentManagerImpl manager;
- CreateTestComponentTree(&manager);
+TEST_F(ComponentManagerTest, SetStateProperties) {
+ CreateTestComponentTree(&manager_);
const char kState1[] = R"({"t1": {"p1": 0, "p2": "foo"}})";
auto state1 = CreateDictionaryValue(kState1);
- ASSERT_TRUE(manager.SetStateProperties("comp1", *state1, nullptr));
+ ASSERT_TRUE(manager_.SetStateProperties("comp1", *state1, nullptr));
const char kExpected1[] = R"({
"comp1": {
"traits": [ "t1" ],
@@ -901,11 +884,11 @@
}
}
})";
- EXPECT_JSON_EQ(kExpected1, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
const char kState2[] = R"({"t1": {"p1": {"bar": "baz"}}})";
auto state2 = CreateDictionaryValue(kState2);
- ASSERT_TRUE(manager.SetStateProperties("comp1", *state2, nullptr));
+ ASSERT_TRUE(manager_.SetStateProperties("comp1", *state2, nullptr));
const char kExpected2[] = R"({
"comp1": {
@@ -933,12 +916,12 @@
}
}
})";
- EXPECT_JSON_EQ(kExpected2, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
const char kState3[] = R"({"t5": {"p1": 1}})";
auto state3 = CreateDictionaryValue(kState3);
- ASSERT_TRUE(manager.SetStateProperties("comp1.comp2[1].comp3.comp4", *state3,
- nullptr));
+ ASSERT_TRUE(manager_.SetStateProperties("comp1.comp2[1].comp3.comp4", *state3,
+ nullptr));
const char kExpected3[] = R"({
"comp1": {
@@ -967,14 +950,13 @@
}
}
})";
- EXPECT_JSON_EQ(kExpected3, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpected3, manager_.GetComponents());
}
-TEST(ComponentManager, SetStatePropertiesFromJson) {
- ComponentManagerImpl manager;
- CreateTestComponentTree(&manager);
+TEST_F(ComponentManagerTest, SetStatePropertiesFromJson) {
+ CreateTestComponentTree(&manager_);
- ASSERT_TRUE(manager.SetStatePropertiesFromJson(
+ ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
"comp1.comp2[1].comp3.comp4", R"({"t5": {"p1": 3}, "t6": {"p2": 5}})",
nullptr));
@@ -1007,11 +989,10 @@
}
}
})";
- EXPECT_JSON_EQ(kExpected, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpected, manager_.GetComponents());
}
-TEST(ComponentManager, SetGetStateProperty) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, SetGetStateProperty) {
const char kTraits[] = R"({
"trait1": {
"state": {
@@ -1027,11 +1008,12 @@
}
})";
auto traits = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
+ ASSERT_TRUE(
+ manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
base::StringValue p1("foo");
- ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
+ ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
const char kExpected1[] = R"({
"comp1": {
@@ -1041,10 +1023,10 @@
}
}
})";
- EXPECT_JSON_EQ(kExpected1, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpected1, manager_.GetComponents());
base::FundamentalValue p2(2);
- ASSERT_TRUE(manager.SetStateProperty("comp1", "trait2.prop3", p2, nullptr));
+ ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait2.prop3", p2, nullptr));
const char kExpected2[] = R"({
"comp1": {
@@ -1055,29 +1037,27 @@
}
}
})";
- EXPECT_JSON_EQ(kExpected2, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpected2, manager_.GetComponents());
// Just the package name without property:
- EXPECT_FALSE(manager.SetStateProperty("comp1", "trait2", p2, nullptr));
+ EXPECT_FALSE(manager_.SetStateProperty("comp1", "trait2", p2, nullptr));
- const base::Value* value = manager.GetStateProperty("comp1", "trait1.prop1",
- nullptr);
+ const base::Value* value =
+ manager_.GetStateProperty("comp1", "trait1.prop1", nullptr);
ASSERT_NE(nullptr, value);
EXPECT_TRUE(p1.Equals(value));
- value = manager.GetStateProperty("comp1", "trait2.prop3", nullptr);
+ value = manager_.GetStateProperty("comp1", "trait2.prop3", nullptr);
ASSERT_NE(nullptr, value);
EXPECT_TRUE(p2.Equals(value));
// Non-existing property:
- EXPECT_EQ(nullptr, manager.GetStateProperty("comp1", "trait2.p", nullptr));
+ EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2.p", nullptr));
// Non-existing component
- EXPECT_EQ(nullptr, manager.GetStateProperty("comp2", "trait.prop", nullptr));
+ EXPECT_EQ(nullptr, manager_.GetStateProperty("comp2", "trait.prop", nullptr));
// Just the package name without property:
- EXPECT_EQ(nullptr, manager.GetStateProperty("comp1", "trait2", nullptr));
+ EXPECT_EQ(nullptr, manager_.GetStateProperty("comp1", "trait2", nullptr));
}
-TEST(ComponentManager, AddStateChangedCallback) {
- SimpleTestClock clock;
- ComponentManagerImpl manager{&clock};
+TEST_F(ComponentManagerTest, AddStateChangedCallback) {
const char kTraits[] = R"({
"trait1": {
"state": {
@@ -1087,38 +1067,36 @@
}
})";
auto traits = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1"}, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
+ ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
int count = 0;
int count2 = 0;
- manager.AddStateChangedCallback(base::Bind([&count]() { count++; }));
- manager.AddStateChangedCallback(base::Bind([&count2]() { count2++; }));
+ manager_.AddStateChangedCallback(base::Bind([&count]() { count++; }));
+ manager_.AddStateChangedCallback(base::Bind([&count2]() { count2++; }));
EXPECT_EQ(1, count);
EXPECT_EQ(1, count2);
- EXPECT_EQ(0, manager.GetLastStateChangeId());
+ EXPECT_EQ(0, manager_.GetLastStateChangeId());
base::StringValue p1("foo");
- ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
+ ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", p1, nullptr));
EXPECT_EQ(2, count);
EXPECT_EQ(2, count2);
- EXPECT_EQ(1, manager.GetLastStateChangeId());
+ EXPECT_EQ(1, manager_.GetLastStateChangeId());
- ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop2", p1, nullptr));
+ ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", p1, nullptr));
EXPECT_EQ(3, count);
EXPECT_EQ(3, count2);
- EXPECT_EQ(2, manager.GetLastStateChangeId());
+ EXPECT_EQ(2, manager_.GetLastStateChangeId());
// Fail - no component.
- ASSERT_FALSE(manager.SetStateProperty("comp2", "trait1.prop2", p1, nullptr));
+ ASSERT_FALSE(manager_.SetStateProperty("comp2", "trait1.prop2", p1, nullptr));
EXPECT_EQ(3, count);
EXPECT_EQ(3, count2);
- EXPECT_EQ(2, manager.GetLastStateChangeId());
+ EXPECT_EQ(2, manager_.GetLastStateChangeId());
}
-TEST(ComponentManager, ComponentStateUpdates) {
- SimpleTestClock clock;
- ComponentManagerImpl manager{&clock};
+TEST_F(ComponentManagerTest, ComponentStateUpdates) {
const char kTraits[] = R"({
"trait1": {
"state": {
@@ -1134,48 +1112,50 @@
}
})";
auto traits = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
+ ASSERT_TRUE(
+ manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
+ ASSERT_TRUE(
+ manager_.AddComponent("", "comp2", {"trait1", "trait2"}, nullptr));
std::vector<ComponentManager::UpdateID> updates1;
auto callback1 = [&updates1](ComponentManager::UpdateID id) {
updates1.push_back(id);
};
// State change queue is empty, callback should be called immediately.
- auto token1 = manager.AddServerStateUpdatedCallback(base::Bind(callback1));
+ auto token1 = manager_.AddServerStateUpdatedCallback(base::Bind(callback1));
ASSERT_EQ(1u, updates1.size());
- EXPECT_EQ(manager.GetLastStateChangeId(), updates1.front());
+ EXPECT_EQ(manager_.GetLastStateChangeId(), updates1.front());
updates1.clear();
base::StringValue foo("foo");
base::Time time1 = base::Time::Now();
- clock.SetNow(time1);
+ EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time1));
// These three updates should be grouped into two separate state change queue
// items, since they all happen at the same time, but for two different
// components.
- ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop1", foo, nullptr));
- ASSERT_TRUE(manager.SetStateProperty("comp2", "trait2.prop3", foo, nullptr));
- ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop2", foo, nullptr));
+ ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", foo, nullptr));
+ ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", foo, nullptr));
+ ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", foo, nullptr));
std::vector<ComponentManager::UpdateID> updates2;
auto callback2 = [&updates2](ComponentManager::UpdateID id) {
updates2.push_back(id);
};
// State change queue is not empty, so callback will be called later.
- auto token2 = manager.AddServerStateUpdatedCallback(base::Bind(callback2));
+ auto token2 = manager_.AddServerStateUpdatedCallback(base::Bind(callback2));
EXPECT_TRUE(updates2.empty());
base::StringValue bar("bar");
base::Time time2 = time1 + base::TimeDelta::FromSeconds(1);
- clock.SetNow(time2);
+ EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(time2));
// Two more update events (as above) but at |time2|.
- ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop1", bar, nullptr));
- ASSERT_TRUE(manager.SetStateProperty("comp2", "trait2.prop3", bar, nullptr));
- ASSERT_TRUE(manager.SetStateProperty("comp1", "trait1.prop2", bar, nullptr));
+ ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop1", bar, nullptr));
+ ASSERT_TRUE(manager_.SetStateProperty("comp2", "trait2.prop3", bar, nullptr));
+ ASSERT_TRUE(manager_.SetStateProperty("comp1", "trait1.prop2", bar, nullptr));
- auto snapshot = manager.GetAndClearRecordedStateChanges();
- EXPECT_EQ(manager.GetLastStateChangeId(), snapshot.update_id);
+ auto snapshot = manager_.GetAndClearRecordedStateChanges();
+ EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot.update_id);
ASSERT_EQ(4u, snapshot.state_changes.size());
EXPECT_EQ("comp1", snapshot.state_changes[0].component);
@@ -1199,38 +1179,37 @@
*snapshot.state_changes[3].changed_properties);
// Make sure previous GetAndClearRecordedStateChanges() clears the queue.
- auto snapshot2 = manager.GetAndClearRecordedStateChanges();
- EXPECT_EQ(manager.GetLastStateChangeId(), snapshot2.update_id);
+ auto snapshot2 = manager_.GetAndClearRecordedStateChanges();
+ EXPECT_EQ(manager_.GetLastStateChangeId(), snapshot2.update_id);
EXPECT_TRUE(snapshot2.state_changes.empty());
// Now indicate that we have update the changes on the server.
- manager.NotifyStateUpdatedOnServer(snapshot.update_id);
+ manager_.NotifyStateUpdatedOnServer(snapshot.update_id);
ASSERT_EQ(1u, updates1.size());
EXPECT_EQ(snapshot.update_id, updates1.front());
ASSERT_EQ(1u, updates2.size());
EXPECT_EQ(snapshot.update_id, updates2.front());
}
-TEST(ComponentManager, FindComponentWithTrait) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, FindComponentWithTrait) {
const char kTraits[] = R"({
"trait1": {},
"trait2": {},
"trait3": {}
})";
auto traits = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp2", {"trait3"}, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
+ ASSERT_TRUE(
+ manager_.AddComponent("", "comp1", {"trait1", "trait2"}, nullptr));
+ ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait3"}, nullptr));
- EXPECT_EQ("comp1", manager.FindComponentWithTrait("trait1"));
- EXPECT_EQ("comp1", manager.FindComponentWithTrait("trait2"));
- EXPECT_EQ("comp2", manager.FindComponentWithTrait("trait3"));
- EXPECT_EQ("", manager.FindComponentWithTrait("trait4"));
+ EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait1"));
+ EXPECT_EQ("comp1", manager_.FindComponentWithTrait("trait2"));
+ EXPECT_EQ("comp2", manager_.FindComponentWithTrait("trait3"));
+ EXPECT_EQ("", manager_.FindComponentWithTrait("trait4"));
}
-TEST(ComponentManager, AddLegacyCommandAndStateDefinitions) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, AddLegacyCommandAndStateDefinitions) {
const char kCommandDefs1[] = R"({
"package1": {
"command1": {
@@ -1248,7 +1227,7 @@
}
})";
auto json = CreateDictionaryValue(kCommandDefs1);
- EXPECT_TRUE(manager.AddLegacyCommandDefinitions(*json, nullptr));
+ EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
const char kExpected1[] = R"({
"package1": {
"commands": {
@@ -1269,11 +1248,11 @@
}
}
})";
- EXPECT_JSON_EQ(kExpected1, manager.GetTraits());
+ EXPECT_JSON_EQ(kExpected1, manager_.GetTraits());
const char kExpectedComponents1[] = R"({
"__weave__": { "traits": ["package1", "package2"] }
})";
- EXPECT_JSON_EQ(kExpectedComponents1, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpectedComponents1, manager_.GetComponents());
const char kCommandDefs2[] = R"({
"package2": {
@@ -1285,7 +1264,7 @@
}
})";
json = CreateDictionaryValue(kCommandDefs2);
- EXPECT_TRUE(manager.AddLegacyCommandDefinitions(*json, nullptr));
+ EXPECT_TRUE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
const char kExpected2[] = R"({
"package1": {
"commands": {
@@ -1313,14 +1292,14 @@
}
}
})";
- EXPECT_JSON_EQ(kExpected2, manager.GetTraits());
+ EXPECT_JSON_EQ(kExpected2, manager_.GetTraits());
const char kExpectedComponents2[] = R"({
"__weave__": { "traits": ["package1", "package2", "package3"] }
})";
- EXPECT_JSON_EQ(kExpectedComponents2, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpectedComponents2, manager_.GetComponents());
// Redefining existing commands.
- EXPECT_FALSE(manager.AddLegacyCommandDefinitions(*json, nullptr));
+ EXPECT_FALSE(manager_.AddLegacyCommandDefinitions(*json, nullptr));
const char kStateDefs1[] = R"({
"package1": {
@@ -1333,11 +1312,11 @@
}
})";
json = CreateDictionaryValue(kStateDefs1);
- EXPECT_TRUE(manager.AddLegacyStateDefinitions(*json, nullptr));
+ EXPECT_TRUE(manager_.AddLegacyStateDefinitions(*json, nullptr));
const char kExpectedComponents3[] = R"({
"__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
})";
- EXPECT_JSON_EQ(kExpectedComponents3, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpectedComponents3, manager_.GetComponents());
const char kExpected3[] = R"({
"package1": {
@@ -1376,14 +1355,14 @@
}
}
})";
- EXPECT_JSON_EQ(kExpected3, manager.GetTraits());
+ EXPECT_JSON_EQ(kExpected3, manager_.GetTraits());
const char kExpectedComponents4[] = R"({
"__weave__": { "traits": ["package1", "package2", "package3", "package4"] }
})";
- EXPECT_JSON_EQ(kExpectedComponents4, manager.GetComponents());
+ EXPECT_JSON_EQ(kExpectedComponents4, manager_.GetComponents());
// Redefining existing commands.
- EXPECT_FALSE(manager.AddLegacyStateDefinitions(*json, nullptr));
+ EXPECT_FALSE(manager_.AddLegacyStateDefinitions(*json, nullptr));
const char kExpected4[] = R"({
"package1": {
@@ -1406,11 +1385,10 @@
"command2": { "minimalRole": "owner" }
}
})";
- EXPECT_JSON_EQ(kExpected4, manager.GetLegacyCommandDefinitions());
+ EXPECT_JSON_EQ(kExpected4, manager_.GetLegacyCommandDefinitions());
}
-TEST(ComponentManager, GetLegacyState) {
- ComponentManagerImpl manager;
+TEST_F(ComponentManagerTest, GetLegacyState) {
const char kTraits[] = R"({
"trait1": {
"state": {
@@ -1426,13 +1404,13 @@
}
})";
auto traits = CreateDictionaryValue(kTraits);
- ASSERT_TRUE(manager.LoadTraits(*traits, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp1", {"trait1"}, nullptr));
- ASSERT_TRUE(manager.AddComponent("", "comp2", {"trait2"}, nullptr));
+ ASSERT_TRUE(manager_.LoadTraits(*traits, nullptr));
+ ASSERT_TRUE(manager_.AddComponent("", "comp1", {"trait1"}, nullptr));
+ ASSERT_TRUE(manager_.AddComponent("", "comp2", {"trait2"}, nullptr));
- ASSERT_TRUE(manager.SetStatePropertiesFromJson(
+ ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
"comp1", R"({"trait1": {"prop1": "foo", "prop2": "bar"}})", nullptr));
- ASSERT_TRUE(manager.SetStatePropertiesFromJson(
+ ASSERT_TRUE(manager_.SetStatePropertiesFromJson(
"comp2", R"({"trait2": {"prop3": "baz", "prop4": "quux"}})", nullptr));
const char kExpected[] = R"({
@@ -1445,10 +1423,10 @@
"prop4": "quux"
}
})";
- EXPECT_JSON_EQ(kExpected, manager.GetLegacyState());
+ EXPECT_JSON_EQ(kExpected, manager_.GetLegacyState());
}
-TEST(ComponentManager, TestMockComponentManager) {
+TEST_F(ComponentManagerTest, TestMockComponentManager) {
// Check that all the virtual methods are mocked out.
MockComponentManager mock;
}
diff --git a/src/device_manager.cc b/src/device_manager.cc
index 7a9021f..cb575b8 100644
--- a/src/device_manager.cc
+++ b/src/device_manager.cc
@@ -13,6 +13,7 @@
#include "src/component_manager_impl.h"
#include "src/config.h"
#include "src/device_registration_info.h"
+#include "src/privet/auth_manager.h"
#include "src/privet/privet_manager.h"
#include "src/string_utils.h"
#include "src/utils.h"
@@ -26,15 +27,26 @@
provider::DnsServiceDiscovery* dns_sd,
provider::HttpServer* http_server,
provider::Wifi* wifi,
- provider::Bluetooth* bluetooth) {
- component_manager_.reset(new ComponentManagerImpl);
+ provider::Bluetooth* bluetooth)
+ : config_{new Config{config_store}},
+ component_manager_{new ComponentManagerImpl} {
+ config_->Load();
- std::unique_ptr<Config> config{new Config{config_store}};
- config->Load();
+ if (http_server) {
+ auth_manager_.reset(
+ new privet::AuthManager(config_->GetSettings().secret,
+ http_server->GetHttpsCertificateFingerprint()));
+
+ if (auth_manager_->GetSecret() != config_->GetSettings().secret) {
+ // There is no Config::OnChangedCallback registered.
+ Config::Transaction transaction(config_.get());
+ transaction.set_secret(auth_manager_->GetSecret());
+ }
+ }
device_info_.reset(new DeviceRegistrationInfo(
- component_manager_.get(), std::move(config), task_runner, http_client,
- network));
+ config_.get(), component_manager_.get(), task_runner, http_client,
+ network, auth_manager_.get()));
base_api_handler_.reset(new BaseApiHandler{device_info_.get(), this});
device_info_->Start();
@@ -68,8 +80,8 @@
provider::Wifi* wifi,
provider::Bluetooth* bluetooth) {
privet_.reset(new privet::Manager{task_runner});
- privet_->Start(network, dns_sd, http_server, wifi, device_info_.get(),
- component_manager_.get());
+ privet_->Start(network, dns_sd, http_server, wifi, auth_manager_.get(),
+ device_info_.get(), component_manager_.get());
}
GcdState DeviceManager::GetGcdState() const {
@@ -93,6 +105,10 @@
return component_manager_->GetTraits();
}
+void DeviceManager::AddTraitDefsChangedCallback(const base::Closure& callback) {
+ component_manager_->AddTraitDefChangedCallback(callback);
+}
+
bool DeviceManager::AddComponent(const std::string& name,
const std::vector<std::string>& traits,
ErrorPtr* error) {
diff --git a/src/device_manager.h b/src/device_manager.h
index 3b042eb..d21f398 100644
--- a/src/device_manager.h
+++ b/src/device_manager.h
@@ -16,6 +16,7 @@
class DeviceRegistrationInfo;
namespace privet {
+class AuthManager;
class Manager;
} // namespace privet
@@ -38,6 +39,7 @@
void AddTraitDefinitionsFromJson(const std::string& json) override;
void AddTraitDefinitions(const base::DictionaryValue& dict) override;
const base::DictionaryValue& GetTraits() const override;
+ void AddTraitDefsChangedCallback(const base::Closure& callback) override;
bool AddComponent(const std::string& name,
const std::vector<std::string>& traits,
ErrorPtr* error) override;
@@ -99,6 +101,8 @@
provider::Wifi* wifi,
provider::Bluetooth* bluetooth);
+ std::unique_ptr<Config> config_;
+ std::unique_ptr<privet::AuthManager> auth_manager_;
std::unique_ptr<ComponentManager> component_manager_;
std::unique_ptr<DeviceRegistrationInfo> device_info_;
std::unique_ptr<BaseApiHandler> base_api_handler_;
diff --git a/src/device_registration_info.cc b/src/device_registration_info.cc
index 110ba81..a6d863c 100644
--- a/src/device_registration_info.cc
+++ b/src/device_registration_info.cc
@@ -27,6 +27,7 @@
#include "src/http_constants.h"
#include "src/json_error_codes.h"
#include "src/notification/xmpp_channel.h"
+#include "src/privet/auth_manager.h"
#include "src/string_utils.h"
#include "src/utils.h"
@@ -234,19 +235,32 @@
return code >= http::kContinue && code < http::kBadRequest;
}
+std::unique_ptr<base::DictionaryValue> BuildDeviceLocalAuth(
+ const std::string& id,
+ const std::string& client_token,
+ const std::string& cert_fingerprint) {
+ std::unique_ptr<base::DictionaryValue> auth{new base::DictionaryValue};
+ auth->SetString("localId", id);
+ auth->SetString("clientToken", client_token);
+ auth->SetString("certFingerprint", cert_fingerprint);
+ return auth;
+}
+
} // anonymous namespace
DeviceRegistrationInfo::DeviceRegistrationInfo(
+ Config* config,
ComponentManager* component_manager,
- std::unique_ptr<Config> config,
provider::TaskRunner* task_runner,
provider::HttpClient* http_client,
- provider::Network* network)
+ provider::Network* network,
+ privet::AuthManager* auth_manager)
: http_client_{http_client},
task_runner_{task_runner},
+ config_{config},
component_manager_{component_manager},
- config_{std::move(config)},
- network_{network} {
+ network_{network},
+ auth_manager_{auth_manager} {
cloud_backoff_policy_.reset(new BackoffEntry::Policy{});
cloud_backoff_policy_->num_errors_to_ignore = 0;
cloud_backoff_policy_->initial_delay_ms = 1000;
@@ -428,6 +442,9 @@
// Now that we have a new access token, retry the connection.
StartNotificationChannel();
}
+
+ SendAuthInfo();
+
callback.Run(nullptr);
}
@@ -628,7 +645,7 @@
access_token_expiration_ =
base::Time::Now() + base::TimeDelta::FromSeconds(expires_in);
- Config::Transaction change{config_.get()};
+ Config::Transaction change{config_};
change.set_cloud_id(cloud_id);
change.set_robot_account(robot_account);
change.set_refresh_token(refresh_token);
@@ -637,6 +654,7 @@
task_runner_->PostDelayedTask(FROM_HERE, base::Bind(callback, nullptr), {});
StartNotificationChannel();
+ SendAuthInfo();
// We're going to respond with our success immediately and we'll connect to
// cloud shortly after.
@@ -712,8 +730,8 @@
return;
}
- if (data->allow_response_without_content &&
- response->GetContentType().empty()) {
+ if (response->GetContentType().empty()) {
+ // Assume no body if no content type.
cloud_backoff_entry_->InformOfRequest(true);
return data->callback.Run({}, nullptr);
}
@@ -804,7 +822,7 @@
void DeviceRegistrationInfo::UpdateDeviceInfo(const std::string& name,
const std::string& description,
const std::string& location) {
- Config::Transaction change{config_.get()};
+ Config::Transaction change{config_};
change.set_name(name);
change.set_description(description);
change.set_location(location);
@@ -818,7 +836,7 @@
void DeviceRegistrationInfo::UpdateBaseConfig(AuthScope anonymous_access_role,
bool local_discovery_enabled,
bool local_pairing_enabled) {
- Config::Transaction change(config_.get());
+ Config::Transaction change(config_);
change.set_local_anonymous_access_role(anonymous_access_role);
change.set_local_discovery_enabled(local_discovery_enabled);
change.set_local_pairing_enabled(local_pairing_enabled);
@@ -836,7 +854,7 @@
"Unable to change config for registered device");
return false;
}
- Config::Transaction change{config_.get()};
+ Config::Transaction change{config_};
change.set_client_id(client_id);
change.set_client_secret(client_secret);
change.set_api_key(api_key);
@@ -912,6 +930,48 @@
AsWeakPtr()));
}
+void DeviceRegistrationInfo::SendAuthInfo() {
+ if (!auth_manager_ || auth_info_update_inprogress_)
+ return;
+ auth_info_update_inprogress_ = true;
+
+ std::string id = GetSettings().device_id;
+ std::string token = Base64Encode(auth_manager_->GetRootDeviceToken());
+ std::string fingerprint =
+ Base64Encode(auth_manager_->GetCertificateFingerprint());
+
+ std::unique_ptr<base::DictionaryValue> auth =
+ BuildDeviceLocalAuth(id, token, fingerprint);
+
+ // TODO(vitalybuka): Remove args from URL when server is ready.
+ std::string url =
+ GetDeviceURL("upsertLocalAuthInfo", {{"localid", id},
+ {"clienttoken", token},
+ {"certfingerprint", fingerprint}});
+ DoCloudRequest(
+ HttpClient::Method::kPost, url, auth.get(),
+ base::Bind(&DeviceRegistrationInfo::OnSendAuthInfoDone, AsWeakPtr()));
+}
+
+void DeviceRegistrationInfo::OnSendAuthInfoDone(
+ const base::DictionaryValue& body,
+ ErrorPtr error) {
+ CHECK(auth_info_update_inprogress_);
+ auth_info_update_inprogress_ = false;
+
+ if (!error) {
+ // TODO(vitalybuka): Enable this when we start uploading real data.
+ // Config::Transaction change{config_.get()};
+ // change.set_local_auth_info_changed(false);
+ // change.Commit();
+ return;
+ }
+
+ task_runner_->PostDelayedTask(
+ FROM_HERE, base::Bind(&DeviceRegistrationInfo::SendAuthInfo, AsWeakPtr()),
+ {});
+}
+
void DeviceRegistrationInfo::OnDeviceInfoRetrieved(
const base::DictionaryValue& device_info,
ErrorPtr error) {
@@ -1270,7 +1330,7 @@
connected_to_cloud_ = false;
LOG(INFO) << "Device is unregistered from the cloud. Deleting credentials";
- Config::Transaction change{config_.get()};
+ Config::Transaction change{config_};
// Keep cloud_id to switch to detect kInvalidCredentials after restart.
change.set_robot_account("");
change.set_refresh_token("");
diff --git a/src/device_registration_info.h b/src/device_registration_info.h
index bacab48..04fb7b6 100644
--- a/src/device_registration_info.h
+++ b/src/device_registration_info.h
@@ -41,6 +41,10 @@
class TaskRunner;
}
+namespace privet {
+class AuthManager;
+}
+
extern const char kErrorDomainOAuth2[];
extern const char kErrorDomainGCD[];
extern const char kErrorDomainGCDServer[];
@@ -53,12 +57,12 @@
base::Callback<void(const base::DictionaryValue& response,
ErrorPtr error)>;
- DeviceRegistrationInfo(
- ComponentManager* component_manager,
- std::unique_ptr<Config> config,
- provider::TaskRunner* task_runner,
- provider::HttpClient* http_client,
- provider::Network* network);
+ DeviceRegistrationInfo(Config* config,
+ ComponentManager* component_manager,
+ provider::TaskRunner* task_runner,
+ provider::HttpClient* http_client,
+ provider::Network* network,
+ privet::AuthManager* auth_manager);
~DeviceRegistrationInfo() override;
@@ -116,7 +120,7 @@
// TODO(vitalybuka): remove getters and pass config to dependent code.
const Config::Settings& GetSettings() const { return config_->GetSettings(); }
- Config* GetMutableConfig() { return config_.get(); }
+ Config* GetMutableConfig() { return config_; }
GcdState GetGcdState() const { return gcd_state_; }
@@ -178,8 +182,6 @@
provider::HttpClient::Method method;
std::string url;
std::string body;
- // Workaround for inconsistent APIs which returns no body.
- bool allow_response_without_content = false;
CloudRequestDoneCallback callback;
};
void SendCloudRequest(const std::shared_ptr<const CloudRequestData>& data);
@@ -199,6 +201,9 @@
ErrorPtr error);
void OnUpdateDeviceResourceError(ErrorPtr error);
+ void SendAuthInfo();
+ void OnSendAuthInfoDone(const base::DictionaryValue& body, ErrorPtr error);
+
// Callback from GetDeviceInfo() to retrieve the device resource timestamp
// and retry UpdateDeviceResource() call.
void OnDeviceInfoRetrieved(const base::DictionaryValue& device_info,
@@ -301,11 +306,12 @@
provider::HttpClient* http_client_{nullptr};
provider::TaskRunner* task_runner_{nullptr};
+
+ Config* config_{nullptr};
+
// Global component manager.
ComponentManager* component_manager_{nullptr};
- std::unique_ptr<Config> config_;
-
// Backoff manager for DoCloudRequest() method.
std::unique_ptr<BackoffEntry::Policy> cloud_backoff_policy_;
std::unique_ptr<BackoffEntry> cloud_backoff_entry_;
@@ -331,12 +337,15 @@
// is in flight to the cloud server.
ResourceUpdateCallbackList queued_resource_update_callbacks_;
+ bool auth_info_update_inprogress_{false};
+
std::unique_ptr<NotificationChannel> primary_notification_channel_;
std::unique_ptr<PullChannel> pull_channel_;
NotificationChannel* current_notification_channel_{nullptr};
bool notification_channel_starting_{false};
provider::Network* network_{nullptr};
+ privet::AuthManager* auth_manager_{nullptr};
// Tracks our GCD state.
GcdState gcd_state_{GcdState::kUnconfigured};
diff --git a/src/device_registration_info_unittest.cc b/src/device_registration_info_unittest.cc
index 72405dc..cc519d2 100644
--- a/src/device_registration_info_unittest.cc
+++ b/src/device_registration_info_unittest.cc
@@ -16,9 +16,12 @@
#include "src/bind_lambda.h"
#include "src/component_manager_impl.h"
#include "src/http_constants.h"
+#include "src/privet/auth_manager.h"
+#include "src/test/mock_clock.h"
using testing::_;
using testing::AtLeast;
+using testing::HasSubstr;
using testing::Invoke;
using testing::InvokeWithoutArgs;
using testing::Mock;
@@ -49,6 +52,7 @@
"fkjh7f.apps.googleusercontent.com";
const char kClientSecret[] = "5sdGdGlfolGlrFKfdFlgP6FG";
const char kCloudId[] = "4a7ea2d1-b331-1e1f-b206-e863c7635196";
+const char kDeviceId[] = "f6885e46-b432-42d7-86a5-d759bfb61f62";
const char kClaimTicketId[] = "RTcUE";
const char kAccessToken[] =
"ya29.1.AADtN_V-dLUM-sVZ0qVjG9Dxm5NgdS9J"
@@ -63,6 +67,12 @@
const char kRobotAccountEmail[] =
"6ed0b3f54f9bd619b942f4ad2441c252@"
"clouddevices.gserviceaccount.com";
+const char kAuthInfo[] = R"({
+ "certFingerprint":
+ "FQY6BEINDjw3FgsmYChRWgMzMhc4TC8uG0UUUFhdDz0=",
+ "clientToken": "UBPkqttkiWt5VWgICLP0eHuCQgECRgMaVm0+gA==",
+ "localId": "f6885e46-b432-42d7-86a5-d759bfb61f62"
+})";
} // namespace test_data
@@ -113,11 +123,11 @@
class DeviceRegistrationInfoTest : public ::testing::Test {
protected:
void SetUp() override {
- std::unique_ptr<Config> config{new Config{&config_store_}};
- config_ = config.get();
- dev_reg_.reset(new DeviceRegistrationInfo{&component_manager_,
- std::move(config), &task_runner_,
- &http_client_, nullptr});
+ EXPECT_CALL(clock_, Now())
+ .WillRepeatedly(Return(base::Time::FromTimeT(1450000000)));
+ dev_reg_.reset(new DeviceRegistrationInfo{&config_, &component_manager_,
+ &task_runner_, &http_client_,
+ nullptr, &auth_});
ReloadDefaults();
}
@@ -139,7 +149,7 @@
settings->service_url = test_data::kServiceURL;
return true;
}));
- config_->Load();
+ config_.Load();
dev_reg_->Start();
}
@@ -148,6 +158,7 @@
dict.SetString("refresh_token", test_data::kRefreshToken);
dict.SetString("cloud_id", test_data::kCloudId);
dict.SetString("robot_account", test_data::kRobotAccountEmail);
+ dict.SetString("device_id", test_data::kDeviceId);
std::string json_string;
base::JSONWriter::WriteWithOptions(
dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_string);
@@ -184,7 +195,14 @@
provider::test::MockConfigStore config_store_;
StrictMock<MockHttpClient> http_client_;
base::DictionaryValue data_;
- Config* config_{nullptr};
+ Config config_{&config_store_};
+ test::MockClock clock_;
+ privet::AuthManager auth_{
+ {68, 52, 36, 95, 74, 89, 25, 2, 31, 5, 65, 87, 64, 32, 17, 26, 8, 73, 57,
+ 16, 33, 82, 71, 10, 72, 62, 45, 1, 77, 97, 70, 24},
+ {21, 6, 58, 4, 66, 13, 14, 60, 55, 22, 11, 38, 96, 40, 81, 90, 3, 51, 50,
+ 23, 56, 76, 47, 46, 27, 69, 20, 80, 88, 93, 15, 61},
+ &clock_};
std::unique_ptr<DeviceRegistrationInfo> dev_reg_;
ComponentManagerImpl component_manager_;
};
@@ -244,6 +262,18 @@
callback.Run(ReplyWithJson(200, json), nullptr);
})));
+ EXPECT_CALL(
+ http_client_,
+ SendRequest(HttpClient::Method::kPost, HasSubstr("upsertLocalAuthInfo"),
+ HttpClient::Headers{GetAuthHeader(), GetJsonHeader()}, _, _))
+ .WillOnce(WithArgs<3, 4>(
+ Invoke([](const std::string& data,
+ const HttpClient::SendRequestCallback& callback) {
+ EXPECT_JSON_EQ(test_data::kAuthInfo, *CreateDictionaryValue(data));
+ base::DictionaryValue json;
+ callback.Run(ReplyWithJson(200, json), nullptr);
+ })));
+
EXPECT_TRUE(RefreshAccessToken(nullptr));
EXPECT_TRUE(HaveRegistrationCredentials());
}
@@ -340,6 +370,8 @@
}
TEST_F(DeviceRegistrationInfoTest, RegisterDevice) {
+ ReloadSettings();
+
auto json_traits = CreateDictionaryValue(R"({
'base': {
'commands': {
@@ -522,6 +554,18 @@
callback.Run(ReplyWithJson(200, json), nullptr);
})));
+ EXPECT_CALL(
+ http_client_,
+ SendRequest(HttpClient::Method::kPost, HasSubstr("upsertLocalAuthInfo"),
+ HttpClient::Headers{GetAuthHeader(), GetJsonHeader()}, _, _))
+ .WillOnce(WithArgs<3, 4>(
+ Invoke([](const std::string& data,
+ const HttpClient::SendRequestCallback& callback) {
+ EXPECT_JSON_EQ(test_data::kAuthInfo, *CreateDictionaryValue(data));
+ base::DictionaryValue json;
+ callback.Run(ReplyWithJson(200, json), nullptr);
+ })));
+
bool done = false;
dev_reg_->RegisterDevice(
test_data::kClaimTicketId, base::Bind([this, &done](ErrorPtr error) {
diff --git a/src/privet/auth_manager.cc b/src/privet/auth_manager.cc
index 0864242..49ef787 100644
--- a/src/privet/auth_manager.cc
+++ b/src/privet/auth_manager.cc
@@ -11,12 +11,18 @@
#include "src/privet/openssl_utils.h"
#include "src/string_utils.h"
+extern "C" {
+#include "third_party/libuweave/src/macaroon.h"
+}
+
namespace weave {
namespace privet {
namespace {
const char kTokenDelimeter[] = ":";
+const size_t kCaveatBuffetSize = 32;
+const size_t kMaxMacaroonSize = 1024;
// Returns "scope:id:time".
std::string CreateTokenData(const UserInfo& user_info, const base::Time& time) {
@@ -49,11 +55,30 @@
return UserInfo{static_cast<AuthScope>(scope), id};
}
+class Caveat {
+ public:
+ Caveat(UwMacaroonCaveatType type, uint32_t value) {
+ CHECK(uw_macaroon_caveat_create_with_uint_(type, value, buffer,
+ sizeof(buffer), &caveat));
+ }
+
+ const UwMacaroonCaveat& GetCaveat() const { return caveat; }
+
+ private:
+ UwMacaroonCaveat caveat;
+ uint8_t buffer[kCaveatBuffetSize];
+
+ DISALLOW_COPY_AND_ASSIGN(Caveat);
+};
+
} // namespace
AuthManager::AuthManager(const std::vector<uint8_t>& secret,
- const std::vector<uint8_t>& certificate_fingerprint)
- : secret_{secret}, certificate_fingerprint_{certificate_fingerprint} {
+ const std::vector<uint8_t>& certificate_fingerprint,
+ base::Clock* clock)
+ : clock_{clock ? clock : &default_clock_},
+ secret_{secret},
+ certificate_fingerprint_{certificate_fingerprint} {
if (secret_.size() != kSha256OutputSize) {
secret_.resize(kSha256OutputSize);
base::RandBytes(secret_.data(), secret_.size());
@@ -63,9 +88,8 @@
AuthManager::~AuthManager() {}
// Returns "[hmac]scope:id:time".
-std::vector<uint8_t> AuthManager::CreateAccessToken(const UserInfo& user_info,
- const base::Time& time) {
- std::string data_str{CreateTokenData(user_info, time)};
+std::vector<uint8_t> AuthManager::CreateAccessToken(const UserInfo& user_info) {
+ std::string data_str{CreateTokenData(user_info, Now())};
std::vector<uint8_t> data{data_str.begin(), data_str.end()};
std::vector<uint8_t> hash{HmacSha256(secret_, data)};
hash.insert(hash.end(), data.begin(), data.end());
@@ -84,5 +108,29 @@
return SplitTokenData(std::string(data.begin(), data.end()), time);
}
+std::vector<uint8_t> AuthManager::GetRootDeviceToken() const {
+ Caveat scope{kUwMacaroonCaveatTypeScope, kUwMacaroonCaveatScopeTypeOwner};
+ Caveat issued{kUwMacaroonCaveatTypeIssued,
+ static_cast<uint32_t>(Now().ToTimeT())};
+
+ UwMacaroonCaveat caveats[] = {
+ scope.GetCaveat(), issued.GetCaveat(),
+ };
+
+ UwMacaroon macaroon{};
+ CHECK(uw_macaroon_new_from_root_key_(
+ &macaroon, secret_.data(), secret_.size(), caveats, arraysize(caveats)));
+
+ std::vector<uint8_t> token(kMaxMacaroonSize);
+ size_t len = 0;
+ CHECK(uw_macaroon_dump_(&macaroon, token.data(), token.size(), &len));
+ token.resize(len);
+ return token;
+}
+
+base::Time AuthManager::Now() const {
+ return clock_->Now();
+}
+
} // namespace privet
} // namespace weave
diff --git a/src/privet/auth_manager.h b/src/privet/auth_manager.h
index 607b820..b3a9599 100644
--- a/src/privet/auth_manager.h
+++ b/src/privet/auth_manager.h
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
+#include <base/time/default_clock.h>
#include <base/time/time.h>
#include <weave/error.h>
@@ -19,11 +20,11 @@
class AuthManager {
public:
AuthManager(const std::vector<uint8_t>& secret,
- const std::vector<uint8_t>& certificate_fingerprint);
+ const std::vector<uint8_t>& certificate_fingerprint,
+ base::Clock* clock = nullptr);
~AuthManager();
- std::vector<uint8_t> CreateAccessToken(const UserInfo& user_info,
- const base::Time& time);
+ std::vector<uint8_t> CreateAccessToken(const UserInfo& user_info);
UserInfo ParseAccessToken(const std::vector<uint8_t>& token,
base::Time* time) const;
@@ -31,8 +32,14 @@
const std::vector<uint8_t>& GetCertificateFingerprint() const {
return certificate_fingerprint_;
}
+ std::vector<uint8_t> GetRootDeviceToken() const;
+
+ base::Time Now() const;
private:
+ base::DefaultClock default_clock_;
+ base::Clock* clock_{nullptr};
+
std::vector<uint8_t> secret_;
std::vector<uint8_t> certificate_fingerprint_;
diff --git a/src/privet/auth_manager_unittest.cc b/src/privet/auth_manager_unittest.cc
index 6b9ae29..4847e01 100644
--- a/src/privet/auth_manager_unittest.cc
+++ b/src/privet/auth_manager_unittest.cc
@@ -4,19 +4,41 @@
#include "src/privet/auth_manager.h"
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <weave/settings.h>
+#include "src/data_encoding.h"
+#include "src/test/mock_clock.h"
+
+using testing::Return;
+
namespace weave {
namespace privet {
class AuthManagerTest : public testing::Test {
public:
- void SetUp() override {}
+ void SetUp() override {
+ EXPECT_GE(auth_.GetSecret().size(), 32u);
+ EXPECT_GE(auth_.GetCertificateFingerprint().size(), 32u);
+
+ EXPECT_CALL(clock_, Now())
+ .WillRepeatedly(Return(base::Time::FromTimeT(1410000000)));
+ }
protected:
- const base::Time time_ = base::Time::FromTimeT(1410000000);
- AuthManager auth_{{}, {}};
+ const std::vector<uint8_t> kSecret{69, 53, 17, 37, 80, 73, 2, 5, 79, 64, 41,
+ 57, 12, 54, 65, 63, 72, 74, 93, 81, 20, 95,
+ 89, 3, 94, 92, 27, 21, 49, 90, 36, 6};
+ const std::vector<uint8_t> kSecret2{
+ 78, 40, 39, 68, 29, 19, 70, 86, 38, 61, 13, 55, 33, 32, 51, 52,
+ 34, 43, 97, 48, 8, 56, 11, 99, 50, 59, 24, 26, 31, 71, 76, 28};
+ const std::vector<uint8_t> kFingerprint{
+ 22, 47, 23, 77, 42, 98, 96, 25, 83, 16, 9, 14, 91, 44, 15, 75,
+ 60, 62, 10, 18, 82, 35, 88, 100, 30, 45, 7, 46, 67, 84, 58, 85};
+
+ test::MockClock clock_;
+ AuthManager auth_{kSecret, kFingerprint, &clock_};
};
TEST_F(AuthManagerTest, RandomSecret) {
@@ -24,63 +46,92 @@
}
TEST_F(AuthManagerTest, DifferentSecret) {
- AuthManager auth{{}, {}};
+ AuthManager auth{kSecret2, {}};
+ EXPECT_GE(auth.GetSecret().size(), 32u);
EXPECT_NE(auth_.GetSecret(), auth.GetSecret());
}
TEST_F(AuthManagerTest, Constructor) {
- std::vector<uint8_t> secret;
- std::vector<uint8_t> fingerpint;
- for (uint8_t i = 0; i < 32; ++i) {
- secret.push_back(i);
- fingerpint.push_back(i + 100);
- }
+ EXPECT_EQ(kSecret, auth_.GetSecret());
+ EXPECT_EQ(kFingerprint, auth_.GetCertificateFingerprint());
+}
- AuthManager auth{secret, fingerpint};
- EXPECT_EQ(secret, auth.GetSecret());
- EXPECT_EQ(fingerpint, auth.GetCertificateFingerprint());
+TEST_F(AuthManagerTest, CreateAccessToken) {
+ EXPECT_EQ(
+ "OUH2L2npY+Gzwjf9AnqigGSK3hxIVR+xX8/Cnu4DGf8wOjA6MTQxMDAwMDAwMA==",
+ Base64Encode(auth_.CreateAccessToken(UserInfo{AuthScope::kNone, 123})));
+ EXPECT_EQ(
+ "iZx0qgEHFF5lq+Q503GtgU0d6gLQ9TlLsU+DcFbZb2QxOjIzNDoxNDEwMDAwMDAw",
+ Base64Encode(auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 234})));
+ EXPECT_EQ(
+ "fTjecsbwtYj6i8/qPJz900B8EMAjRqU8jLT9kfMoz0czOjQ1NjoxNDEwMDAwMDAw",
+ Base64Encode(auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456})));
+ EXPECT_CALL(clock_, Now())
+ .WillRepeatedly(Return(clock_.Now() + base::TimeDelta::FromDays(11)));
+ EXPECT_EQ(
+ "qAmlJykiPTnFljfOKSf3BUII9YZG8/ttzD76q+fII1YyOjM0NToxNDEwOTUwNDAw",
+ Base64Encode(auth_.CreateAccessToken(UserInfo{AuthScope::kUser, 345})));
}
TEST_F(AuthManagerTest, CreateSameToken) {
- EXPECT_EQ(auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}, time_),
- auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}, time_));
+ EXPECT_EQ(auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}),
+ auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}));
}
TEST_F(AuthManagerTest, CreateTokenDifferentScope) {
- EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 456}, time_),
- auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}, time_));
+ EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 456}),
+ auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}));
}
TEST_F(AuthManagerTest, CreateTokenDifferentUser) {
- EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}, time_),
- auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 789}, time_));
+ EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}),
+ auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 789}));
}
TEST_F(AuthManagerTest, CreateTokenDifferentTime) {
- EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567}, time_),
- auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567},
- base::Time::FromTimeT(1400000000)));
+ auto token = auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567});
+ EXPECT_CALL(clock_, Now())
+ .WillRepeatedly(Return(base::Time::FromTimeT(1400000000)));
+ EXPECT_NE(token, auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567}));
}
TEST_F(AuthManagerTest, CreateTokenDifferentInstance) {
- EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kUser, 123}, time_),
- AuthManager({}, {})
- .CreateAccessToken(UserInfo{AuthScope::kUser, 123}, time_));
+ EXPECT_NE(
+ auth_.CreateAccessToken(UserInfo{AuthScope::kUser, 123}),
+ AuthManager({}, {}).CreateAccessToken(UserInfo{AuthScope::kUser, 123}));
}
TEST_F(AuthManagerTest, ParseAccessToken) {
// Multiple attempts with random secrets.
for (size_t i = 0; i < 1000; ++i) {
- AuthManager auth{{}, {}};
+ AuthManager auth{{}, {}, &clock_};
- auto token = auth.CreateAccessToken(UserInfo{AuthScope::kUser, 5}, time_);
+ auto token = auth.CreateAccessToken(UserInfo{AuthScope::kUser, 5});
base::Time time2;
EXPECT_EQ(AuthScope::kUser, auth.ParseAccessToken(token, &time2).scope());
EXPECT_EQ(5u, auth.ParseAccessToken(token, &time2).user_id());
// Token timestamp resolution is one second.
- EXPECT_GE(1, std::abs((time_ - time2).InSeconds()));
+ EXPECT_GE(1, std::abs((clock_.Now() - time2).InSeconds()));
}
}
+TEST_F(AuthManagerTest, GetRootDeviceToken) {
+ EXPECT_EQ("UFTBUcgd9d0HnPRnLeroN2mCQgECRgMaVArkgA==",
+ Base64Encode(auth_.GetRootDeviceToken()));
+}
+
+TEST_F(AuthManagerTest, GetRootDeviceTokenDifferentTime) {
+ EXPECT_CALL(clock_, Now())
+ .WillRepeatedly(Return(clock_.Now() + base::TimeDelta::FromDays(15)));
+ EXPECT_EQ("UGKqwMYGQNOd8jeYFDOsM02CQgECRgMaVB6rAA==",
+ Base64Encode(auth_.GetRootDeviceToken()));
+}
+
+TEST_F(AuthManagerTest, GetRootDeviceTokenDifferentSecret) {
+ AuthManager auth{kSecret2, {}, &clock_};
+ EXPECT_EQ("UK1ACOc3cWGjGBoTIX2bd3qCQgECRgMaVArkgA==",
+ Base64Encode(auth.GetRootDeviceToken()));
+}
+
} // namespace privet
} // namespace weave
diff --git a/src/privet/device_ui_kind.cc b/src/privet/device_ui_kind.cc
index ed7c5ff..8909bed 100644
--- a/src/privet/device_ui_kind.cc
+++ b/src/privet/device_ui_kind.cc
@@ -4,42 +4,40 @@
#include "src/privet/device_ui_kind.h"
+#include <unordered_map>
+
#include <base/logging.h>
namespace weave {
namespace privet {
std::string GetDeviceUiKind(const std::string& manifest_id) {
+
+ // Map of device short id to ui device kind
+ static const std::unordered_map<std::string, std::string> device_kind_map = {
+ {"AC", "accessPoint"},
+ {"AK", "aggregator"},
+ {"AM", "camera"},
+ {"AB", "developmentBoard"},
+ {"AH", "acHeating"},
+ {"AI", "light"},
+ {"AO", "lock"},
+ {"AE", "printer"},
+ {"AF", "scanner"},
+ {"AD", "speaker"},
+ {"AL", "storage"},
+ {"AJ", "toy"},
+ {"AA", "vendor"},
+ {"AN", "video"}
+ };
+
CHECK_EQ(5u, manifest_id.size());
- std::string kind = manifest_id.substr(0, 2);
- if (kind == "AC")
- return "accessPoint";
- if (kind == "AK")
- return "aggregator";
- if (kind == "AM")
- return "camera";
- if (kind == "AB")
- return "developmentBoard";
- if (kind == "AH")
- return "acHeating";
- if (kind == "AI")
- return "light";
- if (kind == "AO")
- return "lock";
- if (kind == "AE")
- return "printer";
- if (kind == "AF")
- return "scanner";
- if (kind == "AD")
- return "speaker";
- if (kind == "AL")
- return "storage";
- if (kind == "AJ")
- return "toy";
- if (kind == "AA")
- return "vendor";
- if (kind == "AN")
- return "video";
+ std::string short_id = manifest_id.substr(0, 2);
+
+ auto iter = device_kind_map.find(short_id);
+ if (iter != device_kind_map.end())
+ return iter->second;
+
LOG(FATAL) << "Invalid model id: " << manifest_id;
return std::string();
}
diff --git a/src/privet/mock_delegates.h b/src/privet/mock_delegates.h
index 0cfa4ed..5c003a7 100644
--- a/src/privet/mock_delegates.h
+++ b/src/privet/mock_delegates.h
@@ -62,8 +62,7 @@
class MockSecurityDelegate : public SecurityDelegate {
public:
- MOCK_METHOD2(CreateAccessToken,
- std::string(const UserInfo&, const base::Time&));
+ MOCK_METHOD1(CreateAccessToken, std::string(const UserInfo&));
MOCK_CONST_METHOD2(ParseAccessToken,
UserInfo(const std::string&, base::Time*));
MOCK_CONST_METHOD0(GetPairingTypes, std::set<PairingType>());
@@ -81,7 +80,7 @@
MOCK_METHOD2(CancelPairing, bool(const std::string&, ErrorPtr*));
MockSecurityDelegate() {
- EXPECT_CALL(*this, CreateAccessToken(_, _))
+ EXPECT_CALL(*this, CreateAccessToken(_))
.WillRepeatedly(Return("GuestAccessToken"));
EXPECT_CALL(*this, ParseAccessToken(_, _))
diff --git a/src/privet/openssl_utils.cc b/src/privet/openssl_utils.cc
index f7bee9b..f38fd1a 100644
--- a/src/privet/openssl_utils.cc
+++ b/src/privet/openssl_utils.cc
@@ -19,8 +19,8 @@
const std::vector<uint8_t>& data) {
std::vector<uint8_t> mac(kSha256OutputSize);
uint8_t hmac_state[uw_crypto_hmac_required_buffer_size_()];
- CHECK_EQ(0u, uw_crypto_hmac_init_(hmac_state, sizeof(hmac_state), key.data(),
- key.size()));
+ CHECK(uw_crypto_hmac_init_(hmac_state, sizeof(hmac_state), key.data(),
+ key.size()));
CHECK(uw_crypto_hmac_update_(hmac_state, sizeof(hmac_state), data.data(),
data.size()));
CHECK(uw_crypto_hmac_final_(hmac_state, sizeof(hmac_state), mac.data(),
diff --git a/src/privet/privet_handler.cc b/src/privet/privet_handler.cc
index 0c9887f..b71ea15 100644
--- a/src/privet/privet_handler.cc
+++ b/src/privet/privet_handler.cc
@@ -676,10 +676,9 @@
}
base::DictionaryValue output;
- output.SetString(
- kAuthAccessTokenKey,
- security_->CreateAccessToken(
- UserInfo{requested_auth_scope, ++last_user_id_}, base::Time::Now()));
+ output.SetString(kAuthAccessTokenKey,
+ security_->CreateAccessToken(
+ UserInfo{requested_auth_scope, ++last_user_id_}));
output.SetString(kAuthTokenTypeKey, kAuthorizationHeaderPrefix);
output.SetInteger(kAuthExpiresInKey, kAccessTokenExpirationSeconds);
output.SetString(kAuthScopeKey, EnumToString(requested_auth_scope));
diff --git a/src/privet/privet_handler_unittest.cc b/src/privet/privet_handler_unittest.cc
index 13c1999..09146e8 100644
--- a/src/privet/privet_handler_unittest.cc
+++ b/src/privet/privet_handler_unittest.cc
@@ -392,7 +392,7 @@
TEST_F(PrivetHandlerTest, AuthPairing) {
EXPECT_CALL(security_, IsValidPairingCode("testToken"))
.WillRepeatedly(Return(true));
- EXPECT_CALL(security_, CreateAccessToken(_, _))
+ EXPECT_CALL(security_, CreateAccessToken(_))
.WillRepeatedly(Return("OwnerAccessToken"));
const char kInput[] = R"({
'mode': 'pairing',
diff --git a/src/privet/privet_manager.cc b/src/privet/privet_manager.cc
index a308eec..16c552e 100644
--- a/src/privet/privet_manager.cc
+++ b/src/privet/privet_manager.cc
@@ -47,8 +47,12 @@
DnsServiceDiscovery* dns_sd,
HttpServer* http_server,
Wifi* wifi,
+ AuthManager* auth_manager,
DeviceRegistrationInfo* device,
ComponentManager* component_manager) {
+ CHECK(auth_manager);
+ CHECK(device);
+
disable_security_ = device->GetSettings().disable_security;
device_ = DeviceDelegate::CreateDefault(
@@ -58,19 +62,9 @@
component_manager);
cloud_observer_.Add(cloud_.get());
- auth_.reset(new AuthManager(device->GetSettings().secret,
- http_server->GetHttpsCertificateFingerprint()));
security_.reset(new SecurityManager(
- auth_.get(), device->GetSettings().pairing_modes,
+ auth_manager, device->GetSettings().pairing_modes,
device->GetSettings().embedded_code, disable_security_, task_runner_));
- if (device->GetSettings().secret.empty()) {
- // TODO(vitalybuka): Post all Config::Transaction to avoid following.
- task_runner_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&Manager::SaveDeviceSecret, weak_ptr_factory_.GetWeakPtr(),
- base::Unretained(device->GetMutableConfig())),
- {});
- }
network->AddConnectionChangedCallback(
base::Bind(&Manager::OnConnectivityChanged, base::Unretained(this)));
@@ -174,10 +168,5 @@
OnChanged();
}
-void Manager::SaveDeviceSecret(Config* config) {
- Config::Transaction transaction(config);
- transaction.set_secret(auth_->GetSecret());
-}
-
} // namespace privet
} // namespace weave
diff --git a/src/privet/privet_manager.h b/src/privet/privet_manager.h
index 1342584..371d843 100644
--- a/src/privet/privet_manager.h
+++ b/src/privet/privet_manager.h
@@ -50,6 +50,7 @@
provider::DnsServiceDiscovery* dns_sd,
provider::HttpServer* http_server,
provider::Wifi* wifi,
+ AuthManager* auth_manager,
DeviceRegistrationInfo* device,
ComponentManager* component_manager);
@@ -78,13 +79,10 @@
void OnChanged();
void OnConnectivityChanged();
- void SaveDeviceSecret(Config* config);
-
bool disable_security_{false};
provider::TaskRunner* task_runner_{nullptr};
std::unique_ptr<CloudDelegate> cloud_;
std::unique_ptr<DeviceDelegate> device_;
- std::unique_ptr<AuthManager> auth_;
std::unique_ptr<SecurityManager> security_;
std::unique_ptr<WifiBootstrapManager> wifi_bootstrap_manager_;
std::unique_ptr<Publisher> publisher_;
diff --git a/src/privet/security_delegate.h b/src/privet/security_delegate.h
index 40f297f..051bf20 100644
--- a/src/privet/security_delegate.h
+++ b/src/privet/security_delegate.h
@@ -22,8 +22,7 @@
virtual ~SecurityDelegate() {}
// Creates access token for the given scope, user id and |time|.
- virtual std::string CreateAccessToken(const UserInfo& user_info,
- const base::Time& time) = 0;
+ virtual std::string CreateAccessToken(const UserInfo& user_info) = 0;
// Validates |token| and returns scope and user id parsed from that.
virtual UserInfo ParseAccessToken(const std::string& token,
diff --git a/src/privet/security_manager.cc b/src/privet/security_manager.cc
index a838dae..00550d1 100644
--- a/src/privet/security_manager.cc
+++ b/src/privet/security_manager.cc
@@ -141,9 +141,8 @@
}
// Returns "base64([hmac]scope:id:time)".
-std::string SecurityManager::CreateAccessToken(const UserInfo& user_info,
- const base::Time& time) {
- return Base64Encode(auth_manager_->CreateAccessToken(user_info, time));
+std::string SecurityManager::CreateAccessToken(const UserInfo& user_info) {
+ return Base64Encode(auth_manager_->CreateAccessToken(user_info));
}
// Parses "base64([hmac]scope:id:time)".
@@ -344,7 +343,7 @@
if (is_security_disabled_)
return true;
- if (block_pairing_until_ > base::Time::Now()) {
+ if (block_pairing_until_ > auth_manager_->Now()) {
Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kDeviceBusy,
"Too many pairing attempts");
return false;
@@ -353,7 +352,7 @@
if (++pairing_attemts_ >= kMaxAllowedPairingAttemts) {
LOG(INFO) << "Pairing blocked for" << kPairingBlockingTimeMinutes
<< "minutes.";
- block_pairing_until_ = base::Time::Now();
+ block_pairing_until_ = auth_manager_->Now();
block_pairing_until_ +=
base::TimeDelta::FromMinutes(kPairingBlockingTimeMinutes);
}
diff --git a/src/privet/security_manager.h b/src/privet/security_manager.h
index 26a42d4..7a3c56a 100644
--- a/src/privet/security_manager.h
+++ b/src/privet/security_manager.h
@@ -60,8 +60,7 @@
~SecurityManager() override;
// SecurityDelegate methods
- std::string CreateAccessToken(const UserInfo& user_info,
- const base::Time& time) override;
+ std::string CreateAccessToken(const UserInfo& user_info) override;
UserInfo ParseAccessToken(const std::string& token,
base::Time* time) const override;
std::set<PairingType> GetPairingTypes() const override;
@@ -84,6 +83,8 @@
void RegisterPairingListeners(const PairingStartListener& on_start,
const PairingEndListener& on_end);
+ const AuthManager* GetAuthManager() const { return auth_manager_; }
+
private:
FRIEND_TEST_ALL_PREFIXES(SecurityManagerTest, ThrottlePairing);
// Allows limited number of new sessions without successful authorization.
diff --git a/src/privet/security_manager_unittest.cc b/src/privet/security_manager_unittest.cc
index 6236d78..d9f5c56 100644
--- a/src/privet/security_manager_unittest.cc
+++ b/src/privet/security_manager_unittest.cc
@@ -24,10 +24,12 @@
#include "src/data_encoding.h"
#include "src/privet/auth_manager.h"
#include "src/privet/openssl_utils.h"
+#include "src/test/mock_clock.h"
#include "third_party/chromium/crypto/p224_spake.h"
-using testing::Eq;
using testing::_;
+using testing::Eq;
+using testing::Return;
namespace weave {
namespace privet {
@@ -57,6 +59,11 @@
class SecurityManagerTest : public testing::Test {
protected:
+ void SetUp() override {
+ EXPECT_CALL(clock_, Now())
+ .WillRepeatedly(Return(base::Time::FromTimeT(1410000000)));
+ }
+
void PairAndAuthenticate(std::string* fingerprint, std::string* signature) {
std::string session_id;
std::string device_commitment_base64;
@@ -94,13 +101,15 @@
const base::Time time_ = base::Time::FromTimeT(1410000000);
provider::test::FakeTaskRunner task_runner_;
+ test::MockClock clock_;
AuthManager auth_manager_{
{},
{{
59, 47, 77, 247, 129, 187, 188, 158, 172, 105, 246, 93, 102, 83, 8,
138, 176, 141, 37, 63, 223, 40, 153, 121, 134, 23, 120, 106, 24, 205,
7, 135,
- }}};
+ }},
+ &clock_};
SecurityManager security_{&auth_manager_,
{PairingType::kEmbeddedCode},
"1234",
@@ -109,56 +118,54 @@
};
TEST_F(SecurityManagerTest, IsBase64) {
- EXPECT_TRUE(IsBase64(
- security_.CreateAccessToken(UserInfo{AuthScope::kUser, 7}, time_)));
+ EXPECT_TRUE(
+ IsBase64(security_.CreateAccessToken(UserInfo{AuthScope::kUser, 7})));
}
TEST_F(SecurityManagerTest, CreateSameToken) {
- EXPECT_EQ(
- security_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}, time_),
- security_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}, time_));
+ EXPECT_EQ(security_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}),
+ security_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}));
}
TEST_F(SecurityManagerTest, CreateTokenDifferentScope) {
- EXPECT_NE(
- security_.CreateAccessToken(UserInfo{AuthScope::kViewer, 456}, time_),
- security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}, time_));
+ EXPECT_NE(security_.CreateAccessToken(UserInfo{AuthScope::kViewer, 456}),
+ security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}));
}
TEST_F(SecurityManagerTest, CreateTokenDifferentUser) {
- EXPECT_NE(
- security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}, time_),
- security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 789}, time_));
+ EXPECT_NE(security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}),
+ security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 789}));
}
TEST_F(SecurityManagerTest, CreateTokenDifferentTime) {
- EXPECT_NE(
- security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567}, time_),
- security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567},
- base::Time::FromTimeT(1400000000)));
+ auto token = security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567});
+ EXPECT_CALL(clock_, Now())
+ .WillRepeatedly(Return(base::Time::FromTimeT(1400000000)));
+ EXPECT_NE(token,
+ security_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567}));
}
TEST_F(SecurityManagerTest, CreateTokenDifferentInstance) {
- AuthManager auth{{}, {}};
- EXPECT_NE(security_.CreateAccessToken(UserInfo{AuthScope::kUser, 123}, time_),
+ AuthManager auth{{}, {}, &clock_};
+ EXPECT_NE(security_.CreateAccessToken(UserInfo{AuthScope::kUser, 123}),
SecurityManager(&auth, {}, "", false, &task_runner_)
- .CreateAccessToken(UserInfo{AuthScope::kUser, 123}, time_));
+ .CreateAccessToken(UserInfo{AuthScope::kUser, 123}));
}
TEST_F(SecurityManagerTest, ParseAccessToken) {
// Multiple attempts with random secrets.
for (size_t i = 0; i < 1000; ++i) {
- AuthManager auth{{}, {}};
+ AuthManager auth{{}, {}, &clock_};
SecurityManager security{&auth, {}, "", false, &task_runner_};
std::string token =
- security.CreateAccessToken(UserInfo{AuthScope::kUser, 5}, time_);
+ security.CreateAccessToken(UserInfo{AuthScope::kUser, 5});
base::Time time2;
EXPECT_EQ(AuthScope::kUser,
security.ParseAccessToken(token, &time2).scope());
EXPECT_EQ(5u, security.ParseAccessToken(token, &time2).user_id());
// Token timestamp resolution is one second.
- EXPECT_GE(1, std::abs((time_ - time2).InSeconds()));
+ EXPECT_GE(1, std::abs((clock_.Now() - time2).InSeconds()));
}
}
@@ -251,13 +258,13 @@
EXPECT_TRUE(pair());
EXPECT_TRUE(pair());
EXPECT_FALSE(pair());
- EXPECT_GT(security_.block_pairing_until_, base::Time::Now());
+ EXPECT_GT(security_.block_pairing_until_, clock_.Now());
EXPECT_LE(security_.block_pairing_until_,
- base::Time::Now() + base::TimeDelta::FromMinutes(15));
+ clock_.Now() + base::TimeDelta::FromMinutes(15));
// Wait timeout.
security_.block_pairing_until_ =
- base::Time::Now() - base::TimeDelta::FromMinutes(1);
+ clock_.Now() - base::TimeDelta::FromMinutes(1);
// Allow exactly one attempt.
EXPECT_TRUE(pair());
@@ -265,7 +272,7 @@
// Wait timeout.
security_.block_pairing_until_ =
- base::Time::Now() - base::TimeDelta::FromMinutes(1);
+ clock_.Now() - base::TimeDelta::FromMinutes(1);
// Completely unblock by successfully pairing.
std::string fingerprint;
diff --git a/src/test/mock_clock.h b/src/test/mock_clock.h
new file mode 100644
index 0000000..f1a2260
--- /dev/null
+++ b/src/test/mock_clock.h
@@ -0,0 +1,22 @@
+// Copyright 2015 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_TEST_MOCK_CLOCK_H_
+#define LIBWEAVE_SRC_TEST_MOCK_CLOCK_H_
+
+#include <base/time/clock.h>
+#include <gmock/gmock.h>
+
+namespace weave {
+namespace test {
+
+class MockClock : public base::Clock {
+ public:
+ MOCK_METHOD0(Now, base::Time());
+};
+
+} // namespace test
+} // namespace weave
+
+#endif // LIBWEAVE_SRC_TEST_MOCK_CLOCK_H_
diff --git a/src/weave_unittest.cc b/src/weave_unittest.cc
index 66850cf..24c6973 100644
--- a/src/weave_unittest.cc
+++ b/src/weave_unittest.cc
@@ -183,10 +183,11 @@
protected:
void SetUp() override {}
+ template <class UrlMatcher>
void ExpectRequest(HttpClient::Method method,
- const std::string& url,
+ const UrlMatcher& url_matcher,
const std::string& json_response) {
- EXPECT_CALL(http_client_, SendRequest(method, url, _, _, _))
+ EXPECT_CALL(http_client_, SendRequest(method, url_matcher, _, _, _))
.WillOnce(WithArgs<4>(Invoke([json_response](
const HttpClient::SendRequestCallback& callback) {
std::unique_ptr<provider::test::MockHttpClientResponse> response{
@@ -400,6 +401,9 @@
"https://accounts.google.com/o/oauth2/token",
kAuthTokenResponse);
+ ExpectRequest(HttpClient::Method::kPost, HasSubstr("upsertLocalAuthInfo"),
+ {});
+
InitDnsSdPublishing(true, "DB");
bool done = false;
diff --git a/third_party/libuweave/src/crypto_hmac.c b/third_party/libuweave/src/crypto_hmac.c
index 56bb754..8b75133 100644
--- a/third_party/libuweave/src/crypto_hmac.c
+++ b/third_party/libuweave/src/crypto_hmac.c
@@ -24,7 +24,7 @@
}
HMAC_CTX* context = (HMAC_CTX*)state_buffer;
HMAC_CTX_init(context);
- return HMAC_Init(context, key, key_len, EVP_sha256()) ? 0 : sizeof(HMAC_CTX);
+ return HMAC_Init(context, key, key_len, EVP_sha256());
}
bool uw_crypto_hmac_update_(uint8_t* state_buffer,
diff --git a/third_party/libuweave/src/macaroon.c b/third_party/libuweave/src/macaroon.c
index d7e6491..70afda1 100644
--- a/third_party/libuweave/src/macaroon.c
+++ b/third_party/libuweave/src/macaroon.c
@@ -7,6 +7,8 @@
#include <string.h>
#include "src/crypto_utils.h"
+#include "src/macaroon_caveat.h"
+#include "src/macaroon_encoding.h"
static bool create_mac_tag_(const uint8_t* key, size_t key_len,
const UwMacaroonCaveat* caveats, size_t num_caveats,
@@ -124,3 +126,94 @@
return create_mac_tag_(old_macaroon->mac_tag, UW_MACAROON_MAC_LEN,
additional_caveat, 1, new_macaroon->mac_tag);
}
+
+// Encode a Macaroon to a byte string
+bool uw_macaroon_dump_(const UwMacaroon* macaroon,
+ uint8_t* out,
+ size_t out_len,
+ size_t* resulting_str_len) {
+ if (macaroon == NULL || out == NULL || out_len == 0 ||
+ resulting_str_len == NULL) {
+ return false;
+ }
+
+ size_t offset = 0, item_len;
+
+ if (!uw_macaroon_encoding_encode_byte_str_(
+ macaroon->mac_tag, UW_MACAROON_MAC_LEN, out, out_len, &item_len)) {
+ return false;
+ }
+ offset += item_len;
+
+ if (!uw_macaroon_encoding_encode_array_len_(
+ (uint32_t)(macaroon->num_caveats), out + offset, out_len - offset, &item_len)) {
+ return false;
+ }
+ offset += item_len;
+
+ for (size_t i = 0; i < macaroon->num_caveats; i++) {
+ if (!uw_macaroon_encoding_encode_byte_str_(
+ macaroon->caveats[i].bytes, macaroon->caveats[i].num_bytes,
+ out + offset, out_len - offset, &item_len)) {
+ return false;
+ }
+ offset += item_len;
+ }
+
+ *resulting_str_len = offset;
+ return true;
+}
+
+// Decode a byte string to a Macaroon
+bool uw_macaroon_load_(const uint8_t* in,
+ size_t in_len,
+ uint8_t* caveats_buffer,
+ size_t caveats_buffer_size,
+ UwMacaroon* macaroon) {
+ if (in == NULL || in_len == 0 || caveats_buffer == NULL ||
+ caveats_buffer_size == 0 || macaroon == NULL) {
+ return false;
+ }
+
+ const uint8_t* tag;
+ size_t tag_len;
+ if (!uw_macaroon_encoding_decode_byte_str_(in, in_len, &tag, &tag_len) ||
+ tag_len != UW_MACAROON_MAC_LEN) {
+ return false;
+ }
+ memcpy(macaroon->mac_tag, tag, UW_MACAROON_MAC_LEN);
+
+ size_t offset = 0, cbor_item_len;
+ if (!uw_macaroon_encoding_get_item_len_(in, in_len, &cbor_item_len)) {
+ return false;
+ }
+ offset += cbor_item_len;
+
+ uint32_t array_len;
+ if (!uw_macaroon_encoding_decode_array_len_(in + offset, in_len - offset,
+ &array_len)) {
+ return false;
+ }
+ macaroon->num_caveats = (size_t)array_len;
+ if (caveats_buffer_size < array_len * sizeof(UwMacaroonCaveat)) {
+ return false;
+ }
+
+ UwMacaroonCaveat* caveats = (UwMacaroonCaveat*)caveats_buffer;
+ for (size_t i = 0; i < array_len; i++) {
+ if (!uw_macaroon_encoding_get_item_len_(in + offset, in_len - offset,
+ &cbor_item_len)) {
+ return false;
+ }
+ offset += cbor_item_len;
+
+ if (!uw_macaroon_encoding_decode_byte_str_(in + offset, in_len - offset,
+ &(caveats[i].bytes),
+ &(caveats[i].num_bytes))) {
+ return false;
+ }
+ }
+ macaroon->caveats = caveats;
+
+ return true;
+}
diff --git a/third_party/libuweave/src/macaroon.h b/third_party/libuweave/src/macaroon.h
index 98ada11..61242f7 100644
--- a/third_party/libuweave/src/macaroon.h
+++ b/third_party/libuweave/src/macaroon.h
@@ -44,4 +44,21 @@
const UwMacaroonCaveat* additional_caveat,
uint8_t* buffer, size_t buffer_size);
+// Encode a Macaroon to a byte string
+bool uw_macaroon_dump_(const UwMacaroon* macaroon,
+ uint8_t* out,
+ size_t out_len,
+ size_t* resulting_str_len);
+
+// Decode a byte string to a Macaroon (the caveats_buffer here is used only for
+// the caveat pointer list *caveats in the UwMacaroon *macaroon). One note is
+// that the function doesn't copy string values to new buffers, so the caller
+// may maintain the input string around to make caveats with string values to
+// be usuable.
+bool uw_macaroon_load_(const uint8_t* in,
+ size_t in_len,
+ uint8_t* caveats_buffer,
+ size_t caveats_buffer_size,
+ UwMacaroon* macaroon);
+
#endif // LIBUWEAVE_SRC_MACAROON_H_
diff --git a/third_party/libuweave/src/macaroon_caveat.c b/third_party/libuweave/src/macaroon_caveat.c
index a04c30d..594f9de 100644
--- a/third_party/libuweave/src/macaroon_caveat.c
+++ b/third_party/libuweave/src/macaroon_caveat.c
@@ -12,7 +12,7 @@
// TODO(bozhu): Find a better way to pre-allocate memory for HMACc computations?
// Are C99 variable-length arrays allowed on embedded devices?
-#define HMAC_STATE_BUFFER_SIZE 300
+#define HMAC_STATE_BUFFER_SIZE 1024
static bool create_caveat_(UwMacaroonCaveatType type, const void* value,
size_t value_len, uint8_t* buffer,
diff --git a/third_party/libuweave/src/macaroon_caveat.h b/third_party/libuweave/src/macaroon_caveat.h
index 5f2c384..2e01742 100644
--- a/third_party/libuweave/src/macaroon_caveat.h
+++ b/third_party/libuweave/src/macaroon_caveat.h
@@ -21,9 +21,16 @@
kUwMacaroonCaveatTypeIssued = 3,
kUwMacaroonCaveatTypeTTL = 4,
kUwMacaroonCaveatTypeExpiration = 5,
- kUwMacaroonCaveatTypeSessionIdentifier = 16
+ kUwMacaroonCaveatTypeSessionIdentifier = 16,
} UwMacaroonCaveatType;
+typedef enum {
+ kUwMacaroonCaveatScopeTypeOwner = 2,
+ kUwMacaroonCaveatScopeTypeManager = 8,
+ kUwMacaroonCaveatScopeTypeUser = 14,
+ kUwMacaroonCaveatScopeTypeViewer = 20,
+} UwMacaroonCaveatScopeType;
+
bool uw_macaroon_caveat_create_without_value_(UwMacaroonCaveatType type,
uint8_t* buffer,
size_t buffer_size,
diff --git a/third_party/libuweave/src/macaroon_encoding.c b/third_party/libuweave/src/macaroon_encoding.c
index 214314d..3fb5323 100644
--- a/third_party/libuweave/src/macaroon_encoding.c
+++ b/third_party/libuweave/src/macaroon_encoding.c
@@ -15,9 +15,10 @@
// #define FLAG_8BYTE_UINT 27 // Do not support 8-byte
typedef enum {
- kCborMajorTypeUint = 0, // type 0
- kCborMajorTypeByteStr = 2 << 5, // type 2
- kCborMajorTypeTextStr = 3 << 5, // type 3
+ kCborMajorTypeUint = 0, // type 0 -- unsigned integers
+ kCborMajorTypeByteStr = 2 << 5, // type 2 -- byte strings
+ kCborMajorTypeTextStr = 3 << 5, // type 3 -- text strings
+ kCborMajorTypeArray = 4 << 5, // type 4 -- arrays
} CborMajorType;
// -- Prototypes begin --
@@ -49,7 +50,7 @@
CborMajorType type = get_type_(cbor);
if (type != kCborMajorTypeUint && type != kCborMajorTypeByteStr &&
- type != kCborMajorTypeTextStr) {
+ type != kCborMajorTypeTextStr && type != kCborMajorTypeArray) {
// Other types are not supported
return false;
}
@@ -61,6 +62,8 @@
*first_item_len = uint_min_len_(unsigned_int) + 1;
+ // For arrays, it returns only the length of the array length portion, not the
+ // length of the whole array
if (type == kCborMajorTypeByteStr || type == kCborMajorTypeTextStr) {
*first_item_len += (size_t)unsigned_int;
}
@@ -84,6 +87,18 @@
resulting_cbor_len);
}
+bool uw_macaroon_encoding_encode_array_len_(const uint32_t array_len,
+ uint8_t* buffer, size_t buffer_size,
+ size_t* resulting_cbor_len) {
+ if (buffer == NULL || buffer_size == 0 || resulting_cbor_len == NULL) {
+ return false;
+ }
+
+ set_type_(kCborMajorTypeArray, buffer);
+ return blindly_encode_uint_(array_len, buffer, buffer_size,
+ resulting_cbor_len);
+}
+
bool uw_macaroon_encoding_encode_byte_str_(const uint8_t* str, size_t str_len,
uint8_t* buffer, size_t buffer_size,
size_t* resulting_cbor_len) {
@@ -110,27 +125,30 @@
bool uw_macaroon_encoding_decode_uint_(const uint8_t* cbor, size_t cbor_len,
uint32_t* unsigned_int) {
- if (cbor == NULL || cbor_len == 0 || unsigned_int == NULL) {
- return false;
- }
-
- CborMajorType type = get_type_(cbor);
- if (type != kCborMajorTypeUint) {
+ if (cbor == NULL || cbor_len == 0 || unsigned_int == NULL ||
+ get_type_(cbor) != kCborMajorTypeUint) {
return false;
}
return blindly_decode_uint_(cbor, cbor_len, unsigned_int);
}
-bool uw_macaroon_encoding_decode_byte_str_(const uint8_t* cbor, size_t cbor_len,
- const uint8_t** out_str,
- size_t* out_str_len) {
- if (cbor == NULL || cbor_len == 0 || out_str == NULL || out_str_len == NULL) {
+bool uw_macaroon_encoding_decode_array_len_(const uint8_t* cbor,
+ size_t cbor_len,
+ uint32_t* array_len) {
+ if (cbor == NULL || cbor_len == 0 || array_len == NULL ||
+ get_type_(cbor) != kCborMajorTypeArray) {
return false;
}
- CborMajorType type = get_type_(cbor);
- if (type != kCborMajorTypeByteStr) {
+ return blindly_decode_uint_(cbor, cbor_len, array_len);
+}
+
+bool uw_macaroon_encoding_decode_byte_str_(const uint8_t* cbor, size_t cbor_len,
+ const uint8_t** out_str,
+ size_t* out_str_len) {
+ if (cbor == NULL || cbor_len == 0 || out_str == NULL || out_str_len == NULL ||
+ get_type_(cbor) != kCborMajorTypeByteStr) {
return false;
}
@@ -140,12 +158,8 @@
bool uw_macaroon_encoding_decode_text_str_(const uint8_t* cbor, size_t cbor_len,
const uint8_t** out_str,
size_t* out_str_len) {
- if (cbor == NULL || cbor_len == 0 || out_str == NULL || out_str_len == NULL) {
- return false;
- }
-
- CborMajorType type = get_type_(cbor);
- if (type != kCborMajorTypeTextStr) {
+ if (cbor == NULL || cbor_len == 0 || out_str == NULL || out_str_len == NULL ||
+ get_type_(cbor) != kCborMajorTypeTextStr) {
return false;
}
diff --git a/third_party/libuweave/src/macaroon_encoding.h b/third_party/libuweave/src/macaroon_encoding.h
index 2c11fd1..edddfc1 100644
--- a/third_party/libuweave/src/macaroon_encoding.h
+++ b/third_party/libuweave/src/macaroon_encoding.h
@@ -10,7 +10,7 @@
* cryptographic use, such as signatures. We only need to support a very small
* subset of the CBOR standard, since only these are used in our cryptographic
* designs. The supported data types are: unsigned integers (maximum 32 bits),
- * byte strings, and text strings.
+ * byte strings, text strings, and arrays.
*/
#include <stdbool.h>
@@ -25,6 +25,9 @@
bool uw_macaroon_encoding_encode_uint_(const uint32_t unsigned_int,
uint8_t* buffer, size_t buffer_size,
size_t* resulting_cbor_len);
+bool uw_macaroon_encoding_encode_array_len_(const uint32_t array_len,
+ uint8_t* buffer, size_t buffer_size,
+ size_t* resulting_cbor_len);
bool uw_macaroon_encoding_encode_byte_str_(const uint8_t* str, size_t str_len,
uint8_t* buffer, size_t buffer_size,
size_t* resulting_cbor_len);
@@ -34,6 +37,8 @@
bool uw_macaroon_encoding_decode_uint_(const uint8_t* cbor, size_t cbor_len,
uint32_t* unsigned_int);
+bool uw_macaroon_encoding_decode_array_len_(const uint8_t* cbor,
+ size_t cbor_len, uint32_t* array_len);
bool uw_macaroon_encoding_decode_byte_str_(const uint8_t* cbor, size_t cbor_len,
const uint8_t** str,
size_t* str_len);