chromium/chrome/browser/optimization_guide/android/optimization_guide_bridge_unittest.cc

// Copyright 2020 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/optimization_guide/android/optimization_guide_bridge.h"

#include "base/android/jni_android.h"
#include "base/memory/raw_ptr.h"
#include "base/test/gmock_callback_support.h"
#include "chrome/browser/optimization_guide/chrome_hints_manager.h"
#include "chrome/browser/optimization_guide/mock_optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "components/optimization_guide/core/optimization_guide_prefs.h"
#include "components/optimization_guide/proto/string_value.pb.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/testing_pref_service.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/test/browser_task_environment.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/browser/optimization_guide/android/native_j_unittests_jni_headers/OptimizationGuideBridgeNativeUnitTest_jni.h"

using ::testing::An;
using ::testing::ByRef;
using ::testing::DoAll;
using ::testing::Eq;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::UnorderedElementsAre;

namespace optimization_guide {
namespace android {

class OptimizationGuideBridgeTest : public testing::Test {
 public:
  OptimizationGuideBridgeTest() = default;
  ~OptimizationGuideBridgeTest() override = default;

  void SetUp() override {
    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    ASSERT_TRUE(profile_manager_.SetUp(temp_dir_.GetPath()));
    profile_ = profile_manager_.CreateTestingProfile(chrome::kInitialProfile);
    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
    optimization_guide::prefs::RegisterProfilePrefs(pref_service_->registry());

    optimization_guide_keyed_service_ = static_cast<
        MockOptimizationGuideKeyedService*>(
        OptimizationGuideKeyedServiceFactory::GetInstance()
            ->SetTestingFactoryAndUse(
                profile_,
                base::BindRepeating([](content::BrowserContext* context)
                                        -> std::unique_ptr<KeyedService> {
                  return std::make_unique<MockOptimizationGuideKeyedService>();
                })));
    j_test_ = Java_OptimizationGuideBridgeNativeUnitTest_Constructor(
        env_,
        optimization_guide_keyed_service_->GetJavaObject());
  }

  void RegisterOptimizationTypes() {
    optimization_guide_keyed_service_->RegisterOptimizationTypes(
        {optimization_guide::proto::DEFER_ALL_SCRIPT,
         optimization_guide::proto::LOADING_PREDICTOR});
  }

 protected:
  base::android::ScopedJavaGlobalRef<jobject> j_test_;
  raw_ptr<JNIEnv> env_ = base::android::AttachCurrentThread();
  raw_ptr<MockOptimizationGuideKeyedService> optimization_guide_keyed_service_;

 private:
  content::BrowserTaskEnvironment task_environment_{
      base::test::TaskEnvironment::MainThreadType::UI};
  TestingProfileManager profile_manager_{TestingBrowserProcess::GetGlobal()};
  raw_ptr<TestingProfile> profile_;
  base::ScopedTempDir temp_dir_;
  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
};

TEST_F(OptimizationGuideBridgeTest, RegisterOptimizationTypes) {
  EXPECT_CALL(*optimization_guide_keyed_service_,
              RegisterOptimizationTypes(UnorderedElementsAre(
                  optimization_guide::proto::LOADING_PREDICTOR,
                  optimization_guide::proto::DEFER_ALL_SCRIPT)));

  Java_OptimizationGuideBridgeNativeUnitTest_testRegisterOptimizationTypes(
      env_, j_test_);
}

TEST_F(OptimizationGuideBridgeTest, CanApplyOptimizationHasHint) {
  RegisterOptimizationTypes();
  optimization_guide::proto::LoadingPredictorMetadata hints_metadata;
  optimization_guide::OptimizationMetadata metadata;
  metadata.SetAnyMetadataForTesting(hints_metadata);
  EXPECT_CALL(*optimization_guide_keyed_service_,
              CanApplyOptimization(
                  GURL("https://example.com/"),
                  optimization_guide::proto::LOADING_PREDICTOR,
                  An<optimization_guide::OptimizationGuideDecisionCallback>()))
      .WillOnce(base::test::RunOnceCallback<2>(
          optimization_guide::OptimizationGuideDecision::kTrue,
          ByRef(metadata)));

  Java_OptimizationGuideBridgeNativeUnitTest_testCanApplyOptimizationHasHint(
      env_, j_test_);
}

TEST_F(OptimizationGuideBridgeTest, CanApplyOptimizationOnDemand) {
  optimization_guide::proto::LoadingPredictorMetadata lp_metadata;
  optimization_guide::OptimizationMetadata metadata;
  metadata.SetAnyMetadataForTesting(lp_metadata);

  optimization_guide::proto::StringValue ds_metadata;
  optimization_guide::OptimizationMetadata metadata2;
  metadata2.SetAnyMetadataForTesting(ds_metadata);

  base::flat_map<optimization_guide::proto::OptimizationType,
                 optimization_guide::OptimizationGuideDecisionWithMetadata>
      url1_decisions = {
          {optimization_guide::proto::LOADING_PREDICTOR,
           {optimization_guide::OptimizationGuideDecision::kTrue, metadata}},
          {optimization_guide::proto::DEFER_ALL_SCRIPT,
           {optimization_guide::OptimizationGuideDecision::kFalse}},
      };
  base::flat_map<optimization_guide::proto::OptimizationType,
                 optimization_guide::OptimizationGuideDecisionWithMetadata>
      url2_decisions = {
          {optimization_guide::proto::LOADING_PREDICTOR,
           {optimization_guide::OptimizationGuideDecision::kFalse}},
          {optimization_guide::proto::DEFER_ALL_SCRIPT,
           {optimization_guide::OptimizationGuideDecision::kTrue, metadata2}},
      };

  EXPECT_CALL(
      *optimization_guide_keyed_service_,
      CanApplyOptimizationOnDemand(
          UnorderedElementsAre(GURL("https://example.com/"),
                               GURL("https://example2.com/")),
          UnorderedElementsAre(optimization_guide::proto::LOADING_PREDICTOR,
                               optimization_guide::proto::DEFER_ALL_SCRIPT),
          optimization_guide::proto::CONTEXT_PAGE_INSIGHTS_HUB,
          base::test::IsNotNullCallback(),
          An<std::optional<
              optimization_guide::proto::RequestContextMetadata>>()))
      .WillOnce(DoAll(base::test::RunCallback<3>(GURL("https://example.com/"),
                                                 ByRef(url1_decisions)),
                      base::test::RunCallback<3>(GURL("https://example2.com/"),
                                                 ByRef(url2_decisions))));

  Java_OptimizationGuideBridgeNativeUnitTest_testCanApplyOptimizationOnDemand(
      env_, j_test_);
}

}  // namespace android
}  // namespace optimization_guide