chromium/chrome/browser/ash/policy/external_data/device_cloud_external_data_policy_observer_browsertest.cc

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

#include "chrome/browser/ash/policy/external_data/device_cloud_external_data_policy_observer.h"

#include <memory>
#include <string>

#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/json/json_writer.h"
#include "base/path_service.h"
#include "base/test/test_future.h"
#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
#include "chrome/browser/ash/policy/core/device_policy_cros_browser_test.h"
#include "chrome/browser/ash/policy/external_data/cloud_external_data_manager_base_test_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/common/chrome_paths.h"
#include "chromeos/ash/components/settings/cros_settings_names.h"
#include "components/policy/core/common/policy_service.h"
#include "components/policy/policy_constants.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using ::testing::_;

namespace policy {

namespace {

const char kExternalDataPath[] = "policy/printers_configuration.json";
const char kExternalDataPathUpdated[] =
    "policy/printers_configuration_updated.json";

// The name of an External Data Policy in Device Policy.
const char* const kPolicyName = key::kDevicePrinters;

class MockDeviceCloudExternalDataPolicyObserverDelegate
    : public DeviceCloudExternalDataPolicyObserver::Delegate {
 public:
  MockDeviceCloudExternalDataPolicyObserverDelegate() {}

  void OnDeviceExternalDataFetched(const std::string& policy,
                                   std::unique_ptr<std::string> data,
                                   const base::FilePath& file_path) override {
    OnDeviceExternalDataFetchedProxy(policy, data.get(), file_path);
  }

  MOCK_METHOD1(OnDeviceExternalDataSet, void(const std::string&));
  MOCK_METHOD1(OnDeviceExternalDataCleared, void(const std::string&));
  MOCK_METHOD3(OnDeviceExternalDataFetchedProxy,
               void(const std::string&, std::string*, const base::FilePath&));
};

}  // namespace

class DeviceCloudExternalDataPolicyObserverTest
    : public DevicePolicyCrosBrowserTest {
 public:
  DeviceCloudExternalDataPolicyObserverTest() {}

 protected:
  void SetUpOnMainThread() override {
    EXPECT_TRUE(embedded_test_server()->Start());
    DevicePolicyCrosBrowserTest::SetUpOnMainThread();

    BrowserPolicyConnectorAsh* policy_connector =
        g_browser_process->platform_part()->browser_policy_connector_ash();
    ASSERT_TRUE(policy_connector);
    PolicyService* policy_service = policy_connector->GetPolicyService();
    ASSERT_TRUE(policy_service->IsInitializationComplete(POLICY_DOMAIN_CHROME));

    observer_ = std::make_unique<DeviceCloudExternalDataPolicyObserver>(
        policy_service, kPolicyName, &mock_delegate_);

    policy_change_registrar_ = std::make_unique<PolicyChangeRegistrar>(
        policy_service, PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
    policy_change_registrar_->Observe(
        kPolicyName, policy_changed_repeating_future_.GetRepeatingCallback());
  }

  void TearDownOnMainThread() override {
    observer_.reset();
    policy_change_registrar_.reset();
    DevicePolicyCrosBrowserTest::TearDownOnMainThread();
  }

  void SetDevicePrintersExternalData(const base::Value::Dict& policy_dict) {
    std::string policy;
    EXPECT_TRUE(base::JSONWriter::Write(policy_dict, &policy));
    device_policy()->payload().mutable_device_printers()->set_external_policy(
        policy);
    RefreshDevicePolicy();

    std::tuple<const base::Value*, const base::Value*> prev_curr_policy =
        policy_changed_repeating_future_.Take();
    ASSERT_TRUE(std::get<1>(prev_curr_policy));
    EXPECT_EQ(policy_dict, *std::get<1>(prev_curr_policy));
  }

  void ClearDevicePrintersExternalData() {
    device_policy()->payload().clear_device_printers();
    RefreshDevicePolicy();

    std::tuple<const base::Value*, const base::Value*> prev_curr_policy =
        policy_changed_repeating_future_.Take();
    ASSERT_FALSE(std::get<1>(prev_curr_policy));
  }

  std::string ReadExternalDataFile(const std::string& file_path) {
    base::FilePath test_data_dir;
    EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
    std::string external_data;
    {
      base::ScopedAllowBlockingForTesting allow_blocking;
      EXPECT_TRUE(base::ReadFileToString(test_data_dir.AppendASCII(file_path),
                                         &external_data));
    }
    return external_data;
  }

  MockDeviceCloudExternalDataPolicyObserverDelegate mock_delegate_;

 private:
  std::unique_ptr<DeviceCloudExternalDataPolicyObserver> observer_;
  std::unique_ptr<PolicyChangeRegistrar> policy_change_registrar_;
  base::test::TestFuture<const base::Value*, const base::Value*>
      policy_changed_repeating_future_;
};

IN_PROC_BROWSER_TEST_F(DeviceCloudExternalDataPolicyObserverTest,
                       DataSetAndDataClearedCalled) {
  EXPECT_CALL(mock_delegate_, OnDeviceExternalDataSet(kPolicyName));
  EXPECT_CALL(mock_delegate_, OnDeviceExternalDataCleared(kPolicyName));

  SetDevicePrintersExternalData(test::ConstructExternalDataPolicy(
      *embedded_test_server(), kExternalDataPath));
  ClearDevicePrintersExternalData();
}

IN_PROC_BROWSER_TEST_F(DeviceCloudExternalDataPolicyObserverTest, PolicyIsSet) {
  EXPECT_CALL(mock_delegate_, OnDeviceExternalDataSet(kPolicyName));

  base::test::TestFuture<std::string, std::string> on_data_fetched_future;
  std::string expected_data_file = ReadExternalDataFile(kExternalDataPath);
  EXPECT_CALL(
      mock_delegate_,
      OnDeviceExternalDataFetchedProxy(
          kPolicyName, testing::Pointee(testing::StrEq(expected_data_file)), _))
      .WillOnce(
          testing::Invoke([&on_data_fetched_future](
                              const std::string& policy, std::string* data,
                              const base::FilePath& file_path) {
            ASSERT_TRUE(data);
            on_data_fetched_future.SetValue(policy, std::string(*data));
          }));

  SetDevicePrintersExternalData(test::ConstructExternalDataPolicy(
      *embedded_test_server(), kExternalDataPath));
  EXPECT_EQ(kPolicyName, on_data_fetched_future.Get<0>());
  EXPECT_EQ(expected_data_file, on_data_fetched_future.Get<1>());
}

IN_PROC_BROWSER_TEST_F(DeviceCloudExternalDataPolicyObserverTest,
                       PolicyIsUpdated) {
  EXPECT_CALL(mock_delegate_, OnDeviceExternalDataSet(kPolicyName));

  {
    base::test::TestFuture<std::string, std::string> on_data_fetched_future;
    std::string expected_data_file = ReadExternalDataFile(kExternalDataPath);
    EXPECT_CALL(mock_delegate_,
                OnDeviceExternalDataFetchedProxy(
                    kPolicyName,
                    testing::Pointee(testing::StrEq(expected_data_file)), _))
        .WillOnce(
            testing::Invoke([&on_data_fetched_future](const std::string& policy,
                                                      std::string* data,
                                                      const base::FilePath&) {
              ASSERT_TRUE(data);
              on_data_fetched_future.SetValue(policy, *data);
            }));

    SetDevicePrintersExternalData(test::ConstructExternalDataPolicy(
        *embedded_test_server(), kExternalDataPath));
    EXPECT_EQ(kPolicyName, on_data_fetched_future.Get<0>());
    EXPECT_EQ(expected_data_file, on_data_fetched_future.Get<1>());
  }

  EXPECT_CALL(mock_delegate_, OnDeviceExternalDataSet(kPolicyName));

  {
    base::test::TestFuture<std::string, std::string> on_data_fetched_future;
    std::string expected_data_file =
        ReadExternalDataFile(kExternalDataPathUpdated);
    EXPECT_CALL(mock_delegate_,
                OnDeviceExternalDataFetchedProxy(
                    kPolicyName,
                    testing::Pointee(testing::StrEq(expected_data_file)), _))
        .WillOnce(
            testing::Invoke([&on_data_fetched_future](const std::string& policy,
                                                      std::string* data,
                                                      const base::FilePath&) {
              ASSERT_TRUE(data);
              on_data_fetched_future.SetValue(policy, *data);
            }));

    SetDevicePrintersExternalData(test::ConstructExternalDataPolicy(
        *embedded_test_server(), kExternalDataPathUpdated));
    EXPECT_EQ(kPolicyName, on_data_fetched_future.Get<0>());
    EXPECT_EQ(expected_data_file, on_data_fetched_future.Get<1>());
  }
}

}  // namespace policy