chromium/chromeos/ash/components/growth/campaigns_manager_unittest.cc

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

#include "chromeos/ash/components/growth/campaigns_manager.h"

#include <memory>
#include <optional>
#include <string_view>

#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/constants/ash_switches.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/time/time.h"
#include "base/version.h"
#include "base/version_info/version_info.h"
#include "chromeos/ash/components/growth/campaigns_logger.h"
#include "chromeos/ash/components/growth/campaigns_model.h"
#include "chromeos/ash/components/growth/growth_metrics.h"
#include "chromeos/ash/components/growth/mock_campaigns_manager_client.h"
#include "components/account_id/account_id.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "components/user_manager/fake_user_manager.h"
#include "components/version_info/version_info.h"
#include "testing/gtest/include/gtest/gtest.h"

using ::testing::_;

namespace growth {
namespace {

inline constexpr char kValidCampaignsFileTemplate[] = R"(
    {
      "0": [
        // List is an invalid targeting.
        {
          "id": 1,
          "targetings": [
            []
          ],
          "payload": {}
        },
        // String is an invalid campaign.
        "Invalid campaign",
        {
          "id": 3,
          "studyId":1,
          "targetings": [
            {
              %s
            }
          ],
          "payload": {
            "demoModeApp": {
              "attractionLoop": {
                "videoSrcLang1": "/asset/peripherals_lang1.mp4",
                "videoSrcLang2": "/asset/peripherals_lang2.mp4"
              }
            }
          }
        }
      ]
    }
)";

inline constexpr char kValidCampaignsFileWithGroupIdTemplate[] = R"(
    {
      "0": [
        // List is an invalid targeting.
        {
          "id": 1,
          "targetings": [
            []
          ],
          "payload": {}
        },
        // String is an invalid campaign.
        "Invalid campaign",
        {
          "id": 3,
          "studyId":1,
          "groupId": 1,
          "targetings": [
            {
              %s
            }
          ],
          "payload": {
            "demoModeApp": {
              "attractionLoop": {
                "videoSrcLang1": "/asset/peripherals_lang1.mp4",
                "videoSrcLang2": "/asset/peripherals_lang2.mp4"
              }
            }
          }
        }
      ]
    }
)";

inline constexpr char kValidCampaignsFileMultiTargetingsTemplate[] = R"(
    {
      "0": [
        // List is an invalid targeting.
        {
          "id": 1,
          "targetings": [
            []
          ],
          "payload": {}
        },
        // String is an invalid campaign.
        "Invalid campaign",
        {
          "id": 3,
          "studyId":1,
          "targetings": %s,
          "payload": {
            "demoModeApp": {
              "attractionLoop": {
                "videoSrcLang1": "/asset/peripherals_lang1.mp4",
                "videoSrcLang2": "/asset/peripherals_lang2.mp4"
              }
            }
          }
        }
      ]
    }
)";

inline constexpr char
    kValidCampaignsFileRegisterTrialWithTriggerEventNameTemplate[] = R"(
    {
      "0": [
        {
          "id": 3,
          "studyId":1,
          // Configuration for `registerTrialWithTriggerEventName` with boolean
          // value.
          %s,
          "targetings": [
            {
              "runtime": {
                "triggerList": %s
              }
            }
          ],
          "payload": {
            "demoModeApp": {
              "attractionLoop": {
                "videoSrcLang1": "/asset/peripherals_lang1.mp4",
                "videoSrcLang2": "/asset/peripherals_lang2.mp4"
              }
            }
          }
        }
      ]
    }
)";

inline constexpr char kValidDemoModeTargeting[] = R"(
    "demoMode": {
      "retailers": ["bby", "bestbuy", "bbt"],
      "storeIds": ["2", "4", "6"],
      "countries": ["US"],
      "capability": {
        "isCloudGamingDevice": true,
        "isFeatureAwareDevice": true
      }
    }
)";

inline constexpr char kValidMultiTargetings[] = R"([
    // Targeting 1.
    {
      "runtime": {
        "appsOpened": [{"appId": "app_id_1"}]
      }
    },
    // Targeting 2.
    {
      "runtime": {
        "appsOpened": [{"appId": "app_id_2"}]
      }
    },
    // Targeting 3.
    {
      "runtime": {
        "appsOpened": [{"appId": "app_id_3"}]
      }
    }
  ])";

inline constexpr char kCampaignsFileName[] = "campaigns.json";

inline constexpr char kCampaignsExperimentTag[] = "exp_tag";

inline constexpr char kCampaignsManagerErrorHistogramName[] =
    "Ash.Growth.CampaignsManager.Error";

inline constexpr char
    kCampaignsComponentDownloadDurationSessionStartHistogram[] =
        "Ash.Growth.CampaignsComponent.DownloadDurationSessionStart";

inline constexpr char kCampaignsComponentDownloadDurationOobeHistogram[] =
    "Ash.Growth.CampaignsComponent.DownloadDurationInOobe";

inline constexpr char kCampaignsComponentReadDurationHistogram[] =
    "Ash.Growth.CampaignsComponent.ParseDuration";

inline constexpr char kCampaignMatchDurationHistogram[] =
    "Ash.Growth.CampaignsManager.MatchDuration";

inline constexpr char kGetCampaignBySlotHistogramName[] =
    "Ash.Growth.CampaignsManager.GetCampaignBySlot";

inline const base::Version kDefaultVersion("1.0.0.0");

inline constexpr char kTestPref1[] = "pref1";
inline constexpr char kTestPref2[] = "pref2";
inline constexpr char kTestPref3[] = "pref3";

// testing::InvokeArgument<N> does not work with base::OnceCallback. Use this
// gmock action template to invoke base::OnceCallback. `k` is the k-th argument
// and `T` is the callback's type.
ACTION_TEMPLATE(InvokeCallbackArgument,
                HAS_2_TEMPLATE_PARAMS(int, k, typename, T),
                AND_1_VALUE_PARAMS(p0)) {
  std::move(const_cast<T&>(std::get<k>(args))).Run(p0);
}

}  // namespace

class TestCampaignsManagerObserver : public CampaignsManager::Observer {
 public:
  // Spins a RunLoop until campaigns are loaded.
  void Wait() { run_loop_.Run(); }

  void OnCampaignsLoadCompleted() override {
    load_completed_ = true;
    run_loop_.Quit();
  }

  bool load_completed() { return load_completed_; }

 private:
  base::RunLoop run_loop_;
  bool load_completed_ = false;
};

class CampaignsManagerTest : public testing::Test {
 public:
  CampaignsManagerTest() = default;

  // testing::Test:
  void SetUp() override {
    testing::Test::SetUp();

    InitializePrefService();
    InitializeUserManager();

    campaigns_manager_ =
        std::make_unique<CampaignsManager>(&mock_client_, local_state_.get());
    campaigns_manager_->SetPrefs(pref_.get());
    campaigns_manager_->SetTrackerInitializedForTesting();
  }

  void TearDown() override {
    // Clean up user manager.
    fake_user_manager_->Shutdown();
    fake_user_manager_->Destroy();
    fake_user_manager_.reset();

    testing::Test::TearDown();
  }

 protected:
  void LoadComponentAndVerifyLoadComplete(std::string_view file_content,
                                          bool in_oobe = false) {
    TestCampaignsManagerObserver observer;
    campaigns_manager_->AddObserver(&observer);

    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    base::FilePath campaigns_file(
        temp_dir_.GetPath().Append(kCampaignsFileName));

    base::WriteFile(campaigns_file, file_content);

    EXPECT_CALL(mock_client_, LoadCampaignsComponent(_))
        .WillOnce(InvokeCallbackArgument<0, CampaignComponentLoadedCallback>(
            temp_dir_.GetPath()));

    base::test::TestFuture<void> load_completed_waiter;
    campaigns_manager_->LoadCampaigns(load_completed_waiter.GetCallback(),
                                      in_oobe);
    ASSERT_TRUE(load_completed_waiter.Wait());
    observer.Wait();

    ASSERT_TRUE(observer.load_completed());
  }

  void MockDemoMode(bool in_demo_mode,
                    bool cloud_gaming_device,
                    bool feature_aware_device,
                    const std::string_view& store_id,
                    const std::string_view& retailer_id,
                    const std::string_view& country) {
    MockDemoMode(in_demo_mode, cloud_gaming_device, feature_aware_device,
                 store_id, retailer_id, country, kDefaultVersion);
  }

  void MockDemoMode(bool in_demo_mode,
                    bool cloud_gaming_device,
                    bool feature_aware_device,
                    const std::string_view& store_id,
                    const std::string_view& retailer_id,
                    const std::string_view& country,
                    const base::Version& app_version) {
    EXPECT_CALL(mock_client_, IsDeviceInDemoMode)
        .WillRepeatedly(testing::Return(in_demo_mode));
    EXPECT_CALL(mock_client_, IsCloudGamingDevice)
        .WillRepeatedly(testing::Return(cloud_gaming_device));
    EXPECT_CALL(mock_client_, IsFeatureAwareDevice)
        .WillRepeatedly(testing::Return(feature_aware_device));
    local_state_->SetString(ash::prefs::kDemoModeStoreId, store_id);
    local_state_->SetString(ash::prefs::kDemoModeRetailerId, retailer_id);
    local_state_->SetString(ash::prefs::kDemoModeCountry, country);
    EXPECT_CALL(mock_client_, GetDemoModeAppVersion)
        .WillRepeatedly(testing::ReturnRef(app_version));
  }

  void MockLocales(const std::string& user_locale,
                   const std::string& application_locale,
                   const std::string& country) {
    EXPECT_CALL(mock_client_, GetUserLocale())
        .WillRepeatedly(testing::ReturnRefOfCopy(std::string(user_locale)));
    EXPECT_CALL(mock_client_, GetApplicationLocale())
        .WillRepeatedly(
            testing::ReturnRefOfCopy(std::string(application_locale)));
    EXPECT_CALL(mock_client_, GetCountryCode())
        .WillRepeatedly(testing::Return(std::string(country)));
  }

  void MockFeatueEngagementCheckOnCaps(bool reach_impression_cap,
                                       bool reach_dismissal_cap,
                                       bool reach_group_impression_cap,
                                       bool reach_group_dismissal_cap) {
    ON_CALL(mock_client_, WouldTriggerHelpUI)
        .WillByDefault([=](const std::map<std::string, std::string>& params) {
          auto event_to_be_checked = params.at("event_to_be_checked");
          if (event_to_be_checked ==
              "name:ChromeOSAshGrowthCampaigns_Campaign3_Impression;comparator:"
              "<6;window:3650;storage:3650") {
            return !reach_impression_cap;
          }

          if (event_to_be_checked ==
              "name:ChromeOSAshGrowthCampaigns_Campaign3_Dismissed;comparator:<"
              "3;window:3650;storage:3650") {
            return !reach_dismissal_cap;
          }
          if (event_to_be_checked ==
              "name:ChromeOSAshGrowthCampaigns_Group1_Impression;comparator:<3;"
              "window:3650;storage:3650") {
            return !reach_group_impression_cap;
          }

          if (event_to_be_checked ==
              "name:ChromeOSAshGrowthCampaigns_Group1_Dismissed;comparator:<2;"
              "window:3650;storage:3650") {
            return !reach_group_dismissal_cap;
          }

          return false;
        });
  }

  void InitilizeCampaignsExperimentTag(const base::Feature& feature,
                                       const std::string& exp_tag) {
    base::FieldTrialParams params;
    params[kCampaignsExperimentTag] = exp_tag;
    base::test::FeatureRefAndParams campaigns_experiment_tag(feature, params);

    scoped_feature_list_.InitWithFeaturesAndParameters(
        {campaigns_experiment_tag}, {});
  }

  void VerifyOwnerAccountValid(bool is_valid) {
    const AccountId& owner_account_id = fake_user_manager_->GetOwnerAccountId();
    ASSERT_EQ(is_valid, owner_account_id.is_valid());
  }

  void VerifyDemoModePayload(const Campaign* campaign) {
    const auto* payload = campaign->FindDictByDottedPath("payload.demoModeApp");
    ASSERT_EQ("/asset/peripherals_lang1.mp4",
              *payload->FindStringByDottedPath("attractionLoop.videoSrcLang1"));
    ASSERT_EQ("/asset/peripherals_lang2.mp4",
              *payload->FindStringByDottedPath("attractionLoop.videoSrcLang2"));
  }

  void LoadComponentWithBasicDeviceTargetings(
      const std::string& milestone_range,
      std::optional<bool> target_feature_aware_device = std::nullopt) {
    std::string feature_aware_targeting = "";
    if (target_feature_aware_device) {
      std::string isFeatureAwareDeviceStr =
          target_feature_aware_device.value() ? "true" : "false";
      feature_aware_targeting =
          base::StringPrintf(R"(,
        "isFeatureAwareDevice": %s
      )",
                             isFeatureAwareDeviceStr.c_str());
    }
    auto device_targeting = base::StringPrintf(R"(
            "device": {
              "locales": ["en-US"],
              "milestone": {
                %s
              }%s
            }
          )",
                                               milestone_range.c_str(),
                                               feature_aware_targeting.c_str());
    LoadComponentAndVerifyLoadComplete(base::StringPrintf(
        kValidCampaignsFileTemplate, device_targeting.c_str()));
  }

  void LoadComponentWithUserLocaleTargetings(const std::string& locales) {
    std::string feature_aware_targeting = "";
    auto device_targeting = base::StringPrintf(R"(
            "device": {
              "userLocales": %s
            }
          )",
                                               locales.c_str());
    LoadComponentAndVerifyLoadComplete(base::StringPrintf(
        kValidCampaignsFileTemplate, device_targeting.c_str()));
  }

  void LoadComponentWithCountryTargetings(const std::string& countries) {
    std::string feature_aware_targeting = "";
    auto device_targeting = base::StringPrintf(R"(
            "device": {
              %s
            }
          )",
                                               countries.c_str());
    LoadComponentAndVerifyLoadComplete(base::StringPrintf(
        kValidCampaignsFileTemplate, device_targeting.c_str()));
  }

  void LoadComponentWithRegisteredTimeTargeting(
      const std::string& registerd_time_targeting) {
    auto device_targeting =
        base::StringPrintf(R"(
            "device": {
              "registeredTime": %s
            }
          )",
                           registerd_time_targeting.c_str());
    LoadComponentAndVerifyLoadComplete(base::StringPrintf(
        kValidCampaignsFileTemplate, device_targeting.c_str()));
  }

  void LoadComponentWithDeviceTargeting(const std::string& device_targeting) {
    auto targeting = base::StringPrintf(R"(
            "device": %s
          )",
                                        device_targeting.c_str());
    LoadComponentAndVerifyLoadComplete(
        base::StringPrintf(kValidCampaignsFileTemplate, targeting.c_str()));
  }

  void LoadComponentWithSessionTargeting(
      const std::string& session_targeting_str) {
    auto session_targeting = base::StringPrintf(R"(
            "session": %s
          )",
                                                session_targeting_str.c_str());
    LoadComponentAndVerifyLoadComplete(base::StringPrintf(
        kValidCampaignsFileTemplate, session_targeting.c_str()));
  }

  void LoadComponentWithExperimentTagTargeting(
      const std::string& feature_index_targeting,
      const std::string& exp_tags) {
    auto session_targeting =
        base::StringPrintf(R"(
            "session": {
              %s,
              "experimentTags": %s
            }
          )",
                           feature_index_targeting.c_str(), exp_tags.c_str());
    LoadComponentAndVerifyLoadComplete(base::StringPrintf(
        kValidCampaignsFileTemplate, session_targeting.c_str()));
  }

  void LoadComponentWithScheduling(const std::string& schedulings) {
    auto runtime_targeting = base::StringPrintf(R"(
            "runtime": {
              "schedulings": %s
            }
          )",
                                                schedulings.c_str());
    LoadComponentAndVerifyLoadComplete(base::StringPrintf(
        kValidCampaignsFileTemplate, runtime_targeting.c_str()));
  }

  void LoadComponentWithTriggerTargeting(const std::string& triggers) {
    auto runtime_targeting = base::StringPrintf(R"(
            "runtime": {
              "triggerList": %s
            }
          )",
                                                triggers.c_str());
    LoadComponentAndVerifyLoadComplete(base::StringPrintf(
        kValidCampaignsFileTemplate, runtime_targeting.c_str()));
  }

  void LoadComponentWithAppsOpenedTargeting(const std::string& apps_opened) {
    auto runtime_targeting = base::StringPrintf(R"(
            "runtime": {
              "appsOpened": %s
            }
          )",
                                                apps_opened.c_str());
    LoadComponentAndVerifyLoadComplete(base::StringPrintf(
        kValidCampaignsFileTemplate, runtime_targeting.c_str()));
  }

  void LoadComponentWithRunTimeTargeting(const std::string& runtime_targeting,
                                         bool has_group_id = false) {
    auto targeting = base::StringPrintf(R"(
            "runtime": %s
          )",
                                        runtime_targeting.c_str());
    LoadComponentAndVerifyLoadComplete(
        base::StringPrintf(has_group_id ? kValidCampaignsFileWithGroupIdTemplate
                                        : kValidCampaignsFileTemplate,
                           targeting.c_str()));
  }

  void LoadComponentWithMultiTargetings(const std::string& targetings) {
    LoadComponentAndVerifyLoadComplete(base::StringPrintf(
        kValidCampaignsFileMultiTargetingsTemplate, targetings.c_str()));
  }

  void LoadComponentWithActiveUrlTargeting(const std::string& active_url) {
    auto session_targeting = base::StringPrintf(R"(
            "runtime": {
              "activeUrlRegexes": %s
            }
          )",
                                                active_url.c_str());
    LoadComponentAndVerifyLoadComplete(base::StringPrintf(
        kValidCampaignsFileTemplate, session_targeting.c_str()));
  }

  void LoadComponentWithUserPrefTargeting(const std::string& values) {
    auto pref_targeting = base::StringPrintf(R"(
            "runtime": {
              "userPrefs": [
                %s
              ]
            }
          )",
                                             values.c_str());
    LoadComponentAndVerifyLoadComplete(base::StringPrintf(
        kValidCampaignsFileTemplate, pref_targeting.c_str()));
  }

  base::Version GetNewVersion(const base::Version& version,
                              int minor_version_delta) {
    auto new_version = version.components();
    auto minor_version_component_index = new_version.size() - 2;
    new_version.at(minor_version_component_index) =
        new_version.at(minor_version_component_index) + minor_version_delta;
    return base::Version(new_version);
  }

  base::test::TaskEnvironment task_environment_;
  MockCampaignsManagerClient mock_client_;
  base::ScopedTempDir temp_dir_;
  std::unique_ptr<TestingPrefServiceSimple> local_state_;
  std::unique_ptr<TestingPrefServiceSimple> pref_;
  std::unique_ptr<CampaignsManager> campaigns_manager_;
  // A sub-class might override this from `InitializeScopedFeatureList`.
  base::test::ScopedFeatureList scoped_feature_list_;
  std::unique_ptr<user_manager::FakeUserManager> fake_user_manager_;

 private:
  void InitializePrefService() {
    local_state_ = std::make_unique<TestingPrefServiceSimple>();
    pref_ = std::make_unique<TestingPrefServiceSimple>();

    local_state_->registry()->RegisterStringPref(ash::prefs::kDemoModeCountry,
                                                 "US");
    local_state_->registry()->RegisterStringPref(
        ash::prefs::kDemoModeRetailerId, std::string());
    local_state_->registry()->RegisterStringPref(ash::prefs::kDemoModeStoreId,
                                                 std::string());
    pref_->registry()->RegisterListPref(
        kTestPref1, base::Value::List().Append("v0").Append("v1"));
    pref_->registry()->RegisterStringPref(kTestPref2, "v2");
    pref_->registry()->RegisterStringPref(kTestPref3, "v3");
  }

  void InitializeUserManager() {
    user_manager::UserManagerBase::RegisterPrefs(local_state_->registry());
    fake_user_manager_ =
        std::make_unique<user_manager::FakeUserManager>(local_state_.get());
    fake_user_manager_->Initialize();
  }
};

TEST_F(CampaignsManagerTest, LoadAndGetDemoModeCampaign) {
  base::HistogramTester histogram_tester;
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US");

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, kValidDemoModeTargeting));

  histogram_tester.ExpectTotalCount(
      kCampaignsComponentDownloadDurationSessionStartHistogram, 1);
  histogram_tester.ExpectTotalCount(kCampaignsComponentReadDurationHistogram,
                                    1);
  histogram_tester.ExpectTotalCount(kCampaignMatchDurationHistogram, 0);

  EXPECT_CALL(mock_client_,
              RegisterSyntheticFieldTrial("CrOSGrowthStudy1", "CampaignId3"));
  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));

  histogram_tester.ExpectBucketCount(kCampaignsManagerErrorHistogramName,
                                     CampaignsManagerError::kInvalidTargeting,
                                     /*count=*/1);

  histogram_tester.ExpectBucketCount(kCampaignsManagerErrorHistogramName,
                                     CampaignsManagerError::kInvalidCampaign,
                                     /*count=*/1);
  histogram_tester.ExpectTotalCount(
      kCampaignsComponentDownloadDurationSessionStartHistogram, 1);
  histogram_tester.ExpectTotalCount(kCampaignsComponentReadDurationHistogram,
                                    1);
  histogram_tester.ExpectTotalCount(kCampaignMatchDurationHistogram, 1);

  histogram_tester.ExpectUniqueSample(kGetCampaignBySlotHistogramName,
                                      Slot::kDemoModeApp,
                                      /*expected_bucket_count=*/1);
}

TEST_F(CampaignsManagerTest, LoadAndGetDemoModeCampaignInOobe) {
  base::HistogramTester histogram_tester;

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, kValidDemoModeTargeting),
      /*in_oobe=*/true);

  histogram_tester.ExpectTotalCount(
      kCampaignsComponentDownloadDurationSessionStartHistogram, 0);

  histogram_tester.ExpectTotalCount(
      kCampaignsComponentDownloadDurationOobeHistogram, 1);
}

TEST_F(CampaignsManagerTest, GetCampaignNoTargeting) {
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US");

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, ""));

  EXPECT_CALL(mock_client_,
              RegisterSyntheticFieldTrial("CrOSGrowthStudy1", "CampaignId3"));
  // Verify that the campaign is selected if there is no demo mode targeting.
  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignNoTargetingNotInDemoMode) {
  MockDemoMode(
      /*in_demo_mode=*/false,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US");

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, ""));

  EXPECT_CALL(mock_client_,
              RegisterSyntheticFieldTrial("CrOSGrowthStudy1", "CampaignId3"));
  // Verify that the campaign is selected if there is not in demo mode.
  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

// TODO(b/302360652): After user prefs targeting is implemented, add test to
// verify that campaign with user prefs related targeting is not selected when
// user prefs are not available.

TEST_F(CampaignsManagerTest, GetDemoModeCampaignNotInDemoMode) {
  base::HistogramTester histogram_tester;

  MockDemoMode(
      /*in_demo_mode=*/false,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US");

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, kValidDemoModeTargeting));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
  histogram_tester.ExpectUniqueSample(kGetCampaignBySlotHistogramName,
                                      Slot::kDemoModeApp,
                                      /*expected_bucket_count=*/0);
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignNotGamingDevice) {
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/false,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US");

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, kValidDemoModeTargeting));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignNotFeatureAwareDevice) {
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/false,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US");

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, kValidDemoModeTargeting));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignstoreIdMismatch) {
  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, kValidDemoModeTargeting));

  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"1",
      /*retailer_id=*/"bby",
      /*country=*/"US");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignRetailerIdMismatch) {
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"abc",
      /*country=*/"US");

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, kValidDemoModeTargeting));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignCanonicalizedRetailerId) {
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bestbuy",
      /*country=*/"US");

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate,
                         R"(
          "demoMode": {
            "retailers": ["best-buy", "best_buy"],
            "storeIds": ["2", "4", "6"],
            "countries": ["US"],
            "capability": {
              "isCloudGamingDevice": true,
              "isFeatureAwareDevice": true
            }
          }
      )"));

  // Verify that the campaign is selected if there is not in demo mode.
  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignCountryMismatch) {
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"UK");

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, kValidDemoModeTargeting));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignAppVersionTargeting) {
  const base::Version expected_app_version("1.0.0.0");
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US",
      /*app_version=*/expected_app_version);

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, R"(
    "demoMode": {
      "appVersion": {
        "min": "1.0.0.0",
        "max": "1.0.0.1"
      }
    }
)"));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignAppVersionMinMismatch) {
  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, R"(
    "demoMode": {
      "appVersion": {
        "min": "1.0.0.1",
        "max": "1.0.0.2"
      }
    }
  )"));

  const base::Version expected_app_version("1.0.0.0");
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US",
      /*app_version=*/expected_app_version);

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignAppVersionMaxMismatch) {
  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, R"(
    "demoMode": {
      "appVersion": {
        "min": "1.0.0.0",
        "max": "1.0.0.1"
      }
    }
  )"));

  const base::Version expected_app_version("1.0.0.2");
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US",
      /*app_version=*/expected_app_version);

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignAppVersionMinOnly) {
  const base::Version expected_app_version("1.0.0.3");

  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US",
      /*app_version=*/expected_app_version);

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, R"(
    "demoMode": {
      "appVersion": {
        "min": "1.0.0.0"
      }
    }
  )"));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignAppVersionMinOnlyMismstch) {
  const base::Version expected_app_version("1.0.0.2");
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US",
      /*app_version=*/expected_app_version);

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, R"(
    "demoMode": {
      "appVersion": {
        "min": "1.0.0.3",
      }
    }
  )"));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignAppVersionMaxOnly) {
  const base::Version expected_app_version("1.0.0.3");
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US",
      /*app_version=*/expected_app_version);

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, R"(
    "demoMode": {
      "appVersion": {
        "max": "1.0.0.3"
      }
    }
  )"));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignAppVersionMaxOnlyMismstch) {
  const base::Version expected_app_version("1.0.0.4");
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US",
      /*app_version=*/expected_app_version);

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, R"(
    "demoMode": {
      "appVersion": {
        "max": "1.0.0.3"
      }
    }
  )"));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetDemoModeCampaignAppVersionInvalidAppVersion) {
  const base::Version expected_app_version = base::Version();
  MockDemoMode(
      /*in_demo_mode=*/true,
      /*cloud_gaming_device=*/true,
      /*feature_aware_device=*/true,
      /*store_id=*/"2",
      /*retailer_id=*/"bby",
      /*country=*/"US",
      /*app_version=*/expected_app_version);

  LoadComponentAndVerifyLoadComplete(
      base::StringPrintf(kValidCampaignsFileTemplate, R"(
    "demoMode": {
      "appVersion": {
        "max": "1.0.0.3"
      }
    }
  )"));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, LoadCampaignsFailed) {
  base::HistogramTester histogram_tester;
  TestCampaignsManagerObserver observer;
  campaigns_manager_->AddObserver(&observer);

  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());

  EXPECT_CALL(mock_client_, LoadCampaignsComponent(_))
      .WillOnce(InvokeCallbackArgument<0, CampaignComponentLoadedCallback>(
          std::nullopt));
  EXPECT_FALSE(CampaignsLogger::Get()->HasLogForTesting());

  campaigns_manager_->LoadCampaigns(base::DoNothing());
  observer.Wait();
  histogram_tester.ExpectTotalCount(
      kCampaignsComponentDownloadDurationSessionStartHistogram, 1);
  histogram_tester.ExpectTotalCount(kCampaignsComponentReadDurationHistogram,
                                    0);

  ASSERT_TRUE(observer.load_completed());

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
  EXPECT_TRUE(CampaignsLogger::Get()->HasLogForTesting());

  histogram_tester.ExpectBucketCount(
      kCampaignsManagerErrorHistogramName,
      CampaignsManagerError::kCampaignsComponentLoadFail,
      /*count=*/1);
  histogram_tester.ExpectTotalCount(kCampaignMatchDurationHistogram, 1);
}

TEST_F(CampaignsManagerTest, LoadCampaignsNoFile) {
  base::HistogramTester histogram_tester;
  TestCampaignsManagerObserver observer;
  campaigns_manager_->AddObserver(&observer);

  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());

  EXPECT_CALL(mock_client_, LoadCampaignsComponent(_))
      .WillOnce(InvokeCallbackArgument<0, CampaignComponentLoadedCallback>(
          temp_dir_.GetPath()));

  campaigns_manager_->LoadCampaigns(base::DoNothing());
  observer.Wait();
  histogram_tester.ExpectTotalCount(
      kCampaignsComponentDownloadDurationSessionStartHistogram, 1);
  histogram_tester.ExpectTotalCount(kCampaignsComponentReadDurationHistogram,
                                    1);

  ASSERT_TRUE(observer.load_completed());

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));

  histogram_tester.ExpectBucketCount(
      kCampaignsManagerErrorHistogramName,
      CampaignsManagerError::kCampaignsFileLoadFail,
      /*count=*/1);
  histogram_tester.ExpectTotalCount(kCampaignMatchDurationHistogram, 1);
}

TEST_F(CampaignsManagerTest, LoadCampaignsInvalidFile) {
  base::HistogramTester histogram_tester;

  LoadComponentAndVerifyLoadComplete("abc");
  histogram_tester.ExpectTotalCount(
      kCampaignsComponentDownloadDurationSessionStartHistogram, 1);
  histogram_tester.ExpectTotalCount(kCampaignsComponentReadDurationHistogram,
                                    1);

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));

  histogram_tester.ExpectBucketCount(
      kCampaignsManagerErrorHistogramName,
      CampaignsManagerError::kCampaignsParsingFail,
      /*count=*/1);
  histogram_tester.ExpectTotalCount(kCampaignMatchDurationHistogram, 1);
}

TEST_F(CampaignsManagerTest, LoadCampaignsEmptyFile) {
  LoadComponentAndVerifyLoadComplete("");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignDeviceTargeting) {
  auto current_version = version_info::GetMajorVersionNumberAsInt();
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));
  LoadComponentWithBasicDeviceTargetings(base::StringPrintf(
      R"(
      "min": %d,
      "max": %d
    )",
      current_version, current_version + 1));
  MockLocales(/*user_locale=*/"en-US", /*application_locale=*/"en-US",
              /*country=*/"us");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignUserLocaleTargeting) {
  MockLocales(/*user_locale=*/"en-IN", /*application_locale=*/"en-GB",
              /*country=*/"in");
  LoadComponentWithUserLocaleTargetings(R"(["en-AU", "en-IN"])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignUserLocaleTargetingMismatch) {
  MockLocales(/*user_locale=*/"en-IN", /*application_locale=*/"en-GB",
              /*country=*/"in");
  LoadComponentWithUserLocaleTargetings(R"(["en-GB", "en-AU"])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignWithIncludedCountryTargeting) {
  MockLocales(/*user_locale=*/"en-IN", /*application_locale=*/"en-GB",
              /*country=*/"in");
  LoadComponentWithCountryTargetings(R"("includedCountries": ["us", "in"])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignIncludedCountryTargetingMismatch) {
  MockLocales(/*user_locale=*/"en-IN", /*application_locale=*/"en-GB",
              /*country=*/"in");
  LoadComponentWithCountryTargetings(R"("includedCountries": ["us", "ca"])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, CampaignWithExcludedCountryTargeting) {
  MockLocales(/*user_locale=*/"en-IN", /*application_locale=*/"en-GB",
              /*country=*/"in");
  LoadComponentWithCountryTargetings(R"("excludedCountries": ["us", "ca"])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignExcludedCountryTargetingMismatch) {
  MockLocales(/*user_locale=*/"en-IN", /*application_locale=*/"en-GB",
              /*country=*/"in");
  LoadComponentWithCountryTargetings(R"("excludedCountries": ["us", "in"])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignMilestoneMinMismatch) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));

  auto current_version = version_info::GetMajorVersionNumberAsInt();
  LoadComponentWithBasicDeviceTargetings(base::StringPrintf(
      R"(
      "min": %d,
      "max": %d
    )",
      current_version + 1, current_version + 1));
  MockLocales(/*user_locale=*/"en-US", /*application_locale=*/"en-US",
              /*country=*/"us");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignMilestoneMaxMismatch) {
  MockLocales(/*user_locale=*/"en-US", /*application_locale=*/"en-US",
              /*country=*/"us");

  auto current_version = version_info::GetMajorVersionNumberAsInt();
  LoadComponentWithBasicDeviceTargetings(base::StringPrintf(
      R"(
        "min": %d,
        "max": %d
      )",
      current_version - 2, current_version - 1));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignMinMilestoneOnly) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));

  auto current_version = version_info::GetMajorVersionNumberAsInt();
  MockLocales(/*user_locale=*/"en-US", /*application_locale=*/"en-US",
              /*country=*/"us");
  LoadComponentWithBasicDeviceTargetings(
      base::StringPrintf(R"("min": %d)", current_version));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignMinMilestoneOnlyMismatch) {
  MockLocales(/*user_locale=*/"en-US", /*application_locale=*/"en-US",
              /*country=*/"us");

  auto current_version = version_info::GetMajorVersionNumberAsInt();
  LoadComponentWithBasicDeviceTargetings(
      base::StringPrintf(R"("min": %d)", current_version + 1));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignMaxMilestoneOnly) {
  MockLocales(/*user_locale=*/"en-US", /*application_locale=*/"en-US",
              /*country=*/"us");

  auto current_version = version_info::GetMajorVersionNumberAsInt();
  LoadComponentWithBasicDeviceTargetings(
      base::StringPrintf(R"("max": %d)", current_version));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignMaxMilestoneOnlyMismatch) {
  MockLocales(/*user_locale=*/"en-US", /*application_locale=*/"en-US",
              /*country=*/"us");

  auto current_version = version_info::GetMajorVersionNumberAsInt();
  LoadComponentWithBasicDeviceTargetings(
      base::StringPrintf(R"("max": %d)", current_version - 1));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignVersionMatch) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));
  LoadComponentWithDeviceTargeting(base::StringPrintf(
      R"(
        {
          "version": {
            "min": "%s",
            "max": "%s"
          }
        }
      )",
      GetNewVersion(version_info::GetVersion(), -1).GetString().c_str(),
      GetNewVersion(version_info::GetVersion(), 1).GetString().c_str()));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignVersionMinMismatch) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));
  LoadComponentWithDeviceTargeting(base::StringPrintf(
      R"(
        {
          "version": {
            "min": "%s",
            "max": "%s"
          }
        }
      )",
      GetNewVersion(version_info::GetVersion(), 1).GetString().c_str(),
      GetNewVersion(version_info::GetVersion(), 2).GetString().c_str()));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignVersionMaxMismatch) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));
  LoadComponentWithDeviceTargeting(base::StringPrintf(
      R"(
        {
          "version": {
            "min": "%s",
            "max": "%s"
          }
        }
      )",
      GetNewVersion(version_info::GetVersion(), -2).GetString().c_str(),
      GetNewVersion(version_info::GetVersion(), -1).GetString().c_str()));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignVersionMinOnly) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));
  LoadComponentWithDeviceTargeting(base::StringPrintf(
      R"(
        {
          "version": {
            "min": "%s"
          }
        }
      )",
      GetNewVersion(version_info::GetVersion(), -1).GetString().c_str()));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignVersionMinOnlyMismatch) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));
  LoadComponentWithDeviceTargeting(base::StringPrintf(
      R"(
        {
          "version": {
            "min": "%s"
          }
        }
      )",
      GetNewVersion(version_info::GetVersion(), 1).GetString().c_str()));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignVersionMaxOnly) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));
  LoadComponentWithDeviceTargeting(base::StringPrintf(
      R"(
        {
          "version": {
            "max": "%s"
          }
        }
      )",
      GetNewVersion(version_info::GetVersion(), 1).GetString().c_str()));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignVersionMaxOnlyMismatch) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));
  LoadComponentWithDeviceTargeting(base::StringPrintf(
      R"(
        {
          "version": {
            "max": "%s"
          }
        }
      )",
      GetNewVersion(version_info::GetVersion(), -1).GetString().c_str()));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignApplicationLocaleMismatch) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-CA")));

  auto current_version = version_info::GetMajorVersionNumberAsInt();
  LoadComponentWithBasicDeviceTargetings(
      base::StringPrintf(R"("max": %d)", current_version));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTargetFeatureAwareDevice) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));

  scoped_feature_list_.InitWithFeatures(
      {ash::features::kFeatureManagementGrowthFramework}, {});

  auto current_version = version_info::GetMajorVersionNumberAsInt();
  LoadComponentWithBasicDeviceTargetings(
      base::StringPrintf(R"("max": %d)", current_version),
      /*target_feature_aware_device=*/true);
  MockLocales(/*user_locale=*/"en-US", /*application_locale=*/"en-US",
              /*country=*/"us");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTargetFeatureAwareDeviceMismatch) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));
  scoped_feature_list_.InitWithFeatures(
      {ash::features::kFeatureManagementGrowthFramework}, {});

  auto current_version = version_info::GetMajorVersionNumberAsInt();
  LoadComponentWithBasicDeviceTargetings(
      base::StringPrintf(R"("max": %d)", current_version),
      /*target_feature_aware_device=*/false);

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTargetNotFeatureAwareDevice) {
  EXPECT_CALL(mock_client_, GetApplicationLocale())
      .WillRepeatedly(testing::ReturnRefOfCopy(std::string("en-US")));
  scoped_feature_list_.InitWithFeatures(
      {}, {ash::features::kFeatureManagementGrowthFramework});

  auto current_version = version_info::GetMajorVersionNumberAsInt();
  LoadComponentWithBasicDeviceTargetings(
      base::StringPrintf(R"("max": %d)", current_version),
      /*target_feature_aware_device=*/false);

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTargetNotFeatureAwareDeviceMismatch) {
  MockLocales(/*user_locale=*/"en-US", /*application_locale=*/"en-US",
              /*country=*/"us");

  scoped_feature_list_.InitWithFeatures(
      {}, {ash::features::kFeatureManagementGrowthFramework});

  auto current_version = version_info::GetMajorVersionNumberAsInt();
  LoadComponentWithBasicDeviceTargetings(
      base::StringPrintf(R"("max": %d)", current_version),
      /*target_feature_aware_device=*/true);

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTargetDeviceAge) {
  campaigns_manager_->SetOobeCompleteTimeForTesting(base::Time::Now() -
                                                    base::Hours(26281));
  // 3 years to 4 years.
  LoadComponentWithDeviceTargeting(base::StringPrintf(R"({
        "deviceAgeInHours": {
          "start": 26280,
          "end": 35040
        }
      })"));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTargetDeviceAgeStartOnly) {
  campaigns_manager_->SetOobeCompleteTimeForTesting(base::Time::Now() -
                                                    base::Hours(26281));
  LoadComponentWithDeviceTargeting(base::StringPrintf(R"({
        "deviceAgeInHours": {
          "start": 26280
        }
      })"));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTargetDeviceAgeEndOnly) {
  campaigns_manager_->SetOobeCompleteTimeForTesting(base::Time::Now() -
                                                    base::Hours(35039));
  LoadComponentWithDeviceTargeting(base::StringPrintf(R"({
        "deviceAgeInHours": {
          "end": 35040
        }
      })"));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTargetDeviceAgeMismatch) {
  campaigns_manager_->SetOobeCompleteTimeForTesting(base::Time::Now() -
                                                    base::Hours(26279));
  LoadComponentWithDeviceTargeting(base::StringPrintf(R"({
        "deviceAgeInHours": {
          "start": 26280,
          "end": 35040
        }
      })"));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTargetDeviceAgeStartOnlyMismatch) {
  campaigns_manager_->SetOobeCompleteTimeForTesting(base::Time::Now() -
                                                    base::Hours(26279));
  LoadComponentWithDeviceTargeting(base::StringPrintf(R"({
        "deviceAgeInHours": {
          "start": 26280
        }
      })"));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTargetDeviceAgeEndOnlyMismatch) {
  campaigns_manager_->SetOobeCompleteTimeForTesting(base::Time::Now() -
                                                    base::Hours(35041));
  LoadComponentWithDeviceTargeting(base::StringPrintf(R"({
        "deviceAgeInHours": {
          "end": 35040
        }
      })"));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignExperimentTag) {
  InitilizeCampaignsExperimentTag(
      /*feature*/ ash::features::kGrowthCampaignsExperiment2, /*exp_tag=*/"1");

  LoadComponentWithExperimentTagTargeting(
      /*feature_index_targeting=*/R"("predefinedFeatureIndex": 1)",
      R"(["1", "2", "3"])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignExperimentTagOrRelationship) {
  InitilizeCampaignsExperimentTag(
      /*feature*/ ash::features::kGrowthCampaignsExperiment2,
      /*exp_tag=*/"2");

  LoadComponentWithExperimentTagTargeting(
      /*feature_index_targeting=*/R"("predefinedFeatureIndex": 1)",
      R"(["1", "2", "3"])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignExperimentTagMismatch) {
  InitilizeCampaignsExperimentTag(
      /*feature*/ ash::features::kGrowthCampaignsExperiment2,
      /*exp_tag=*/"4");

  LoadComponentWithExperimentTagTargeting(
      /*feature_index_targeting=*/R"("predefinedFeatureIndex": 1)",
      R"(["1", "2", "3"])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest,
       GetCampaignExperimentTagMismatchedFeatureFlagIndex) {
  InitilizeCampaignsExperimentTag(
      /*feature*/ ash::features::kGrowthCampaignsExperiment1,
      /*exp_tag=*/"3");

  LoadComponentWithExperimentTagTargeting(
      /*feature_index_targeting=*/R"("predefinedFeatureIndex": 1)",
      R"(["1", "2", "3"])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignExperimentTagInvalidFeatureFlagIndex) {
  InitilizeCampaignsExperimentTag(
      /*feature*/ ash::features::kGrowthCampaignsExperiment1,
      /*exp_tag=*/"3");

  LoadComponentWithExperimentTagTargeting(
      /*feature_index_targeting=*/R"("predefinedFeatureIndex": 100)",
      R"(["1", "2", "3"])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignExperimentTagWithOneOffFeature) {
  InitilizeCampaignsExperimentTag(
      /*feature*/ ash::features::kGrowthCampaignsExperimentFileAppGamgee,
      /*exp_tag=*/"1");

  LoadComponentWithExperimentTagTargeting(
      /*feature_index_targeting=*/R"("oneOffExpFeatureIndex": 1)",
      R"(["1", "2", "3"])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest,
       GetCampaignExperimentTagMismatchedOneOffFeatureFlagIndex) {
  InitilizeCampaignsExperimentTag(
      /*feature*/ ash::features::kGrowthCampaignsExperimentFileAppGamgee,
      /*exp_tag=*/"3");

  LoadComponentWithExperimentTagTargeting(
      /*feature_index_targeting=*/R"("oneOffExpFeatureIndex": 0)",
      R"(["1", "2", "3"])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest,
       GetCampaignExperimentTagInvalidOneOffFeatureFlagIndex) {
  InitilizeCampaignsExperimentTag(
      /*feature*/ ash::features::kGrowthCampaignsExperimentFileAppGamgee,
      /*exp_tag=*/"3");

  LoadComponentWithExperimentTagTargeting(
      /*feature_index_targeting=*/R"("oneOffExpFeatureIndex": 100)",
      R"(["1", "2", "3"])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignForOwner) {
  LoadComponentWithSessionTargeting(R"({
    "isOwner": true
  })");

  campaigns_manager_->SetIsUserOwner(true);

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignForOwnerMismatch) {
  LoadComponentWithSessionTargeting(R"({
    "isOwner": true
  })");

  campaigns_manager_->SetIsUserOwner(false);

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignForNonOwner) {
  LoadComponentWithSessionTargeting(R"({
    "isOwner": false
  })");

  campaigns_manager_->SetIsUserOwner(false);

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignForNonOwnerMismatch) {
  LoadComponentWithSessionTargeting(R"({
    "isOwner": false
  })");

  campaigns_manager_->SetIsUserOwner(true);

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetSchedulingCampaign) {
  const auto now = base::Time::Now();
  auto start = now;
  auto end = now + base::Seconds(5);
  LoadComponentWithScheduling(base::StringPrintf(
      R"([{"start": %f, "end": %f}])", start.InSecondsFSinceUnixEpoch(),
      end.InSecondsFSinceUnixEpoch()));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetSchedulingCampaignMultipleSchedulings) {
  const auto now = base::Time::Now();
  // First scheduling start and end before now.
  auto start = now - base::Seconds(10);
  auto end = now - base::Seconds(5);

  // Second scheduling start after now.
  auto start2 = now + base::Seconds(10);
  auto end2 = now + base::Seconds(20);

  // Third scheduling start now and end 10 secs from now.
  auto start3 = now;
  auto end3 = now + base::Seconds(10);
  LoadComponentWithScheduling(base::StringPrintf(
      R"([
          {"start": %f, "end": %f},
          {"start": %f, "end": %f},
          {"start": %f, "end": %f}
        ])",
      start.InSecondsFSinceUnixEpoch(), end.InSecondsFSinceUnixEpoch(),
      start2.InSecondsFSinceUnixEpoch(), end2.InSecondsFSinceUnixEpoch(),
      start3.InSecondsFSinceUnixEpoch(), end3.InSecondsFSinceUnixEpoch()));

  // Verify that there is a match.
  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetSchedulingCampaignMismatch) {
  const auto now = base::Time::Now();
  auto start = now + base::Seconds(5);
  auto end = now + base::Seconds(10);
  LoadComponentWithScheduling(base::StringPrintf(
      R"([{"start": %f, "end": %f}])", start.InSecondsFSinceUnixEpoch(),
      end.InSecondsFSinceUnixEpoch()));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetSchedulingCampaignMismatchWithSwitch) {
  const auto now = base::Time::Now();
  auto start = now + base::Seconds(5);
  auto end = now + base::Seconds(10);
  auto fake_now = now + base::Seconds(8);

  base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
  command_line.AppendSwitchASCII(
      ash::switches::kGrowthCampaignsCurrentTimeSecondsSinceUnixEpoch,
      base::NumberToString(fake_now.InSecondsFSinceUnixEpoch()));
  LoadComponentWithScheduling(base::StringPrintf(
      R"([{"start": %f, "end": %f}])", start.InSecondsFSinceUnixEpoch(),
      end.InSecondsFSinceUnixEpoch()));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetSchedulingCampaignStartOnly) {
  const auto now = base::Time::Now();
  LoadComponentWithScheduling(
      base::StringPrintf(R"([{"start": %f}])", now.InSecondsFSinceUnixEpoch()));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetSchedulingCampaignStartOnlyMismatch) {
  const auto now = base::Time::Now();
  auto start = now + base::Seconds(5);
  LoadComponentWithScheduling(base::StringPrintf(
      R"([{"start": %f}])", start.InSecondsFSinceUnixEpoch()));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetSchedulingCampaignEndOnly) {
  const auto now = base::Time::Now();
  auto end = now + base::Seconds(5);
  LoadComponentWithScheduling(
      base::StringPrintf(R"([{"end": %f}])", end.InSecondsFSinceUnixEpoch()));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetSchedulingCampaignEndOnlyMismatch) {
  const auto now = base::Time::Now();
  auto end = now - base::Seconds(10);
  LoadComponentWithScheduling(
      base::StringPrintf(R"([{"end": %f}])", end.InSecondsFSinceUnixEpoch()));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetSchedulingCampaignInvalidTargeting) {
  base::HistogramTester histogram_tester;

  LoadComponentWithScheduling("1");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));

  histogram_tester.ExpectBucketCount(kCampaignsManagerErrorHistogramName,
                                     CampaignsManagerError::kInvalidCampaign,
                                     /*count=*/1);

  histogram_tester.ExpectBucketCount(kCampaignsManagerErrorHistogramName,
                                     CampaignsManagerError::kInvalidTargeting,
                                     /*count=*/1);
}

TEST_F(CampaignsManagerTest, GetSchedulingCampaignInvalidScheduling) {
  base::HistogramTester histogram_tester;

  LoadComponentWithScheduling(R"([
    "test1",
    "test2"
  ])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));

  // Verify that two of the scheduling is invalids.
  histogram_tester.ExpectBucketCount(kCampaignsManagerErrorHistogramName,
                                     CampaignsManagerError::kInvalidScheduling,
                                     /*count=*/2);

  // There is a invalid campaign in the list of campaigns.
  histogram_tester.ExpectBucketCount(kCampaignsManagerErrorHistogramName,
                                     CampaignsManagerError::kInvalidCampaign,
                                     /*count=*/1);

  // There is a campaign with invalid targeting in the list of campaigns.
  histogram_tester.ExpectBucketCount(kCampaignsManagerErrorHistogramName,
                                     CampaignsManagerError::kInvalidTargeting,
                                     /*count=*/1);
}

TEST_F(CampaignsManagerTest, GetCampaignWithRegisteredTimeTargeting) {
  const auto now = base::Time::Now();
  auto start = now;
  auto end = now + base::Seconds(5);
  campaigns_manager_->SetOobeCompleteTimeForTesting(now);
  LoadComponentWithRegisteredTimeTargeting(base::StringPrintf(
      R"({"start": %f, "end": %f})", start.InSecondsFSinceUnixEpoch(),
      end.InSecondsFSinceUnixEpoch()));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignWithRegisteredTimeTargetingStartOnly) {
  const auto now = base::Time::Now();
  auto start = now;
  campaigns_manager_->SetOobeCompleteTimeForTesting(now);
  LoadComponentWithRegisteredTimeTargeting(
      base::StringPrintf(R"({"start": %f})", start.InSecondsFSinceUnixEpoch()));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignWithRegisteredTimeTargetingEndOnly) {
  const auto now = base::Time::Now();
  auto end = now + base::Seconds(5);
  campaigns_manager_->SetOobeCompleteTimeForTesting(now);
  LoadComponentWithRegisteredTimeTargeting(
      base::StringPrintf(R"({"end": %f})", end.InSecondsFSinceUnixEpoch()));

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest,
       GetCampaignWithRegisteredTimeTargetingStartMismatch) {
  const auto now = base::Time::Now();
  auto start = now + base::Seconds(5);
  auto end = now + base::Seconds(10);
  campaigns_manager_->SetOobeCompleteTimeForTesting(now);
  LoadComponentWithRegisteredTimeTargeting(base::StringPrintf(
      R"({"start": %f, "end": %f})", start.InSecondsFSinceUnixEpoch(),
      end.InSecondsFSinceUnixEpoch()));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest,
       GetCampaignWithRegisteredTimeTargetingEndMismatch) {
  const auto now = base::Time::Now();
  auto start = now - base::Seconds(2);
  auto end = now - base::Seconds(1);
  campaigns_manager_->SetOobeCompleteTimeForTesting(now);
  LoadComponentWithRegisteredTimeTargeting(base::StringPrintf(
      R"({"start": %f, "end": %f})", start.InSecondsFSinceUnixEpoch(),
      end.InSecondsFSinceUnixEpoch()));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest,
       GetCampaignWithRegisteredTimeTargetingStartOnlyMismatch) {
  const auto now = base::Time::Now();
  auto start = now + base::Seconds(5);
  campaigns_manager_->SetOobeCompleteTimeForTesting(now);
  LoadComponentWithRegisteredTimeTargeting(
      base::StringPrintf(R"({"start": %f})", start.InSecondsFSinceUnixEpoch()));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest,
       GetCampaignWithRegisteredTimeTargetingEndOnlyMismatch) {
  const auto now = base::Time::Now();
  auto end = now - base::Seconds(5);
  campaigns_manager_->SetOobeCompleteTimeForTesting(now);
  LoadComponentWithRegisteredTimeTargeting(
      base::StringPrintf(R"({"end": %f})", end.InSecondsFSinceUnixEpoch()));

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignWithRegisteredTimeNoOwner) {
  const auto now = base::Time::Now();
  auto start = now - base::Seconds(2);
  VerifyOwnerAccountValid(false);

  LoadComponentWithRegisteredTimeTargeting(
      base::StringPrintf(R"({"start": %f})", start.InSecondsFSinceUnixEpoch()));
  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignActiveUrl) {
  campaigns_manager_->SetActiveUrl(GURL("https://www.google.com/?foo=bar"));

  LoadComponentWithActiveUrlTargeting(
      R"([
        "https://www\\.google\\.com/\\?foo=bar",
        "https://gmail\\.google\\.com/\\?foo=bar",
        "https://www\\.google\\.com/\\?foo=bar2"
    ])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignActiveUrlOrRelationship) {
  campaigns_manager_->SetActiveUrl(GURL("https://www.google.com/?foo=bar"));

  LoadComponentWithActiveUrlTargeting(
      R"([
        "https://gmail\\.google\\.com/\\?foo=bar",
        "https://www\\.google\\.com/\\?foo=bar",
        "https://www\\.google\\.com/\\?foo=bar2",
        "https://www\\.google\\.com/foo=bar"
    ])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignActiveUrlMismatch) {
  campaigns_manager_->SetActiveUrl(GURL("https://www.google.com/?foo=bar"));

  LoadComponentWithActiveUrlTargeting(
      R"([
        "1https://gmail\\.google\\.com/\\?foo=bar",
        "http://www\\.google\\.com/\\?foo=bar",
        "https://www\\.google\\.com/\\?foo=bar2"
    ])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignActiveUrlEmptyActiveUrl) {
  campaigns_manager_->SetActiveUrl(GURL::EmptyGURL());

  LoadComponentWithActiveUrlTargeting(
      R"([
        "1https://gmail\\.google\\.com/\\?foo=bar",
        "http://www\\.google\\.com/\\?foo=bar",
        "https://www\\.google\\.com/\\?foo=bar2"
    ])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignActiveUrlNoActiveUrl) {
  LoadComponentWithActiveUrlTargeting(
      R"([
        "1https://gmail\\.google\\.com/\\?foo=bar",
        "http://www\\.google\\.com/\\?foo=bar",
        "https://www\\.google\\.com/\\?foo=bar2"
    ])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTriggersWithAppOpened) {
  growth::Trigger trigger(growth::TriggerType::kAppOpened);
  campaigns_manager_->SetTrigger(std::move(trigger));

  LoadComponentWithTriggerTargeting(
      R"([{"triggerType": 0, "triggerEvents": []}])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTriggersOrRelationship) {
  growth::Trigger trigger(growth::TriggerType::kAppOpened);
  campaigns_manager_->SetTrigger(std::move(trigger));

  LoadComponentWithTriggerTargeting(R"([
  {"triggerType": 0, "triggerEvents": []},
  {"triggerType": 1, "triggerEvents": []}
  ])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTriggersWithEvent) {
  growth::Trigger trigger(growth::TriggerType::kEvent);
  trigger.event = "event_1";
  campaigns_manager_->SetTrigger(std::move(trigger));

  LoadComponentWithTriggerTargeting(R"([
    {"triggerType": 2, "triggerEvents": ["event_0", "event_1"]}
  ])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTriggersWithDelayedOneShotTimer) {
  growth::Trigger trigger(growth::TriggerType::kDelayedOneShotTimer);
  campaigns_manager_->SetTrigger(std::move(trigger));

  LoadComponentWithTriggerTargeting(R"([
    {"triggerType": 3, "triggerEvents": []}
  ])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTriggersMissmatch) {
  growth::Trigger trigger(growth::TriggerType::kAppOpened);
  campaigns_manager_->SetTrigger(std::move(trigger));

  LoadComponentWithTriggerTargeting(
      R"([{"triggerType": 1, "triggerEvents": []}])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignTriggersNoTrigger) {
  LoadComponentWithTriggerTargeting(R"([
  {"triggerType": 0, "triggerEvents": []},
  {"triggerType": 1, "triggerEvents": []}
  ])");
  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignAppsOpened) {
  campaigns_manager_->SetOpenedApp("app_id_1");

  LoadComponentWithAppsOpenedTargeting(
      R"([
      {"appId": "app_id_1"},
      {"appId": "app_id_10"},
      {"appId": "app_id_15"}
    ])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignAppsOpenedOrRelationship) {
  campaigns_manager_->SetOpenedApp("app_id_10");

  LoadComponentWithAppsOpenedTargeting(
      R"([
      {"appId": "app_id_1"},
      {"appId": "app_id_10"},
      {"appId": "app_id_15"}
    ])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignAppOpenedMismatch) {
  campaigns_manager_->SetOpenedApp("app_id_2");

  LoadComponentWithAppsOpenedTargeting(
      R"([
      {"appId": "app_id_1"},
      {"appId": "app_id_10"},
      {"appId": "app_id_15"}
    ])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignAppOpenedNoOpenedApp) {
  LoadComponentWithAppsOpenedTargeting(
      R"([
      {"appId": "app_id_1"},
      {"appId": "app_id_10"},
      {"appId": "app_id_15"}
    ])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignMatchFirstTargeting) {
  campaigns_manager_->SetOpenedApp("app_id_1");

  LoadComponentWithMultiTargetings(kValidMultiTargetings);
  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignMatchSecondTargeting) {
  campaigns_manager_->SetOpenedApp("app_id_2");

  LoadComponentWithMultiTargetings(kValidMultiTargetings);
  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignMatchMultiTargetingsMismatch) {
  campaigns_manager_->SetOpenedApp("app_id_20");

  LoadComponentWithMultiTargetings(kValidMultiTargetings);
  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignWithInvalidPrefTargeting) {
  LoadComponentWithUserPrefTargeting(R"(
    [
      {
        "name": "pref1",
        "value": "v0"
      }
    ])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignWithPrefTargetingMismatch) {
  LoadComponentWithUserPrefTargeting(R"(
    [
      {
        "name": "pref1",
        "value": ["v1"]
      }
    ],
    [
      {
        "name": "pref2",
        "value": ["v"]
      }
    ])");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignWithPrefTargetingMatch) {
  // This 2nd set of considtion match pref1 = value_0 and pref2 = value_2.
  LoadComponentWithUserPrefTargeting(R"(
    [
      {
        "name": "pref1",
        "value": ["v", "v1"]
      },
      {
        "name": "pref2",
        "value": ["v2"]
      }
    ],
    [
      {
        "name": "pref3",
        "value": ["v3"]
      }
    ])");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, CampaignsFilteringTest) {
  MockLocales(/*user_locale=*/"en-US", /*application_locale=*/"en-US",
              /*country=*/"us");

  LoadComponentAndVerifyLoadComplete(
      R"({
          "0": [
            {
              "id": 3,
              "targetings": [
                {
                  "device": {
                    "locales": ["en-GB"]
                  }
                }
              ],
              "payload": {}
            },
            {
              "id": 3,
              "targetings": [
                {
                  "device": {
                    "locales": ["en-AU"]
                  }
                }
              ],
              "payload": {}
            },
            {
              "id": 3,
              "targetings": [
                {
                  "device": {
                    "locales": ["en-US"]
                  }
                }
              ],
              "payload": {}
            }
          ],
          "3": [
            {
              "id": 4,
              "targetings": [
                {
                  "device": {
                    "locales": ["en-GB"]
                  }
                }
              ],
              "payload": {}
            },
            {
              "id": 4,
              "targetings": [
                {
                  "device": {
                    "locales": ["en-AU"]
                  }
                }
              ],
              "payload": {}
            },
            {
              "id": 4,
              "targetings": [
                {
                  "device": {
                    "locales": ["en-US"]
                  }
                }
              ],
              "payload": {}
            },
            {
              "id": 5,
              "targetings": [
                {
                  "device": {
                    "locales": ["en-US"]
                  },
                  "runtime": {
                    "appsOpened": [
                      {
                        "appId": "foo"
                      }
                    ]
                  }
                }
              ],
              "payload": {}
            }
          ]
        }
      )",
      /*in_oobe=*/false);

  // Verify that prematch is ran to filter campaigns at campaign load time.
  ASSERT_EQ(1u,
            campaigns_manager_->GetCampaignsBySlotForTesting(Slot::kDemoModeApp)
                ->size());

  // Verify that runtime targeting is not used for prematch. The campaign with
  // runtime targeting is not filtered.
  ASSERT_EQ(
      2u, campaigns_manager_->GetCampaignsBySlotForTesting(Slot::kNotification)
              ->size());
}

TEST_F(CampaignsManagerTest, RegisterSyntheticFieldTrialWithTriggerEventName) {
  constexpr char kGmailAppIdWeb[] = "fmgjjmmmlfnkbppncabfkddbjimcfncm";
  constexpr char kCampaignEventName[] = "GmailOpened";

  growth::Trigger trigger(growth::TriggerType::kEvent);
  trigger.event = kCampaignEventName;
  campaigns_manager_->SetTrigger(std::move(trigger));
  campaigns_manager_->SetOpenedApp(kGmailAppIdWeb);

  LoadComponentAndVerifyLoadComplete(base::StringPrintf(
      kValidCampaignsFileRegisterTrialWithTriggerEventNameTemplate,
      R"("registerTrialWithTriggerEventName":true)",
      R"([
            {
              "triggerType": 2,
              "triggerEvents": [
                "event_0",
                "GmailOpened"
              ]
            }
          ])"));

  EXPECT_CALL(mock_client_,
              RegisterSyntheticFieldTrial("CrOSGrowthStudy1", "CampaignId3"))
      .Times(1);
  EXPECT_CALL(
      mock_client_,
      RegisterSyntheticFieldTrial(
          "CrOSGrowthStudy1", "CampaignId3" + std::string(kCampaignEventName)))
      .Times(1);

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest,
       NotRegisterSyntheticFieldTrialWithTriggerEventNameIfNotToRegister) {
  constexpr char kGmailAppIdWeb[] = "fmgjjmmmlfnkbppncabfkddbjimcfncm";
  constexpr char kCampaignEventName[] = "GmailOpened";

  growth::Trigger trigger(growth::TriggerType::kEvent);
  trigger.event = kCampaignEventName;
  campaigns_manager_->SetTrigger(std::move(trigger));
  campaigns_manager_->SetOpenedApp(kGmailAppIdWeb);

  LoadComponentAndVerifyLoadComplete(base::StringPrintf(
      kValidCampaignsFileRegisterTrialWithTriggerEventNameTemplate,
      R"("registerTrialWithTriggerEventName":false)",
      R"([
            {
              "triggerType": 2,
              "triggerEvents": [
                "event_0",
                "GmailOpened"
              ]
            }
          ])"));

  EXPECT_CALL(mock_client_,
              RegisterSyntheticFieldTrial("CrOSGrowthStudy1", "CampaignId3"))
      .Times(1);
  EXPECT_CALL(
      mock_client_,
      RegisterSyntheticFieldTrial(
          "CrOSGrowthStudy1", "CampaignId3" + std::string(kCampaignEventName)))
      .Times(0);

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest,
       NotRegisterSyntheticFieldTrialIfNotTriggeredByEvent) {
  growth::Trigger trigger(growth::TriggerType::kAppOpened);
  campaigns_manager_->SetTrigger(std::move(trigger));

  // `app_id_1` does not have grouped app id.
  campaigns_manager_->SetOpenedApp("app_id_1");

  LoadComponentAndVerifyLoadComplete(base::StringPrintf(
      kValidCampaignsFileRegisterTrialWithTriggerEventNameTemplate,
      R"("registerTrialWithTriggerEventName":true)",
      R"([
            {"triggerType": 0, "triggerEvents": []}
          ])"));

  EXPECT_CALL(mock_client_,
              RegisterSyntheticFieldTrial("CrOSGrowthStudy1", "CampaignId3"))
      .Times(1);
  EXPECT_CALL(mock_client_, RegisterSyntheticFieldTrial("CrOSGrowthStudy1",
                                                        "CampaignId3app_id_1"))
      .Times(0);

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignUnderCap) {
  MockFeatueEngagementCheckOnCaps(
      /*reach_impression_cap=*/false,
      /*reach_dismissal_cap=*/false,
      // For campaigns that don't specify group impression cap and dismissal.
      // These params are no-ops.
      /*reach_group_impression_cap=*/true,
      /*reach_group_dismissal_cap=*/true);

  LoadComponentWithRunTimeTargeting(
      R"({
        "events": {
          "impressionCap": 6,
          "dismissalCap": 3
        }
      })");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignUnderCapNoGroupId) {
  MockFeatueEngagementCheckOnCaps(
      /*reach_impression_cap=*/false,
      /*reach_dismissal_cap=*/false,
      // For campaigns that don't have group ID specified. Group impression cap
      // and dismissal cap are no-op.
      /*reach_group_impression_cap=*/true,
      /*reach_group_dismissal_cap=*/true);

  LoadComponentWithRunTimeTargeting(
      R"({
        "events": {
          "impressionCap": 6,
          "dismissalCap": 3,
          "groupImpressionCap": 3,
          "groupDismissalCap": 2
        }
      })");

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignReachImpressionCap) {
  MockFeatueEngagementCheckOnCaps(
      /*reach_impression_cap=*/true,
      /*reach_dismissal_cap=*/false,
      // For campaigns that don't specify group impression cap and dismissal.
      // These params are no-ops.
      /*reach_group_impression_cap=*/true,
      /*reach_group_dismissal_cap=*/true);

  LoadComponentWithRunTimeTargeting(
      R"({
        "events": {
          "impressionCap": 6,
          "dismissalCap": 3
        }
      })");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignReachDismissalCap) {
  MockFeatueEngagementCheckOnCaps(
      /*reach_impression_cap=*/false,
      /*reach_dismissal_cap=*/true,
      // For campaigns that don't specify group impression cap and dismissal.
      // These params are no-ops.
      /*reach_group_impression_cap=*/true,
      /*reach_group_dismissal_cap=*/true);

  LoadComponentWithRunTimeTargeting(
      R"({
        "events": {
          "impressionCap": 6,
          "dismissalCap": 3
        }
      })");

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignUnderGroupImpressionCap) {
  MockFeatueEngagementCheckOnCaps(
      /*reach_impression_cap=*/false,
      /*reach_dismissal_cap=*/false,
      /*reach_group_impression_cap=*/false,
      /*reach_group_dismissal_cap=*/false);

  LoadComponentWithRunTimeTargeting(
      R"({
        "events": {
          "impressionCap": 6,
          "dismissalCap": 3,
          "groupImpressionCap": 3,
          "groupDismissalCap": 2
        }
      })",
      /*has_group_id=*/true);

  VerifyDemoModePayload(
      campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignReachGroupImpressionCap) {
  MockFeatueEngagementCheckOnCaps(
      /*reach_impression_cap=*/false,
      /*reach_dismissal_cap=*/false,
      /*reach_group_impression_cap=*/true,
      /*reach_group_dismissal_cap=*/false);

  LoadComponentWithRunTimeTargeting(
      R"({
        "events": {
          "impressionCap": 6,
          "dismissalCap": 3,
          "groupImpressionCap": 3,
          "groupDismissalCap": 2
        }
      })",
      /*has_group_id=*/true);

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetCampaignReachGroupDismissalCap) {
  MockFeatueEngagementCheckOnCaps(
      /*reach_impression_cap=*/false,
      /*reach_dismissal_cap=*/false,
      /*reach_group_impression_cap=*/false,
      /*reach_group_dismissal_cap=*/true);

  LoadComponentWithRunTimeTargeting(
      R"({
        "events": {
          "impressionCap": 6,
          "dismissalCap": 3,
          "groupImpressionCap": 3,
          "groupDismissalCap": 2
        }
      })",
      /*has_group_id=*/true);

  ASSERT_EQ(nullptr, campaigns_manager_->GetCampaignBySlot(Slot::kDemoModeApp));
}

TEST_F(CampaignsManagerTest, GetTestingRegisteredTimeWithSwitch) {
  // Timestamp of "2024-08-01".
  const std::string seconds_since_epoch = "1722495600";
  const double seconds_since_epoch_double = 1722495600;
  base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
  command_line.AppendSwitchASCII(
      ash::switches::kGrowthCampaignsRegisteredTimeSecondsSinceUnixEpoch,
      seconds_since_epoch);

  auto registered_time = campaigns_manager_->GetRegisteredTimeForTesting();
  EXPECT_TRUE(registered_time);

  const auto expected_time =
      base::Time::FromSecondsSinceUnixEpoch(seconds_since_epoch_double);
  EXPECT_EQ(expected_time, registered_time);
}

TEST_F(CampaignsManagerTest, GetTestingRegisteredTimeWithoutSwitch) {
  auto registered_time = campaigns_manager_->GetRegisteredTimeForTesting();
  EXPECT_FALSE(registered_time);
}

}  // namespace growth