buffet: Add base.updateBaseConfiguration implementation

Required base command handled by buffet.

BUG=brillo:810
TEST=`FEATURES=test emerge-gizmo buffet`

Change-Id: I97ecd9f5d792cc636e76bbff92899a7ddfa4a605
Reviewed-on: https://chromium-review.googlesource.com/273618
Reviewed-by: Vitaly Buka <vitalybuka@chromium.org>
Commit-Queue: Vitaly Buka <vitalybuka@chromium.org>
Tested-by: Vitaly Buka <vitalybuka@chromium.org>
diff --git a/buffet/base_api_handler.cc b/buffet/base_api_handler.cc
index 69ed67c..16e9ec3 100644
--- a/buffet/base_api_handler.cc
+++ b/buffet/base_api_handler.cc
@@ -7,6 +7,7 @@
 #include "buffet/commands/command_instance.h"
 #include "buffet/commands/command_manager.h"
 #include "buffet/device_registration_info.h"
+#include "buffet/states/state_manager.h"
 
 namespace buffet {
 
@@ -30,6 +31,17 @@
     return true;
   }
 
+  bool GetParameter(const std::string& name, bool* value) const {
+    auto it = parameters_->find(name);
+    if (it == parameters_->end())
+      return false;
+    const BooleanValue* bool_value = it->second->GetBoolean();
+    if (!bool_value)
+      return false;
+    *value = bool_value->GetValue();
+    return true;
+  }
+
  private:
   const native_types::Object* parameters_;
 };
@@ -38,8 +50,9 @@
 
 BaseApiHandler::BaseApiHandler(
     const base::WeakPtr<DeviceRegistrationInfo>& device_info,
+    const std::shared_ptr<StateManager>& state_manager,
     const std::shared_ptr<CommandManager>& command_manager)
-    : device_info_{device_info} {
+    : device_info_{device_info}, state_manager_{state_manager} {
   command_manager->AddOnCommandAddedCallback(base::Bind(
       &BaseApiHandler::OnCommandAdded, weak_ptr_factory_.GetWeakPtr()));
 }
@@ -48,10 +61,44 @@
   if (command->GetStatus() != CommandInstance::kStatusQueued)
     return;
 
+  if (command->GetName() == "base.updateBaseConfiguration")
+    return UpdateBaseConfiguration(command);
+
   if (command->GetName() == "base.updateDeviceInfo")
     return UpdateDeviceInfo(command);
 }
 
+void BaseApiHandler::UpdateBaseConfiguration(CommandInstance* command) {
+  command->SetProgress({});
+
+  const BuffetConfig& config{device_info_->GetConfig()};
+  std::string anonymous_access_role{config.local_anonymous_access_role()};
+  bool discovery_enabled{config.local_discovery_enabled()};
+  bool pairing_enabled{config.local_pairing_enabled()};
+
+  ParametersReader parameters{&command->GetParameters()};
+  parameters.GetParameter("localAnonymousAccessMaxRole",
+                          &anonymous_access_role);
+  parameters.GetParameter("localDiscoveryEnabled", &discovery_enabled);
+  parameters.GetParameter("localPairingEnabled", &pairing_enabled);
+
+  chromeos::VariantDictionary state{
+      {"base.localAnonymousAccessMaxRole", anonymous_access_role},
+      {"base.localDiscoveryEnabled", discovery_enabled},
+      {"base.localPairingEnabled", pairing_enabled},
+  };
+  if (!state_manager_->SetProperties(state, nullptr)) {
+    return command->Abort();
+  }
+
+  if (!device_info_->UpdateBaseConfig(anonymous_access_role, discovery_enabled,
+                                      pairing_enabled, nullptr)) {
+    return command->Abort();
+  }
+
+  command->Done();
+}
+
 void BaseApiHandler::UpdateDeviceInfo(CommandInstance* command) {
   command->SetProgress({});
 
diff --git a/buffet/base_api_handler.h b/buffet/base_api_handler.h
index 8743bcf..9c9bcb0 100644
--- a/buffet/base_api_handler.h
+++ b/buffet/base_api_handler.h
@@ -15,22 +15,27 @@
 class CommandInstance;
 class CommandManager;
 class DeviceRegistrationInfo;
+class StateManager;
 
 // Handles commands from 'base' package.
 // Objects of the class subscribe for notification from CommandManager and
 // execute incoming commands.
 // Handled commands:
 //  base.updateDeviceInfo
+//  base.updateBaseConfiguration
 class BaseApiHandler final {
  public:
   BaseApiHandler(const base::WeakPtr<DeviceRegistrationInfo>& device_info,
+                 const std::shared_ptr<StateManager>& state_manager,
                  const std::shared_ptr<CommandManager>& command_manager);
 
  private:
   void OnCommandAdded(CommandInstance* command);
+  void UpdateBaseConfiguration(CommandInstance* command);
   void UpdateDeviceInfo(CommandInstance* command);
 
   base::WeakPtr<DeviceRegistrationInfo> device_info_;
+  std::shared_ptr<StateManager> state_manager_;
 
   base::WeakPtrFactory<BaseApiHandler> weak_ptr_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(BaseApiHandler);
diff --git a/buffet/base_api_handler_unittest.cc b/buffet/base_api_handler_unittest.cc
index d1de49f..cde0c41 100644
--- a/buffet/base_api_handler_unittest.cc
+++ b/buffet/base_api_handler_unittest.cc
@@ -25,13 +25,37 @@
     transport_ = std::make_shared<chromeos::http::fake::Transport>();
     command_manager_ = std::make_shared<CommandManager>();
     state_manager_ = std::make_shared<StateManager>(&mock_state_change_queue_);
-    state_manager_->Startup();
+    auto state_definition = unittests::CreateDictionaryValue(R"({
+      'base': {
+        'firmwareVersion': 'string',
+        'localDiscoveryEnabled': 'boolean',
+        'localAnonymousAccessMaxRole': [ 'none', 'viewer', 'user' ],
+        'localPairingEnabled': 'boolean',
+        'network': {
+          'properties': {
+            'name': 'string'
+          }
+        }
+      }
+    })");
+    auto state_defaults = unittests::CreateDictionaryValue(R"({
+      'base': {
+        'firmwareVersion': '123123',
+        'localDiscoveryEnabled': false,
+        'localAnonymousAccessMaxRole': 'none',
+        'localPairingEnabled': false
+      }
+    })");
+    ASSERT_TRUE(state_manager_->LoadStateDefinition(*state_definition, "base",
+                                                    nullptr));
+    ASSERT_TRUE(state_manager_->LoadStateDefaults(*state_defaults, nullptr));
     dev_reg_.reset(new DeviceRegistrationInfo(
         command_manager_, state_manager_,
         std::unique_ptr<BuffetConfig>{new BuffetConfig{
             std::unique_ptr<StorageInterface>{new MemStorage}}},
         transport_, true));
-    handler_.reset(new BaseApiHandler{dev_reg_->AsWeakPtr(), command_manager_});
+    handler_.reset(new BaseApiHandler{
+        dev_reg_->AsWeakPtr(), state_manager_, command_manager_});
   }
 
   void LoadCommands(const std::string& command_definitions) {
@@ -63,6 +87,68 @@
   int command_id_{0};
 };
 
+TEST_F(BaseApiHandlerTest, UpdateBaseConfiguration) {
+  LoadCommands(R"({
+    'base': {
+      'updateBaseConfiguration': {
+        'parameters': {
+          'localDiscoveryEnabled': 'boolean',
+          'localAnonymousAccessMaxRole': [ 'none', 'viewer', 'user' ],
+          'localPairingEnabled': 'boolean'
+         },
+         'results': {}
+      }
+    }
+  })");
+
+  const BuffetConfig& config{dev_reg_->GetConfig()};
+
+  AddCommand(R"({
+    'name' : 'base.updateBaseConfiguration',
+    'parameters': {
+      'localDiscoveryEnabled': false,
+      'localAnonymousAccessMaxRole': 'none',
+      'localPairingEnabled': false
+    }
+  })");
+  EXPECT_EQ("none", config.local_anonymous_access_role());
+  EXPECT_FALSE(config.local_discovery_enabled());
+  EXPECT_FALSE(config.local_pairing_enabled());
+
+  auto expected = R"({
+    'base': {
+      'firmwareVersion': '123123',
+      'localAnonymousAccessMaxRole': 'none',
+      'localDiscoveryEnabled': false,
+      'localPairingEnabled': false,
+      'network': {}
+    }
+  })";
+  EXPECT_JSON_EQ(expected, *state_manager_->GetStateValuesAsJson(nullptr));
+
+  AddCommand(R"({
+    'name' : 'base.updateBaseConfiguration',
+    'parameters': {
+      'localDiscoveryEnabled': true,
+      'localAnonymousAccessMaxRole': 'user',
+      'localPairingEnabled': true
+    }
+  })");
+  EXPECT_EQ("user", config.local_anonymous_access_role());
+  EXPECT_TRUE(config.local_discovery_enabled());
+  EXPECT_TRUE(config.local_pairing_enabled());
+  expected = R"({
+    'base': {
+      'firmwareVersion': '123123',
+      'localAnonymousAccessMaxRole': 'user',
+      'localDiscoveryEnabled': true,
+      'localPairingEnabled': true,
+      'network': {}
+    }
+  })";
+  EXPECT_JSON_EQ(expected, *state_manager_->GetStateValuesAsJson(nullptr));
+}
+
 TEST_F(BaseApiHandlerTest, UpdateDeviceInfo) {
   LoadCommands(R"({
     'base': {
diff --git a/buffet/device_registration_info.cc b/buffet/device_registration_info.cc
index 1fc329f..bd99917 100644
--- a/buffet/device_registration_info.cc
+++ b/buffet/device_registration_info.cc
@@ -672,6 +672,25 @@
   return true;
 }
 
+bool DeviceRegistrationInfo::UpdateBaseConfig(
+    const std::string& anonymous_access_role,
+    bool local_discovery_enabled,
+    bool local_pairing_enabled,
+    chromeos::ErrorPtr* error) {
+  BuffetConfig::Transaction change(config_.get());
+  if (!change.set_local_anonymous_access_role(anonymous_access_role)) {
+    chromeos::Error::AddToPrintf(error, FROM_HERE, kErrorDomainBuffet,
+                                 "invalid_parameter", "Invalid role: %s",
+                                 anonymous_access_role.c_str());
+    return false;
+  }
+
+  change.set_local_discovery_enabled(local_discovery_enabled);
+  change.set_local_pairing_enabled(local_pairing_enabled);
+
+  return true;
+}
+
 bool DeviceRegistrationInfo::UpdateServiceConfig(
     const std::string& client_id,
     const std::string& client_secret,
diff --git a/buffet/device_registration_info.h b/buffet/device_registration_info.h
index fe11d87..f8c2292 100644
--- a/buffet/device_registration_info.h
+++ b/buffet/device_registration_info.h
@@ -122,6 +122,12 @@
                         const std::string& location,
                         chromeos::ErrorPtr* error);
 
+  // Updates base device config.
+  bool UpdateBaseConfig(const std::string& anonymous_access_role,
+                        bool local_discovery_enabled,
+                        bool local_pairing_enabled,
+                        chromeos::ErrorPtr* error);
+
   // Updates GCD service configuration. Usually for testing.
   bool UpdateServiceConfig(const std::string& client_id,
                            const std::string& client_secret,
diff --git a/buffet/manager.cc b/buffet/manager.cc
index c69dfdd..1fd85c2 100644
--- a/buffet/manager.cc
+++ b/buffet/manager.cc
@@ -77,8 +77,8 @@
   device_info_->AddOnRegistrationChangedCallback(base::Bind(
       &Manager::OnRegistrationChanged, weak_ptr_factory_.GetWeakPtr()));
 
-  base_api_handler_.reset(
-      new BaseApiHandler{device_info_->AsWeakPtr(), command_manager_});
+  base_api_handler_.reset(new BaseApiHandler{
+      device_info_->AsWeakPtr(), state_manager_, command_manager_});
 
   device_info_->Start();
   dbus_adaptor_.RegisterWithDBusObject(&dbus_object_);
diff --git a/buffet/states/state_manager.h b/buffet/states/state_manager.h
index cf2c60a..a34f7c1 100644
--- a/buffet/states/state_manager.h
+++ b/buffet/states/state_manager.h
@@ -61,6 +61,7 @@
   std::vector<StateChange> GetAndClearRecordedStateChanges();
 
  private:
+  friend class BaseApiHandlerTest;
   friend class StateManagerTest;
 
   // Updates a single property value. |full_property_name| must be the full