chromium/components/policy/core/browser/android/policy_cache_updater_android_unittest.cc

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

#include "components/policy/core/browser/android/policy_cache_updater_android.h"

#include <jni.h>
#include <memory>

#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/memory/raw_ptr.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "components/policy/core/browser/configuration_policy_handler.h"
#include "components/policy/core/browser/policy_conversions_client.h"
#include "components/policy/core/browser/policy_error_map.h"
#include "components/policy/core/common/configuration_policy_provider.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_service_impl.h"
#include "components/strings/grit/components_strings.h"
#include "testing/gtest/include/gtest/gtest.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "components/policy/android/test_jni_headers/PolicyCacheUpdaterTestSupporter_jni.h"

using ::testing::_;
using ::testing::Return;

namespace policy {
namespace android {
namespace {
// The list of policies that can be cached is controlled by Java library. Hence
// we use real policy name for testing.
constexpr char kPolicyName[] = "BrowserSignin";
constexpr int kPolicyValue = 1;

class StubPolicyHandler : public ConfigurationPolicyHandler {
 public:
  StubPolicyHandler(const std::string& policy_name,
                    PolicyMap::MessageType error_level)
      : StubPolicyHandler(policy_name,
                          /*has_error=*/true,
                          error_level) {}
  StubPolicyHandler(
      const std::string& policy_name,
      bool has_error,
      PolicyMap::MessageType error_level = PolicyMap::MessageType::kError)
      : policy_name_(policy_name),
        has_error_(has_error),
        error_level_(error_level) {}
  StubPolicyHandler(const StubPolicyHandler&) = delete;
  StubPolicyHandler& operator=(const StubPolicyHandler&) = delete;
  ~StubPolicyHandler() override = default;

  bool CheckPolicySettings(const PolicyMap& policies,
                           PolicyErrorMap* errors) override {
    if (has_error_) {
      errors->AddError(policy_name_, IDS_POLICY_BLOCKED, /*error_path=*/{},
                       error_level_);
    }
    return policies.GetValue(policy_name_, base::Value::Type::INTEGER) &&
           error_level_ != PolicyMap::MessageType::kError;
  }

 private:
  void ApplyPolicySettings(const PolicyMap& policies,
                           PrefValueMap* prefs) override {}
  std::string policy_name_;
  bool has_error_;
  PolicyMap::MessageType error_level_;
};
}  // namespace

class PolicyCacheUpdaterAndroidTest : public ::testing::Test {
 public:
  PolicyCacheUpdaterAndroidTest() {
    policy_provider_.SetDefaultReturns(
        true /* is_initialization_complete_return */,
        true /* is_first_policy_load_complete_return */);
    j_support_ = Java_PolicyCacheUpdaterTestSupporter_Constructor(env_);
    policy_service_ = std::make_unique<policy::PolicyServiceImpl>(
        std::vector<raw_ptr<ConfigurationPolicyProvider, VectorExperimental>>{
            &policy_provider_});
    policy_handler_list_ = std::make_unique<ConfigurationPolicyHandlerList>(
        ConfigurationPolicyHandlerList::
            PopulatePolicyHandlerParametersCallback(),
        GetChromePolicyDetailsCallback(),
        /*are_future_policies_allowed_by_default=*/false);
  }
  ~PolicyCacheUpdaterAndroidTest() override = default;

  void TearDown() override {
    Java_PolicyCacheUpdaterTestSupporter_resetPolicyCache(env_, j_support_);
  }

  void SetPolicy(const std::string& policy, int policy_value) {
    policy_map_.Set(policy, PolicyLevel::POLICY_LEVEL_MANDATORY,
                    PolicyScope::POLICY_SCOPE_MACHINE,
                    PolicySource::POLICY_SOURCE_PLATFORM,
                    base::Value(policy_value),
                    /*external_data_fetcher=*/nullptr);
  }

  void UpdatePolicy() { policy_provider_.UpdateChromePolicy(policy_map_); }

  void VerifyIntPolicyNotCached(const std::string& policy) {
    Java_PolicyCacheUpdaterTestSupporter_verifyIntPolicyNotCached(
        env_, j_support_, base::android::ConvertUTF8ToJavaString(env_, policy));
  }

  void VerifyIntPolicyHasValue(const std::string& policy, int expected_value) {
    Java_PolicyCacheUpdaterTestSupporter_verifyIntPolicyHasValue(
        env_, j_support_, base::android::ConvertUTF8ToJavaString(env_, policy),
        expected_value);
  }

  ConfigurationPolicyHandlerList* policy_handler_list() {
    return policy_handler_list_.get();
  }

  PolicyService* policy_service() { return policy_service_.get(); }

  PolicyMap* policy_map() { return &policy_map_; }

 private:
  raw_ptr<JNIEnv> env_ = base::android::AttachCurrentThread();
  base::android::ScopedJavaLocalRef<jobject> j_support_;
  PolicyMap policy_map_;
  testing::NiceMock<MockConfigurationPolicyProvider> policy_provider_;
  std::unique_ptr<PolicyService> policy_service_;
  std::unique_ptr<ConfigurationPolicyHandlerList> policy_handler_list_;
  base::test::SingleThreadTaskEnvironment task_environment_;
};

TEST_F(PolicyCacheUpdaterAndroidTest, TestCachePolicy) {
  policy_handler_list()->AddHandler(
      std::make_unique<StubPolicyHandler>(kPolicyName, /*has_error=*/false));

  PolicyCacheUpdater updater(policy_service(), policy_handler_list());
  SetPolicy(kPolicyName, kPolicyValue);
  UpdatePolicy();
  VerifyIntPolicyHasValue(kPolicyName, kPolicyValue);
}

TEST_F(PolicyCacheUpdaterAndroidTest, TestPolicyNotExist) {
  policy_handler_list()->AddHandler(
      std::make_unique<StubPolicyHandler>(kPolicyName, /*has_error=*/false));

  PolicyCacheUpdater updater(policy_service(), policy_handler_list());
  UpdatePolicy();
  VerifyIntPolicyNotCached(kPolicyName);
}

TEST_F(PolicyCacheUpdaterAndroidTest, TestPolicyErrorPolicy) {
  policy_handler_list()->AddHandler(
      std::make_unique<StubPolicyHandler>(kPolicyName, /*has_error=*/true));

  PolicyCacheUpdater updater(policy_service(), policy_handler_list());
  SetPolicy(kPolicyName, kPolicyValue);
  UpdatePolicy();
  VerifyIntPolicyNotCached(kPolicyName);
}

TEST_F(PolicyCacheUpdaterAndroidTest, TestPolicyMapIgnoredPolicy) {
  policy_handler_list()->AddHandler(
      std::make_unique<StubPolicyHandler>(kPolicyName, /*has_error=*/false));

  PolicyCacheUpdater updater(policy_service(), policy_handler_list());
  SetPolicy(kPolicyName, kPolicyValue);
  policy_map()->GetMutable(kPolicyName)->SetIgnored();
  UpdatePolicy();
  VerifyIntPolicyNotCached(kPolicyName);
}

TEST_F(PolicyCacheUpdaterAndroidTest, TestPolicyMapErrorMessagePolicy) {
  policy_handler_list()->AddHandler(
      std::make_unique<StubPolicyHandler>(kPolicyName, /*has_error=*/false));

  PolicyCacheUpdater updater(policy_service(), policy_handler_list());
  SetPolicy(kPolicyName, kPolicyValue);
  policy_map()
      ->GetMutable(kPolicyName)
      ->AddMessage(PolicyMap::MessageType::kError, IDS_POLICY_BLOCKED);
  UpdatePolicy();
  VerifyIntPolicyNotCached(kPolicyName);
}

TEST_F(PolicyCacheUpdaterAndroidTest, TestPolicyMapWarningMessagePolicy) {
  policy_handler_list()->AddHandler(
      std::make_unique<StubPolicyHandler>(kPolicyName, /*has_error=*/false));

  PolicyCacheUpdater updater(policy_service(), policy_handler_list());
  SetPolicy(kPolicyName, kPolicyValue);
  policy_map()
      ->GetMutable(kPolicyName)
      ->AddMessage(PolicyMap::MessageType::kWarning, IDS_POLICY_BLOCKED);
  UpdatePolicy();
  VerifyIntPolicyHasValue(kPolicyName, kPolicyValue);
}

TEST_F(PolicyCacheUpdaterAndroidTest, TestPolicyUpdatedBeforeUpdaterCreated) {
  policy_handler_list()->AddHandler(
      std::make_unique<StubPolicyHandler>(kPolicyName, /*has_error=*/false));

  SetPolicy(kPolicyName, kPolicyValue);
  UpdatePolicy();
  VerifyIntPolicyNotCached(kPolicyName);
  PolicyCacheUpdater updater(policy_service(), policy_handler_list());
  VerifyIntPolicyHasValue(kPolicyName, kPolicyValue);
}

TEST_F(PolicyCacheUpdaterAndroidTest,
       TestWithFatalError_PolicyDoesntHaveValue) {
  policy_handler_list()->AddHandler(std::make_unique<StubPolicyHandler>(
      kPolicyName, PolicyMap::MessageType::kError));

  PolicyCacheUpdater updater(policy_service(), policy_handler_list());
  SetPolicy(kPolicyName, kPolicyValue);
  UpdatePolicy();
  VerifyIntPolicyNotCached(kPolicyName);
}

TEST_F(PolicyCacheUpdaterAndroidTest, TestWithWarningError_PolicyHasValue) {
  policy_handler_list()->AddHandler(std::make_unique<StubPolicyHandler>(
      kPolicyName, PolicyMap::MessageType::kWarning));

  PolicyCacheUpdater updater(policy_service(), policy_handler_list());
  SetPolicy(kPolicyName, kPolicyValue);
  UpdatePolicy();
  VerifyIntPolicyHasValue(kPolicyName, kPolicyValue);
}

TEST_F(PolicyCacheUpdaterAndroidTest, TestWithInfoError_PolicyHasValue) {
  policy_handler_list()->AddHandler(std::make_unique<StubPolicyHandler>(
      kPolicyName, PolicyMap::MessageType::kInfo));

  PolicyCacheUpdater updater(policy_service(), policy_handler_list());
  SetPolicy(kPolicyName, kPolicyValue);
  UpdatePolicy();
  VerifyIntPolicyHasValue(kPolicyName, kPolicyValue);
}

}  // namespace android
}  // namespace policy