blob: 70650634505957334845d34e35c43a04e3122d04 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
#include <optional>
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/user_metrics.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "base/version.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
#include "chrome/browser/metrics/variations/google_groups_manager_factory.h"
#include "chrome/browser/policy/policy_test_utils.h"
#include "chrome/browser/prefs/incognito_mode_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/hats/hats_service_desktop.h"
#include "chrome/browser/ui/hats/hats_service_factory.h"
#include "chrome/browser/ui/hats/survey_config.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/chrome_test_utils.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/metrics_services_manager/metrics_services_manager.h"
#include "components/plus_addresses/core/browser/plus_address_hats_utils.h"
#include "components/plus_addresses/core/common/features.h"
#include "components/policy/core/common/policy_pref_names.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_service.h"
#include "components/variations/service/google_groups_manager.h"
#include "components/variations/service/google_groups_manager_prefs.h"
#include "components/variations/variations_seed_processor.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/isolated_world_ids.h"
#include "content/public/test/browser_test.h"
#include "net/dns/mock_host_resolver.h"
namespace {
constexpr char kRelevantGroupId[] = "1234";
constexpr base::TimeDelta kCooldownOverride = base::Days(14);
base::test::FeatureRefAndParams probability_zero{
features::kHappinessTrackingSurveysForDesktopSettings,
{{"probability", "0.000"}}};
base::test::FeatureRefAndParams probability_one{
features::kHappinessTrackingSurveysForDesktopSettings,
{{"probability", "1.000"},
{"survey", kHatsSurveyTriggerSettings},
{"en_site_id", "test_site_id"}}};
base::test::FeatureRefAndParams cool_down_period_overriden{
autofill::features::kPlusAddressAcceptedFirstTimeCreateSurvey,
{{"probability", "1.000"},
{"survey", kHatsSurveyTriggerPlusAddressAcceptedFirstTimeCreate},
{"cooldown-override-days", /*days=*/"14"}}};
base::test::FeatureRefAndParams cool_down_period_overriden_and_group_controlled{
autofill::features::kPlusAddressAcceptedFirstTimeCreateSurvey,
{{variations::internal::kGoogleGroupFeatureParamName, kRelevantGroupId},
{"probability", "1.000"},
{"survey", kHatsSurveyTriggerPlusAddressAcceptedFirstTimeCreate},
{"cooldown-override-days", /*days=*/"14"}}};
class ScopedSetMetricsConsent {
public:
// Enables or disables metrics consent based off of |consent|.
explicit ScopedSetMetricsConsent(bool consent) : consent_(consent) {
ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
&consent_);
}
ScopedSetMetricsConsent(const ScopedSetMetricsConsent&) = delete;
ScopedSetMetricsConsent& operator=(const ScopedSetMetricsConsent&) = delete;
~ScopedSetMetricsConsent() {
ChromeMetricsServiceAccessor::SetMetricsAndCrashReportingForTesting(
nullptr);
}
private:
const bool consent_;
};
class HatsServiceBrowserTestBase : public policy::PolicyTest {
public:
HatsServiceBrowserTestBase(const HatsServiceBrowserTestBase&) = delete;
HatsServiceBrowserTestBase& operator=(const HatsServiceBrowserTestBase&) =
delete;
protected:
explicit HatsServiceBrowserTestBase(
std::vector<base::test::FeatureRefAndParams> enabled_features)
: enabled_features_(enabled_features) {
scoped_feature_list_.InitWithFeaturesAndParameters(enabled_features_, {});
}
HatsServiceBrowserTestBase() = default;
~HatsServiceBrowserTestBase() override = default;
Profile* profile() { return chrome_test_utils::GetProfile(this); }
HatsServiceDesktop* GetHatsService(Browser* browser = nullptr) {
Profile* profile =
browser ? browser->profile() : this->browser()->profile();
HatsServiceDesktop* service = static_cast<HatsServiceDesktop*>(
HatsServiceFactory::GetForProfile(profile, true));
return service;
}
void SetMetricsConsent(bool consent) {
scoped_metrics_consent_.emplace(consent);
}
bool HatsNextDialogCreated(Browser* browser = nullptr) {
return GetHatsService(browser)->hats_next_dialog_exists_for_testing();
}
// Mock a survey with a custom requested browser type. The `other_browser`
// param may be used to mock the survey in another browser too. Returns the
// trigger to use when launching the survey.
std::string MockSurveyWithRequestedBrowserType(
Browser* other_browser,
hats::SurveyConfig::RequestedBrowserType requested_browser_type) {
for (HatsServiceDesktop* service :
{GetHatsService(), GetHatsService(other_browser)}) {
service
->GetSurveyConfigsByTriggersForTesting()[kHatsSurveyTriggerSettings]
.requested_browser_type = requested_browser_type;
}
return kHatsSurveyTriggerSettings;
}
private:
std::optional<ScopedSetMetricsConsent> scoped_metrics_consent_;
base::test::ScopedFeatureList scoped_feature_list_;
std::vector<base::test::FeatureRefAndParams> enabled_features_;
};
class HatsServiceProbabilityZero : public HatsServiceBrowserTestBase {
public:
HatsServiceProbabilityZero(const HatsServiceProbabilityZero&) = delete;
HatsServiceProbabilityZero& operator=(const HatsServiceProbabilityZero&) =
delete;
protected:
HatsServiceProbabilityZero()
: HatsServiceBrowserTestBase({probability_zero}) {}
~HatsServiceProbabilityZero() override = default;
};
class HatsServiceProbabilityOne : public HatsServiceBrowserTestBase {
public:
HatsServiceProbabilityOne(const HatsServiceProbabilityOne&) = delete;
HatsServiceProbabilityOne& operator=(const HatsServiceProbabilityOne&) =
delete;
protected:
HatsServiceProbabilityOne() : HatsServiceBrowserTestBase({probability_one}) {}
~HatsServiceProbabilityOne() override = default;
private:
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
// Set the profile creation time to be old enough to ensure triggering.
browser()->profile()->SetCreationTimeForTesting(base::Time::Now() -
base::Days(45));
}
void TearDownOnMainThread() override {
GetHatsService()->SetSurveyMetadataForTesting({});
}
};
class HatsServiceConfigCoolDownPeriodOverriden
: public HatsServiceBrowserTestBase {
public:
HatsServiceConfigCoolDownPeriodOverriden(
const HatsServiceConfigCoolDownPeriodOverriden&) = delete;
HatsServiceConfigCoolDownPeriodOverriden& operator=(
const HatsServiceConfigCoolDownPeriodOverriden&) = delete;
protected:
HatsServiceConfigCoolDownPeriodOverriden()
: HatsServiceBrowserTestBase({cool_down_period_overriden}) {}
~HatsServiceConfigCoolDownPeriodOverriden() override = default;
};
class HatsServiceSurveyFeatureControlledByGroup
: public HatsServiceBrowserTestBase {
public:
HatsServiceSurveyFeatureControlledByGroup(
const HatsServiceSurveyFeatureControlledByGroup&) = delete;
HatsServiceSurveyFeatureControlledByGroup& operator=(
const HatsServiceSurveyFeatureControlledByGroup&) = delete;
protected:
HatsServiceSurveyFeatureControlledByGroup()
: HatsServiceBrowserTestBase(
{cool_down_period_overriden_and_group_controlled}) {}
~HatsServiceSurveyFeatureControlledByGroup() override = default;
void AddProfileToGroup(const std::string& group) {
base::Value::List pref_groups_list;
base::Value::Dict group_dict;
group_dict.Set(variations::kDogfoodGroupsSyncPrefGaiaIdKey, group);
pref_groups_list.Append(std::move(group_dict));
profile()->GetPrefs()->SetList(
#if BUILDFLAG(IS_CHROMEOS)
variations::kOsDogfoodGroupsSyncPrefName,
#else
variations::kDogfoodGroupsSyncPrefName,
#endif
std::move(pref_groups_list));
}
};
} // namespace
IN_PROC_BROWSER_TEST_F(HatsServiceBrowserTestBase, BubbleNotShownOnDefault) {
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityZero, NoShow) {
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, NoShowConsentNotGiven) {
SetMetricsConsent(false);
ASSERT_FALSE(
g_browser_process->GetMetricsServicesManager()->IsMetricsConsentGiven());
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_FALSE(HatsNextDialogCreated());
Browser* incognito_browser = CreateIncognitoBrowser();
GetHatsService(incognito_browser)->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_FALSE(HatsNextDialogCreated(incognito_browser));
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, TriggerMismatchNoShow) {
SetMetricsConsent(true);
ASSERT_TRUE(
g_browser_process->GetMetricsServicesManager()->IsMetricsConsentGiven());
GetHatsService()->LaunchSurvey("nonexistent-trigger");
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, AlwaysShow) {
SetMetricsConsent(true);
ASSERT_TRUE(
g_browser_process->GetMetricsServicesManager()->IsMetricsConsentGiven());
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_TRUE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
ShowWhenFeedbackSurveyPolicyEnabled) {
SetMetricsConsent(true);
policy::PolicyMap policies;
SetPolicy(&policies, policy::key::kFeedbackSurveysEnabled, base::Value(true));
UpdateProviderPolicy(policies);
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_TRUE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
NoShowWhenFeedbackSurveyPolicyDisabled) {
SetMetricsConsent(true);
policy::PolicyMap policies;
SetPolicy(&policies, policy::key::kFeedbackSurveysEnabled,
base::Value(false));
UpdateProviderPolicy(policies);
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_FALSE(HatsNextDialogCreated());
Browser* incognito_browser = CreateIncognitoBrowser();
auto trigger = MockSurveyWithRequestedBrowserType(
incognito_browser, hats::SurveyConfig::RequestedBrowserType::kIncognito);
GetHatsService(incognito_browser)->LaunchSurvey(trigger);
EXPECT_FALSE(HatsNextDialogCreated(incognito_browser));
}
IN_PROC_BROWSER_TEST_F(
HatsServiceProbabilityOne,
NeverShowWhenFeedbackSurveyPolicyEnabledWithoutMetricsConsent) {
SetMetricsConsent(false);
policy::PolicyMap policies;
SetPolicy(&policies, policy::key::kFeedbackSurveysEnabled, base::Value(true));
UpdateProviderPolicy(policies);
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, AlsoShowsSettingsSurvey) {
SetMetricsConsent(true);
ASSERT_TRUE(
g_browser_process->GetMetricsServicesManager()->IsMetricsConsentGiven());
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_TRUE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, SameMajorVersionNoShow) {
SetMetricsConsent(true);
base::HistogramTester histogram_tester;
HatsServiceDesktop::SurveyMetadata metadata;
metadata.last_major_version = version_info::GetVersion().components()[0];
GetHatsService()->SetSurveyMetadataForTesting(metadata);
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
histogram_tester.ExpectUniqueSample(
kHatsShouldShowSurveyReasonHistogram,
HatsServiceDesktop::ShouldShowSurveyReasons::
kNoReceivedSurveyInCurrentMilestone,
1);
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, DifferentMajorVersionShow) {
SetMetricsConsent(true);
HatsServiceDesktop::SurveyMetadata metadata;
metadata.last_major_version = 42;
ASSERT_NE(42u, version_info::GetVersion().components()[0]);
GetHatsService()->SetSurveyMetadataForTesting(metadata);
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_TRUE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
SurveyStartedBeforeRequiredElapsedTimeNoShow) {
SetMetricsConsent(true);
base::HistogramTester histogram_tester;
HatsServiceDesktop::SurveyMetadata metadata;
metadata.last_survey_started_time = base::Time::Now();
GetHatsService()->SetSurveyMetadataForTesting(metadata);
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
histogram_tester.ExpectUniqueSample(
kHatsShouldShowSurveyReasonHistogram,
HatsServiceDesktop::ShouldShowSurveyReasons::kNoLastSurveyTooRecent, 1);
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
SurveyStartedBeforeElapsedTimeBetweenAnySurveys) {
SetMetricsConsent(true);
base::HistogramTester histogram_tester;
HatsServiceDesktop::SurveyMetadata metadata;
metadata.any_last_survey_started_time = base::Time::Now();
GetHatsService()->SetSurveyMetadataForTesting(metadata);
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_FALSE(HatsNextDialogCreated());
histogram_tester.ExpectUniqueSample(
kHatsShouldShowSurveyReasonHistogram,
HatsServiceDesktop::ShouldShowSurveyReasons::kNoAnyLastSurveyTooRecent,
1);
}
IN_PROC_BROWSER_TEST_F(
HatsServiceConfigCoolDownPeriodOverriden,
SurveyWithCoolddownOverride_FeatureNotGroupControlled_NoSurvey) {
base::HistogramTester histogram_tester;
SetMetricsConsent(true);
browser()->profile()->SetCreationTimeForTesting(base::Time::Now() -
base::Days(31));
GoogleGroupsManager* groups_manager =
GoogleGroupsManagerFactory::GetForBrowserContext(profile());
EXPECT_FALSE(groups_manager->IsFeatureGroupControlled(
autofill::features::kPlusAddressAcceptedFirstTimeCreateSurvey));
EXPECT_TRUE(groups_manager->IsFeatureEnabledForProfile(
autofill::features::kPlusAddressAcceptedFirstTimeCreateSurvey));
// The cooldown override for the feature should be set to 14 days.
EXPECT_EQ(base::FeatureParam<int>(
&autofill::features::kPlusAddressAcceptedFirstTimeCreateSurvey,
plus_addresses::hats::kCooldownOverrideDays, 0)
.Get(),
14);
HatsServiceDesktop::SurveyMetadata metadata;
metadata.any_last_survey_started_time = base::Time::Now();
metadata.any_last_survey_with_cooldown_override_started_time =
base::Time::Now() - (kCooldownOverride + base::Days(1));
GetHatsService()->SetSurveyMetadataForTesting(metadata);
// kHatsSurveyTriggerPlusAddressAcceptedFirstTimeCreate overrides the cool
// down period.
GetHatsService()->LaunchSurvey(
kHatsSurveyTriggerPlusAddressAcceptedFirstTimeCreate,
/*success_callback=*/base::DoNothing(),
/*failure_callback=*/base::DoNothing(), /*product_specific_bits_data=*/{},
/*product_specific_string_data=*/
std::map<std::string, std::string>{
{plus_addresses::hats::kPlusAddressesCount, "0"},
{plus_addresses::hats::kFirstPlusAddressCreationTime, "0"},
{plus_addresses::hats::kLastPlusAddressFillingTime, "0"}});
EXPECT_FALSE(GetHatsService()->hats_next_dialog_exists_for_testing());
// Since the feature is not group controlled, the cooldown override has no
// effect. The default cooldown of 180 days is used, so the survey is on
// cooldown.
histogram_tester.ExpectUniqueSample(
kHatsShouldShowSurveyReasonHistogram,
HatsServiceDesktop::ShouldShowSurveyReasons::kNoAnyLastSurveyTooRecent,
1);
}
IN_PROC_BROWSER_TEST_F(
HatsServiceSurveyFeatureControlledByGroup,
SurveyWithCoolddownOverride_FeatureIsOnCooldown_NoSurvey) {
base::HistogramTester histogram_tester;
// Add the profile to the group assigned in the field trial config.
// `GoogleGroupsManager::IsFeatureGroupControlled()` returns `false` without
// this call.
AddProfileToGroup(kRelevantGroupId);
SetMetricsConsent(true);
browser()->profile()->SetCreationTimeForTesting(base::Time::Now() -
base::Days(31));
GoogleGroupsManager* groups_manager =
GoogleGroupsManagerFactory::GetForBrowserContext(profile());
EXPECT_TRUE(groups_manager->IsFeatureGroupControlled(
autofill::features::kPlusAddressAcceptedFirstTimeCreateSurvey));
EXPECT_TRUE(groups_manager->IsFeatureEnabledForProfile(
autofill::features::kPlusAddressAcceptedFirstTimeCreateSurvey));
// The cooldown override for the feature should be set to 14 days.
EXPECT_EQ(base::FeatureParam<int>(
&autofill::features::kPlusAddressAcceptedFirstTimeCreateSurvey,
plus_addresses::hats::kCooldownOverrideDays, 0)
.Get(),
14);
HatsServiceDesktop::SurveyMetadata metadata;
metadata.any_last_survey_started_time = base::Time::Now() - base::Days(365);
metadata.any_last_survey_with_cooldown_override_started_time =
base::Time::Now() - (kCooldownOverride - base::Days(1));
GetHatsService()->SetSurveyMetadataForTesting(metadata);
// kHatsSurveyTriggerPlusAddressAcceptedFirstTimeCreate overrides the cool
// down period.
GetHatsService()->LaunchSurvey(
kHatsSurveyTriggerPlusAddressAcceptedFirstTimeCreate,
/*success_callback=*/base::DoNothing(),
/*failure_callback=*/base::DoNothing(), /*product_specific_bits_data=*/{},
/*product_specific_string_data=*/
std::map<std::string, std::string>{
{plus_addresses::hats::kPlusAddressesCount, "0"},
{plus_addresses::hats::kFirstPlusAddressCreationTime, "0"},
{plus_addresses::hats::kLastPlusAddressFillingTime, "0"}});
EXPECT_FALSE(GetHatsService()->hats_next_dialog_exists_for_testing());
// Cooldown period is set, the feature is enabled for profile and group
// controlled. However, the last survey with cooldown override was shown just
// 2 days ago, so the survey is on cooldown.
histogram_tester.ExpectUniqueSample(
kHatsShouldShowSurveyReasonHistogram,
HatsServiceDesktop::ShouldShowSurveyReasons::kNoAnyLastSurveyTooRecent,
1);
}
IN_PROC_BROWSER_TEST_F(
HatsServiceSurveyFeatureControlledByGroup,
SurveyWithCoolddownOverride_FeatureIsGroupControlled_StartsSurvey) {
// Add the profile to the group assigned in the field trial config.
// `GoogleGroupsManager::IsFeatureGroupControlled()` returns `false` without
// this call.
AddProfileToGroup(kRelevantGroupId);
SetMetricsConsent(true);
browser()->profile()->SetCreationTimeForTesting(base::Time::Now() -
base::Days(31));
GoogleGroupsManager* groups_manager =
GoogleGroupsManagerFactory::GetForBrowserContext(profile());
EXPECT_TRUE(groups_manager->IsFeatureGroupControlled(
autofill::features::kPlusAddressAcceptedFirstTimeCreateSurvey));
EXPECT_TRUE(groups_manager->IsFeatureEnabledForProfile(
autofill::features::kPlusAddressAcceptedFirstTimeCreateSurvey));
// The cooldown override for the feature should be set to 14 days.
EXPECT_EQ(base::FeatureParam<int>(
&autofill::features::kPlusAddressAcceptedFirstTimeCreateSurvey,
plus_addresses::hats::kCooldownOverrideDays, 0)
.Get(),
14);
HatsServiceDesktop::SurveyMetadata metadata;
metadata.any_last_survey_started_time = base::Time::Now();
metadata.any_last_survey_with_cooldown_override_started_time =
base::Time::Now() - (kCooldownOverride + base::Days(1));
GetHatsService()->SetSurveyMetadataForTesting(metadata);
// kHatsSurveyTriggerPlusAddressAcceptedFirstTimeCreate overrides the cool
// down period.
GetHatsService()->LaunchSurvey(
kHatsSurveyTriggerPlusAddressAcceptedFirstTimeCreate,
/*success_callback=*/base::DoNothing(),
/*failure_callback=*/base::DoNothing(), /*product_specific_bits_data=*/{},
/*product_specific_string_data=*/
std::map<std::string, std::string>{
{plus_addresses::hats::kPlusAddressesCount, "0"},
{plus_addresses::hats::kFirstPlusAddressCreationTime, "0"},
{plus_addresses::hats::kLastPlusAddressFillingTime, "0"}});
EXPECT_TRUE(GetHatsService()->hats_next_dialog_exists_for_testing());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, ProfileTooYoungToShow) {
SetMetricsConsent(true);
base::HistogramTester histogram_tester;
// Set creation time to only 15 days.
browser()->profile()->SetCreationTimeForTesting(base::Time::Now() -
base::Days(15));
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
histogram_tester.ExpectUniqueSample(
kHatsShouldShowSurveyReasonHistogram,
HatsServiceDesktop::ShouldShowSurveyReasons::kNoProfileTooNew, 1);
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, ProfileOldEnoughToShow) {
SetMetricsConsent(true);
// Set creation time to 31 days. This is just past the threshold.
browser()->profile()->SetCreationTimeForTesting(base::Time::Now() -
base::Days(31));
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_TRUE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
RegularSurveyInIncognitoNoShow) {
SetMetricsConsent(true);
base::HistogramTester histogram_tester;
// A regular survey should not be shown in incognito
Browser* incognito_browser = CreateIncognitoBrowser();
GetHatsService(incognito_browser)->LaunchSurvey(kHatsSurveyTriggerSettings);
histogram_tester.ExpectUniqueSample(
kHatsShouldShowSurveyReasonHistogram,
HatsServiceDesktop::ShouldShowSurveyReasons::kNoWrongBrowserType, 1);
EXPECT_FALSE(HatsNextDialogCreated(incognito_browser));
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
IncognitoSurveyShownOnlyInIncognito) {
SetMetricsConsent(true);
base::HistogramTester histogram_tester;
Browser* incognito_browser = CreateIncognitoBrowser();
auto trigger = MockSurveyWithRequestedBrowserType(
incognito_browser, hats::SurveyConfig::RequestedBrowserType::kIncognito);
// An incognito survey should not be shown in regular
GetHatsService()->LaunchSurvey(trigger);
histogram_tester.ExpectUniqueSample(
kHatsShouldShowSurveyReasonHistogram,
HatsServiceDesktop::ShouldShowSurveyReasons::kNoWrongBrowserType, 1);
EXPECT_FALSE(HatsNextDialogCreated());
// An incognito survey should be shown in incognito
GetHatsService(incognito_browser)->LaunchSurvey(trigger);
EXPECT_TRUE(HatsNextDialogCreated(incognito_browser));
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, IncognitoModeDisabledNoShow) {
SetMetricsConsent(true);
// Disable incognito mode for this profile.
PrefService* pref_service = browser()->profile()->GetPrefs();
pref_service->SetInteger(
policy::policy_prefs::kIncognitoModeAvailability,
static_cast<int>(policy::IncognitoModeAvailability::kDisabled));
EXPECT_EQ(policy::IncognitoModeAvailability::kDisabled,
IncognitoModePrefs::GetAvailability(pref_service));
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, CheckedWithinADayNoShow) {
SetMetricsConsent(true);
base::HistogramTester histogram_tester;
HatsServiceDesktop::SurveyMetadata metadata;
metadata.last_survey_check_time = base::Time::Now() - base::Hours(23);
GetHatsService()->SetSurveyMetadataForTesting(metadata);
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
histogram_tester.ExpectUniqueSample(
kHatsShouldShowSurveyReasonHistogram,
HatsServiceDesktop::ShouldShowSurveyReasons::kNoLastSurveyCheckTooRecent,
1);
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, CheckedAfterADayToShow) {
SetMetricsConsent(true);
HatsServiceDesktop::SurveyMetadata metadata;
metadata.last_survey_check_time = base::Time::Now() - base::Days(1);
GetHatsService()->SetSurveyMetadataForTesting(metadata);
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_TRUE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, SurveyAlreadyFullNoShow) {
SetMetricsConsent(true);
HatsServiceDesktop::SurveyMetadata metadata;
metadata.is_survey_full = true;
GetHatsService()->SetSurveyMetadataForTesting(metadata);
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, LaunchDelayedSurvey) {
SetMetricsConsent(true);
EXPECT_TRUE(
GetHatsService()->LaunchDelayedSurvey(kHatsSurveyTriggerSettings, 0));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
LaunchDelayedSurveyForWebContents) {
SetMetricsConsent(true);
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_TRUE(GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings, web_contents, 0));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, DisallowsEmptyWebContents) {
SetMetricsConsent(true);
EXPECT_FALSE(GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings, nullptr, 0));
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(
HatsServiceProbabilityOne,
AllowsMultipleDelayedSurveyRequestsDifferentWebContents) {
SetMetricsConsent(true);
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_TRUE(GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings, web_contents, 0));
base::RunLoop().RunUntilIdle();
chrome::AddTabAt(browser(), GURL(), -1, true);
EXPECT_TRUE(GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings,
browser()->tab_strip_model()->GetActiveWebContents(), 0));
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
DisallowsSameDelayedSurveyForWebContentsRequests) {
SetMetricsConsent(true);
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_TRUE(GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings, web_contents, 0));
EXPECT_FALSE(GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings, web_contents, 0));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
ReleasesPendingTaskAfterFulfilling) {
SetMetricsConsent(true);
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_TRUE(GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings, web_contents, 0));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(GetHatsService()->HasPendingTasks());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, VisibleWebContentsShow) {
SetMetricsConsent(true);
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings, web_contents, 0);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, InvisibleWebContentsNoShow) {
SetMetricsConsent(true);
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings, web_contents, 0);
chrome::AddTabAt(browser(), GURL(), -1, true);
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
NavigatedWebContents_RequireSameOrigin) {
SetMetricsConsent(true);
ASSERT_TRUE(embedded_test_server()->Start());
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("a.test", "/empty.html")));
// As navigating also occurs asynchronously, a long survey delay is use to
// ensure it completes before the survey tries to run.
GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings, web_contents, 10000, {}, {},
/*navigation_behavior=*/
HatsService::NavigationBehavior::REQUIRE_SAME_ORIGIN);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("b.test", "/empty.html")));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(GetHatsService()->HasPendingTasks());
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
NavigatedWebContents_NoRequireSameOrigin) {
SetMetricsConsent(true);
ASSERT_TRUE(embedded_test_server()->Start());
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("a.test", "/empty.html")));
EXPECT_FALSE(GetHatsService()->HasPendingTasks());
GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings, web_contents, 10000, {}, {},
/*navigation_behavior=*/
HatsService::NavigationBehavior::ALLOW_ANY);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("b.test", "/empty.html")));
base::RunLoop().RunUntilIdle();
// The survey task should still be in the pending task queue.
EXPECT_TRUE(GetHatsService()->HasPendingTasks());
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
NavigatedWebContents_RequireSameDocument) {
SetMetricsConsent(true);
ASSERT_TRUE(embedded_test_server()->Start());
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
const GURL kTestUrl = embedded_test_server()->GetURL("a.test", "/empty.html");
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), kTestUrl));
// As navigating also occurs asynchronously, a long survey delay is use to
// ensure it completes before the survey tries to run.
GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings, web_contents, 10000, {}, {},
/*navigation_behavior=*/
HatsService::NavigationBehavior::REQUIRE_SAME_DOCUMENT);
// Same-document navigation
web_contents->GetPrimaryMainFrame()->ExecuteJavaScriptForTests(
u"document.location='#';", base::NullCallback(),
content::ISOLATED_WORLD_ID_GLOBAL);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(GetHatsService()->HasPendingTasks());
EXPECT_FALSE(HatsNextDialogCreated());
// Same-origin navigation
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
embedded_test_server()->GetURL("a.test", "/empty_script.html")));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(GetHatsService()->HasPendingTasks());
EXPECT_FALSE(HatsNextDialogCreated());
}
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, SameOriginNavigation) {
SetMetricsConsent(true);
ASSERT_TRUE(embedded_test_server()->Start());
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("a.test", "/empty.html")));
EXPECT_FALSE(GetHatsService()->HasPendingTasks());
GetHatsService()->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettings, web_contents, 10000, {}, {},
/*navigation_behavior=*/
HatsService::NavigationBehavior::REQUIRE_SAME_ORIGIN);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("a.test", "/form.html")));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(GetHatsService()->HasPendingTasks());
EXPECT_FALSE(HatsNextDialogCreated());
}
// Check that once a HaTS Next dialog has been created, ShouldShowSurvey
// returns false until the service has been informed the dialog was closed.
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, SingleHatsNextDialog) {
SetMetricsConsent(true);
EXPECT_TRUE(GetHatsService()->ShouldShowSurvey(kHatsSurveyTriggerSettings));
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
// Clear any metadata that would prevent another survey from being displayed.
GetHatsService()->SetSurveyMetadataForTesting({});
// At this point a HaTS Next dialog is created and is attempting to contact
// the wrapper website (which will fail as requests to non-localhost addresses
// are disallowed in browser tests). Regardless of the outcome of the network
// request, the dialog waits for a timeout posted to the UI thread before
// closing itself. Since this test is also on the UI thread, these checks,
// which rely on the dialog still being open, will not race.
EXPECT_FALSE(GetHatsService()->ShouldShowSurvey(kHatsSurveyTriggerSettings));
// Inform the service directly that the dialog has been closed.
GetHatsService()->HatsNextDialogClosed();
EXPECT_TRUE(GetHatsService()->ShouldShowSurvey(kHatsSurveyTriggerSettings));
}
// Check that launching a HaTS Next survey records a survey check time
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne, SurveyCheckTimeRecorded) {
SetMetricsConsent(true);
// Clear any existing survey metadata.
GetHatsService()->SetSurveyMetadataForTesting({});
GetHatsService()->LaunchSurvey(kHatsSurveyTriggerSettings);
HatsServiceDesktop::SurveyMetadata metadata;
GetHatsService()->GetSurveyMetadataForTesting(&metadata);
EXPECT_TRUE(metadata.last_survey_check_time.has_value());
}
// Check that launching a HaTS Next survey records a survey check time even if
// triggered in incognito
IN_PROC_BROWSER_TEST_F(HatsServiceProbabilityOne,
SurveyCheckTimeRecordedIncognito) {
SetMetricsConsent(true);
// Clear any existing survey metadata.
GetHatsService()->SetSurveyMetadataForTesting({});
Browser* incognito_browser = CreateIncognitoBrowser();
auto trigger = MockSurveyWithRequestedBrowserType(
incognito_browser, hats::SurveyConfig::RequestedBrowserType::kIncognito);
GetHatsService(incognito_browser)->LaunchSurvey(trigger);
HatsServiceDesktop::SurveyMetadata metadata;
GetHatsService()->GetSurveyMetadataForTesting(&metadata);
EXPECT_TRUE(metadata.last_survey_check_time.has_value());
}