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);