chromium/chrome/browser/lacros/policy_ui_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 <vector>

#include "base/json/json_reader.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_test_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chromeos/crosapi/mojom/crosapi.mojom.h"
#include "chromeos/startup/browser_init_params.h"
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "components/policy/policy_constants.h"
#include "components/policy/proto/cloud_policy.pb.h"
#include "components/policy/proto/device_management_backend.pb.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"

namespace em = enterprise_management;

namespace {

std::vector<uint8_t> GetValidPolicyFetchResponse() {
  em::PolicyData policy_data;
  const em::CloudPolicySettings policy_proto;
  policy_proto.SerializeToString(policy_data.mutable_policy_value());
  policy_data.set_policy_type(policy::dm_protocol::kChromeUserPolicyType);
  policy_data.set_managed_by("managed.domain");

  em::PolicyFetchResponse policy_response;
  policy_data.SerializeToString(policy_response.mutable_policy_data());
  std::vector<uint8_t> data;
  size_t size = policy_response.ByteSizeLong();
  data.resize(size);
  policy_response.SerializeToArray(data.data(), size);
  return data;
}

}  // namespace

class PolicyUiLacrosBrowserTest : public InProcessBrowserTest {
 public:
  PolicyUiLacrosBrowserTest() = default;
  PolicyUiLacrosBrowserTest(const PolicyUiLacrosBrowserTest&) = delete;
  PolicyUiLacrosBrowserTest& operator=(const PolicyUiLacrosBrowserTest&) =
      delete;

  // Set custom init params in SetUpInProcessBrowserTestFixture, as it must
  // happen after BrowserTestBase::SetUp sets up the crosapi command line
  // switches but before the profile-independent instance of PolicyLoaderLacros
  // is initialized (ChromeMainDelegate::PostEarlyInitialization).
  void SetUpInProcessBrowserTestFixture() override {
    std::vector<uint8_t> data = GetValidPolicyFetchResponse();
    auto init_params = chromeos::BrowserInitParams::GetForTests()->Clone();
    init_params->device_account_policy = data;
    chromeos::BrowserInitParams::SetInitParamsForTests(std::move(init_params));

    InProcessBrowserTest::SetUpInProcessBrowserTestFixture();
  }

  void ReadStatusFor(Browser* browser,
                     const std::string& policy_legend,
                     base::flat_map<std::string, std::string>* policy_status);
};

void PolicyUiLacrosBrowserTest::ReadStatusFor(
    Browser* browser,
    const std::string& policy_legend,
    base::flat_map<std::string, std::string>* policy_status) {
  // Retrieve the text contents of the status table with specified legend.
  const std::string javascript = R"JS(
    (function() {
      function readStatus() {
        // Wait for the status box to appear in case page just loaded.
        const statusSection = document.getElementById('status-section');
        if (statusSection.hidden) {
          return new Promise(resolve => {
            window.requestIdleCallback(resolve);
          }).then(readStatus);
        }

        const policies = getPolicyFieldsets();
        const statuses = {};
        for (let i = 0; i < policies.length; ++i) {
          const statusHeading = policies[i]
            .querySelector('.status-box-heading').textContent;
          const entries = {};
          const rows = policies[i]
            .querySelectorAll('.status-entry div:nth-child(2)');
          for (let j = 0; j < rows.length; ++j) {
            entries[rows[j].className.split(' ')[0]] = rows[j].textContent
              .trim();
          }
          statuses[statusHeading.trim()] = entries;
        }
        return JSON.stringify(statuses);
      };

      return new Promise(resolve => {
        window.requestIdleCallback(resolve);
      }).then(readStatus);
    })();
  )JS";
  content::WebContents* contents =
      browser->tab_strip_model()->GetActiveWebContents();
  std::string json = content::EvalJs(contents, javascript).ExtractString();
  std::optional<base::Value> statuses = base::JSONReader::Read(json);
  ASSERT_TRUE(statuses.has_value() && statuses->is_dict());
  const base::Value::Dict* actual_entries =
      statuses->GetDict().FindDict(policy_legend);
  ASSERT_TRUE(actual_entries);
  for (const auto entry : *actual_entries) {
    policy_status->insert_or_assign(entry.first, entry.second.GetString());
  }
}

IN_PROC_BROWSER_TEST_F(PolicyUiLacrosBrowserTest, ShowManagedByField) {
  ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(),
                                           GURL(chrome::kChromeUIPolicyURL)));
  base::flat_map<std::string, std::string> status;
  ReadStatusFor(browser(), "User policies", &status);
  EXPECT_EQ(status["managed-by"], "managed.domain");
}

IN_PROC_BROWSER_TEST_F(PolicyUiLacrosBrowserTest,
                       ShowManagedByFieldForSecondaryProfile) {
  // Create secondary profile and a browser for it.
  ProfileManager* profile_manager = g_browser_process->profile_manager();
  Profile& secondary_profile = profiles::testing::CreateProfileSync(
      profile_manager, profile_manager->GenerateNextProfileDirectoryPath());
  ASSERT_FALSE(secondary_profile.IsMainProfile());
  Browser* secondary_browser = CreateBrowser(&secondary_profile);

  ASSERT_TRUE(ui_test_utils::NavigateToURL(secondary_browser,
                                           GURL(chrome::kChromeUIPolicyURL)));
  base::flat_map<std::string, std::string> status;
  ReadStatusFor(secondary_browser, "User policies", &status);
  EXPECT_EQ(status["managed-by"], "");
}