chromium/chrome/browser/lacros/component_policy_lacros_browsertest.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/test/repeating_test_future.h"
#include "base/test/values_test_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/browser/policy/schema_registry_service.h"
#include "chrome/browser/profiles/profile_impl.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chromeos/lacros/lacros_service.h"
#include "chromeos/startup/browser_init_params.h"
#include "components/policy/core/common/policy_loader_lacros.h"
#include "components/policy/core/common/policy_service.h"
#include "content/public/test/browser_test.h"
#include "testing/gmock/include/gmock/gmock.h"

namespace {

const char kTestExtension[] = "super_secret_component_id";
constexpr char kValidationSchemaJson[] = R"(
{
  "type": "object",
  "properties": {
    "force_allowed_client_app_ids": {
      "title": "Force allowed client App identifiers.",
      "description": "List of client App identifiers",
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 32,
        "maxLength": 32
      }
    }
  }
}
)";

constexpr char kTestPolicy1[] = R"(
    {"force_allowed_client_app_ids":
    {"Value":["haeblkpifdemlfnkogkipmghfcbonief"]}})";
constexpr char kTestPolicy2[] = R"(
    {"force_allowed_client_app_ids":{"Value":
    ["haeblkpifdemlfnkogkipmghfcbonie1","haeblkpifdemlfnkogkipmghfcbonie2"]}})";

int map_size_test1 = 1, map_size_test2 = 1, list_size_test1 = 1,
    list_size_test2 = 2;

const policy::PolicyNamespace ns(policy::POLICY_DOMAIN_EXTENSIONS,
                                 kTestExtension);

void VerifyMap(int map_size, int list_size) {
  auto* profile = ProfileManager::GetPrimaryUserProfile();
  auto* policy_connector = profile->GetProfilePolicyConnector();

  const policy::PolicyMap& map =
      policy_connector->policy_service()->GetPolicies(ns);
  EXPECT_THAT(map, testing::SizeIs(map_size));
  const policy::PolicyMap::Entry* entry =
      map.Get("force_allowed_client_app_ids");
  ASSERT_TRUE(entry);
  const base::Value* value = entry->value(base::Value::Type::LIST);
  ASSERT_TRUE(value);
  const base::Value::List& list = value->GetList();
  EXPECT_THAT(list, testing::SizeIs(list_size));
}

}  // namespace

class TestPolicyServiceObserver : public policy::PolicyService::Observer {
 public:
  TestPolicyServiceObserver(policy::PolicyService* policy_service,
                            policy::PolicyDomain policy_domain)
      : policy_service_(policy_service), policy_domain_(policy_domain) {
    policy_service_->AddObserver(policy_domain_, this);
  }

  ~TestPolicyServiceObserver() override {
    policy_service_->RemoveObserver(policy_domain_, this);
  }

  void OnPolicyUpdated(const policy::PolicyNamespace& nsp,
                       const policy::PolicyMap& previous,
                       const policy::PolicyMap& current) override {
    policy_updated_future_.AddValue();
  }

  void WaitForUpdate() {
    ASSERT_TRUE(policy_updated_future_.Wait());
    policy_updated_future_.Take();
  }

  const raw_ptr<policy::PolicyService> policy_service_;
  const policy::PolicyDomain policy_domain_;

  base::test::RepeatingTestFuture<void> policy_updated_future_;
};

class ComponentPolicyLacrosBrowserTest : public InProcessBrowserTest {
 public:
  // Set custom init params in CreatedBrowserMainParts, as it must happen after
  // reading the data from Ash (happens in ContentMainRunner::Initialize) and
  // before profile creation.
  void CreatedBrowserMainParts(
      content::BrowserMainParts* browser_main_parts) override {
    base::Value json = base::test::ParseJson(kTestPolicy1);
    ASSERT_TRUE(json.is_dict());

    policy::ComponentPolicyMap component_policy;
    component_policy[ns] = std::move(json);
    crosapi::mojom::BrowserInitParamsPtr params =
        chromeos::BrowserInitParams::GetForTests()->Clone();
    params->device_account_component_policy = std::move(component_policy);
    chromeos::BrowserInitParams::SetInitParamsForTests(std::move(params));

    InProcessBrowserTest::CreatedBrowserMainParts(browser_main_parts);
  }
};

// Test to check the initial component policy received from Ash.
IN_PROC_BROWSER_TEST_F(ComponentPolicyLacrosBrowserTest,
                       BasicInitParamsSuccess) {
  auto* profile = ProfileManager::GetPrimaryUserProfile();

  auto* registry = profile->GetPolicySchemaRegistryService()->registry();
  const auto schema = policy::Schema::Parse(kValidationSchemaJson);
  ASSERT_TRUE(schema.has_value()) << schema.error();
  registry->RegisterComponent(ns, *schema);

  TestPolicyServiceObserver observer(
      profile->GetProfilePolicyConnector()->policy_service(), ns.domain);
  registry->SetDomainReady(ns.domain);
  observer.WaitForUpdate();
  VerifyMap(map_size_test1, list_size_test1);
}

// Test to check the update of component policy received from Ash.
IN_PROC_BROWSER_TEST_F(ComponentPolicyLacrosBrowserTest, BasicUpdateSuccess) {
  auto* profile = ProfileManager::GetPrimaryUserProfile();

  auto* registry = profile->GetPolicySchemaRegistryService()->registry();
  const auto schema = policy::Schema::Parse(kValidationSchemaJson);
  ASSERT_TRUE(schema.has_value()) << schema.error();
  registry->RegisterComponent(ns, *schema);
  registry->SetDomainReady(ns.domain);

  TestPolicyServiceObserver observer(
      profile->GetProfilePolicyConnector()->policy_service(), ns.domain);
  policy::ComponentPolicyMap component_policy;

  base::Value json = base::test::ParseJson(kTestPolicy2);
  ASSERT_TRUE(json.is_dict());
  component_policy[ns] = std::move(json);

  chromeos::LacrosService::Get()->NotifyComponentPolicyUpdated(
      std::move(component_policy));
  observer.WaitForUpdate();
  VerifyMap(map_size_test2, list_size_test2);
}