chromium/chrome/browser/metrics/ukm_browsertest.cc

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

#include <memory>
#include <string>

#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/system/sys_info.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browsing_data/chrome_browsing_data_remover_constants.h"
#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
#include "chrome/browser/metrics/chrome_metrics_service_client.h"
#include "chrome/browser/metrics/chrome_metrics_services_manager_client.h"
#include "chrome/browser/metrics/testing/metrics_reporting_pref_helper.h"
#include "chrome/browser/metrics/testing/sync_metrics_test_utils.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_test_util.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/browser/sync/test/integration/secondary_account_helper.h"
#include "chrome/browser/sync/test/integration/sync_service_impl_harness.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
#include "chrome/browser/unified_consent/unified_consent_service_factory.h"
#include "components/metrics/demographics/demographic_metrics_provider.h"
#include "components/metrics/demographics/demographic_metrics_test_utils.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics_services_manager/metrics_services_manager.h"
#include "components/signin/public/base/signin_buildflags.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/sync/base/features.h"
#include "components/sync/service/sync_service.h"
#include "components/sync/service/sync_service_impl.h"
#include "components/sync/service/sync_token_status.h"
#include "components/sync/test/fake_server_network_resources.h"
#include "components/ukm/ukm_recorder_observer.h"
#include "components/ukm/ukm_service.h"
#include "components/ukm/ukm_test_helper.h"
#include "components/unified_consent/unified_consent_service.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/browsing_data_remover.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/browsing_data_remover_test_util.h"
#include "content/public/test/navigation_handle_observer.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/cpp/ukm_source.h"
#include "services/network/test/test_network_quality_tracker.h"
#include "third_party/metrics_proto/ukm/report.pb.h"
#include "third_party/metrics_proto/user_demographics.pb.h"
#include "url/url_constants.h"

#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/tabs/tab_enums.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#else
#include "chrome/browser/flags/android/chrome_feature_list.h"
#include "chrome/browser/flags/android/chrome_session_state.h"
#include "chrome/browser/ui/android/tab_model/tab_model.h"
#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
#include "chrome/browser/ui/android/tab_model/tab_model_observer.h"
#include "chrome/test/base/android/android_browser_test.h"
#include "content/public/browser/web_contents.h"
#endif  // !BUILDFLAG(IS_ANDROID)

#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/ui/profiles/profile_picker.h"
#include "chrome/browser/ui/profiles/profile_ui_test_utils.h"
#endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)

namespace metrics {
namespace {

class TestTabModel;

#if !BUILDFLAG(IS_ANDROID)
PlatformBrowser;
#else
typedef std::unique_ptr<TestTabModel> PlatformBrowser;
#endif  // !BUILDFLAG(IS_ANDROID)

// Clears the specified data using BrowsingDataRemover.
void ClearBrowsingData(Profile* profile) {}

ukm::UkmService* GetUkmService() {}

class TestUkmRecorderObserver : public ukm::UkmRecorderObserver {};

#if BUILDFLAG(IS_ANDROID)

// ActivityType that doesn't restore tabs on cold start.
// Any type other than kTabbed is fine.
const auto TEST_ACTIVITY_TYPE = chrome::android::ActivityType::kCustomTab;

// TestTabModel provides a means of creating a tab associated with a given
// profile. The new tab can then be added to Android's TabModelList.
class TestTabModel : public TabModel {
 public:
  explicit TestTabModel(Profile* profile)
      : TabModel(profile, TEST_ACTIVITY_TYPE),
        web_contents_(content::WebContents::Create(
            content::WebContents::CreateParams(GetProfile()))) {}

  ~TestTabModel() override = default;

  // TabModel:
  int GetTabCount() const override { return 0; }
  int GetActiveIndex() const override { return 0; }
  base::android::ScopedJavaLocalRef<jobject> GetJavaObject() const override {
    return nullptr;
  }
  content::WebContents* GetActiveWebContents() const override {
    return web_contents_.get();
  }
  content::WebContents* GetWebContentsAt(int index) const override {
    return nullptr;
  }
  TabAndroid* GetTabAt(int index) const override { return nullptr; }
  void SetActiveIndex(int index) override {}
  void CloseTabAt(int index) override {}
  void CreateTab(TabAndroid* parent,
                 content::WebContents* web_contents,
                 bool select) override {}
  void HandlePopupNavigation(TabAndroid* parent,
                             NavigateParams* params) override {}
  content::WebContents* CreateNewTabForDevTools(const GURL& url) override {
    return nullptr;
  }
  bool IsSessionRestoreInProgress() const override { return false; }
  bool IsActiveModel() const override { return false; }
  void AddObserver(TabModelObserver* observer) override {}
  void RemoveObserver(TabModelObserver* observer) override {}
  int GetTabCountNavigatedInTimeWindow(
      const base::Time& begin_time,
      const base::Time& end_time) const override {
    return 0;
  }
  void CloseTabsNavigatedInTimeWindow(const base::Time& begin_time,
                                      const base::Time& end_time) override {}

 private:
  // The WebContents associated with this tab's profile.
  std::unique_ptr<content::WebContents> web_contents_;
};
#endif  // BUILDFLAG(IS_ANDROID)

}  // namespace

// A helper object for overriding metrics enabled state.
class MetricsConsentOverride {};

// Test fixture that provides access to some UKM internals.
class UkmBrowserTestBase : public SyncTest {};

class UkmBrowserTest : public UkmBrowserTestBase {};

class UkmBrowserTestWithSyncTransport : public UkmBrowserTestBase {};

// This tests if UKM service is enabled/disabled appropriately based on an
// input bool param. The bool reflects if metrics reporting state is
// enabled/disabled via prefs.
#if !BUILDFLAG(IS_ANDROID)
class UkmConsentParamBrowserTest : public UkmBrowserTestBase,
                                   public testing::WithParamInterface<bool> {};
#endif  // !BUILDFLAG(IS_ANDROID)

// Test the reporting of the synced user's birth year and gender.
class UkmBrowserTestWithDemographics
    : public UkmBrowserTestBase,
      public testing::WithParamInterface<test::DemographicsTestParams> {};

// Make sure that UKM is disabled while an incognito window is open.
// Keep in sync with testRegularPlusIncognito in ios/chrome/browser/metrics/
// ukm_egtest.mm.
// Disabled on Android due to flakiness. See crbug.com/355609356.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_RegularPlusIncognitoCheck
#else
#define MAYBE_RegularPlusIncognitoCheck
#endif
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, MAYBE_RegularPlusIncognitoCheck) {}

// Make sure opening a real window after Incognito doesn't enable UKM.
// Keep in sync with testIncognitoPlusRegular in ios/chrome/browser/metrics/
// ukm_egtest.mm.
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, IncognitoPlusRegularCheck) {}

// Make sure that UKM is disabled while a guest profile's window is open.
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, RegularPlusGuestCheck) {}
#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)

// ProfilePicker and System profile do not exist on Chrome Ash and on Android.
#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)
// Displaying the ProfilePicker implicitly creates a System Profile.
// System Profile shouldn't have any effect on the UKM Enable Status.
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, ProfilePickerCheck) {}
#endif  // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID)

// Not applicable to Android as it doesn't have multiple profiles.
#if !BUILDFLAG(IS_ANDROID)
// Make sure that UKM is disabled while an non-sync profile's window is open.
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, OpenNonSyncCheck) {}
#endif  // !BUILDFLAG(IS_ANDROID)

// Make sure that UKM is disabled when metrics consent is revoked.
// Keep in sync with testMetricsConsent in ios/chrome/browser/metrics/
// ukm_egtest.mm.
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, MetricsConsentCheck) {}

#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, LogProtoData) {}
#endif  // !BUILDFLAG(IS_ANDROID)

// TODO(crbug.com/40103988): Add the remaining test cases.
// Keep this test in sync with testUKMDemographicsReportingWithFeatureEnabled
// and testUKMDemographicsReportingWithFeatureDisabled in
// ios/chrome/browser/metrics/demographics_egtest.mm.
IN_PROC_BROWSER_TEST_P(UkmBrowserTestWithDemographics,
                       AddSyncedUserBirthYearAndGenderToProtoData) {}

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Cannot test for the enabled feature on Chrome OS because there are always
// multiple profiles.
static const auto kDemographicsTestParams = testing::Values(
    test::DemographicsTestParams{/*enable_feature=*/false,
                                 /*expect_reported_demographics=*/false});
#else
static const auto kDemographicsTestParams =;
#endif

INSTANTIATE_TEST_SUITE_P();

// Verifies that network provider attaches effective connection type correctly
// to the UKM report.
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, NetworkProviderPopulatesSystemProfile) {}
#endif  // !BUILDFLAG(IS_ANDROID)

// Verifies that install date is attached.
// Disabled on Android due to flakiness. See crbug.com/355609356.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_InstallDateProviderPopulatesSystemProfile
#else
#define MAYBE_InstallDateProviderPopulatesSystemProfile
#endif
IN_PROC_BROWSER_TEST_F(UkmBrowserTest,
                       MAYBE_InstallDateProviderPopulatesSystemProfile) {}

// Make sure that providing consent doesn't enable UKM when sync is disabled.
// Keep in sync with testConsentAddedButNoSync in ios/chrome/browser/metrics/
// ukm_egtest.mm and consentAddedButNoSyncCheck in chrome/android/javatests/src/
// org/chromium/chrome/browser/sync/UkmTest.java.
// Flaky on Android crbug.com/1096400
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_ConsentAddedButNoSyncCheck
#else
#define MAYBE_ConsentAddedButNoSyncCheck
#endif
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, MAYBE_ConsentAddedButNoSyncCheck) {}

// Make sure that extension URLs are disabled when an open sync window
// disables it.
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, SingleDisableExtensionsSyncCheck) {}
#endif  // !BUILDFLAG(IS_ANDROID)

// Make sure that extension URLs are disabled when any open sync window
// disables it.
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, MultiDisableExtensionsSyncCheck) {}
#endif  // !BUILDFLAG(IS_ANDROID)

#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, LogsTabId) {}
#endif  // !BUILDFLAG(IS_ANDROID)

#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, LogsPreviousSourceId) {}
#endif  // !BUILDFLAG(IS_ANDROID)

#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, LogsOpenerSource) {}
#endif  // !BUILDFLAG(IS_ANDROID)

// ChromeOS doesn't have the concept of sign-out so this test doesn't make sense
// there.
//
// Flaky on Android: https://crbug.com/1096047.
//
// Make sure that UKM is disabled when the profile signs out of Sync.
// Keep in sync with testSingleSyncSignout in ios/chrome/browser/metrics/
// ukm_egtest.mm and singleSyncSignoutCheck in chrome/android/javatests/src/org/
// chromium/chrome/browser/sync/UkmTest.java.
#if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, SingleSyncSignoutCheck) {}
#endif  // !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)

// ChromeOS doesn't have the concept of sign-out so this test doesn't make sense
// there. Android doesn't have multiple profiles.
#if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
// Make sure that UKM is disabled when any profile signs out of Sync.
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, MultiSyncSignoutCheck) {}
#endif  // !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)

// Make sure that if history/sync services weren't available when we tried to
// attach listeners, UKM is not enabled.
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, ServiceListenerInitFailedCheck) {}
#endif  // !BUILDFLAG(IS_ANDROID)

// Make sure that UKM is not affected by MetricsReporting Feature (sampling).
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, MetricsReportingCheck) {}
#endif  // !BUILDFLAG(IS_ANDROID)

// Make sure that pending data is deleted when user deletes history.
//
// Keep in sync with testHistoryDelete in ios/chrome/browser/metrics/
// ukm_egtest.mm and testHistoryDeleteCheck in chrome/android/javatests/src/org/
// chromium/chrome/browser/metrics/UkmTest.java.
//
// Flaky on Android: https://crbug.com/1131541.
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_HistoryDeleteCheck
#else
#define MAYBE_HistoryDeleteCheck
#endif
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, MAYBE_HistoryDeleteCheck) {}

// On ChromeOS, the test profile starts with a primary account already set, so
// this test doesn't apply.
#if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTestWithSyncTransport,
                       NotEnabledForSecondaryAccountSync) {}
#endif  // !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)

#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_P(UkmConsentParamBrowserTest, GroupPolicyConsentCheck) {}
#endif  // !BUILDFLAG(IS_ANDROID)

#if !BUILDFLAG(IS_ANDROID)
// Verify UKM is enabled/disabled for both potential settings of group policy.
INSTANTIATE_TEST_SUITE_P();
#endif  // !BUILDFLAG(IS_ANDROID)

// Verify that sources kept alive in-memory will be discarded by UKM service in
// one reporting cycle after the web contents are destroyed when the tab is
// closed or when the user navigated away in the same tab.
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, EvictObsoleteSources) {}
#endif  // !BUILDFLAG(IS_ANDROID)

// Verify that correct sources are marked as obsolete when same-document
// navigation happens.
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest,
                       MarkObsoleteSourcesSameDocumentNavigation) {}
#endif  // !BUILDFLAG(IS_ANDROID)

// Verify that sources are not marked as obsolete by a new navigation that does
// not commit.
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, NotMarkSourcesIfNavigationNotCommitted) {}
#endif  // !BUILDFLAG(IS_ANDROID)

#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, DebugUiRenders) {}
#endif  // !BUILDFLAG(IS_ANDROID)

#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_F(UkmBrowserTest, AllowedStateChanged) {}
#endif  // !BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_CHROMEOS_ASH)
class UkmBrowserTestForAppConsent : public UkmBrowserTestBase {
 public:
  UkmBrowserTestForAppConsent() = default;
};

IN_PROC_BROWSER_TEST_F(UkmBrowserTestForAppConsent, MetricsClientEnablement) {
  ukm::UkmService* ukm_service = GetUkmService();
  ukm::UkmTestHelper ukm_test_helper(ukm_service);
  MetricsConsentOverride metrics_consent(true);
  Profile* profile = ProfileManager::GetLastUsedProfileIfLoaded();
  unified_consent::UnifiedConsentService* consent_service =
      UnifiedConsentServiceFactory::GetForProfile(profile);
  std::unique_ptr<SyncServiceImplHarness> harness =
      EnableSyncForProfile(profile);

  // All consents are on.
  EXPECT_TRUE(ukm_test_helper.IsRecordingEnabled());
  EXPECT_TRUE(ukm_service->recording_enabled(ukm::MSBB));
  EXPECT_TRUE(ukm_service->recording_enabled(ukm::EXTENSIONS));
  EXPECT_TRUE(ukm_service->recording_enabled(ukm::APPS));

  // Turn off MSBB consent.
  consent_service->SetUrlKeyedAnonymizedDataCollectionEnabled(false);

  // Still have AppKM consent.
  EXPECT_TRUE(ukm_test_helper.IsRecordingEnabled());
  EXPECT_FALSE(ukm_service->recording_enabled(ukm::MSBB));
  EXPECT_FALSE(ukm_service->recording_enabled(ukm::EXTENSIONS));
  EXPECT_TRUE(ukm_service->recording_enabled(ukm::APPS));

  // Turn off App-sync.
  auto* user_settings = harness->service()->GetUserSettings();
  auto registered_os_sync_types =
      user_settings->GetRegisteredSelectableOsTypes();
  registered_os_sync_types.Remove(syncer::UserSelectableOsType::kOsApps);
  user_settings->SetSelectedOsTypes(false, registered_os_sync_types);

  // UKM recording is now disabled since MSBB and App-sync consent
  // has been removed.
  EXPECT_FALSE(ukm_test_helper.IsRecordingEnabled());
  EXPECT_FALSE(ukm_service->recording_enabled(ukm::MSBB));
  EXPECT_FALSE(ukm_service->recording_enabled(ukm::EXTENSIONS));
  EXPECT_FALSE(ukm_service->recording_enabled(ukm::APPS));
}

IN_PROC_BROWSER_TEST_F(UkmBrowserTestForAppConsent,
                       ClientIdResetWhenConsentRemoved) {
  ukm::UkmService* ukm_service = GetUkmService();
  ukm::UkmTestHelper ukm_test_helper(ukm_service);
  MetricsConsentOverride metrics_consent(true);
  Profile* profile = ProfileManager::GetLastUsedProfileIfLoaded();
  unified_consent::UnifiedConsentService* consent_service =
      UnifiedConsentServiceFactory::GetForProfile(profile);
  std::unique_ptr<SyncServiceImplHarness> harness =
      EnableSyncForProfile(profile);
  const auto original_client_id = ukm_test_helper.GetClientId();
  EXPECT_NE(0ul, original_client_id);

  // All consents are on.
  EXPECT_TRUE(ukm_test_helper.IsRecordingEnabled());
  EXPECT_TRUE(ukm_service->recording_enabled(ukm::MSBB));
  EXPECT_TRUE(ukm_service->recording_enabled(ukm::EXTENSIONS));
  EXPECT_TRUE(ukm_service->recording_enabled(ukm::APPS));

  // Turn off MSBB consent.
  consent_service->SetUrlKeyedAnonymizedDataCollectionEnabled(false);

  EXPECT_FALSE(ukm_service->recording_enabled(ukm::MSBB));

  // Client ID should reset when MSBB is disabled.
  const auto app_sync_client_id = ukm_test_helper.GetClientId();
  EXPECT_NE(original_client_id, app_sync_client_id);

  // Turn off app sync.
  auto* user_settings = harness->service()->GetUserSettings();
  auto registered_os_sync_types =
      user_settings->GetRegisteredSelectableOsTypes();
  registered_os_sync_types.Remove(syncer::UserSelectableOsType::kOsApps);
  user_settings->SetSelectedOsTypes(false, registered_os_sync_types);

  EXPECT_FALSE(ukm_service->recording_enabled(ukm::APPS));

  // Client ID should reset when app sync is disable.
  const auto final_client_id = ukm_test_helper.GetClientId();
  EXPECT_NE(app_sync_client_id, final_client_id);
}

IN_PROC_BROWSER_TEST_F(UkmBrowserTestForAppConsent,
                       EnsurePurgeOnConsentChange) {
  ukm::UkmService* ukm_service = GetUkmService();
  ukm::UkmTestHelper ukm_test_helper(ukm_service);
  MetricsConsentOverride metrics_consent(true);
  Profile* profile = ProfileManager::GetLastUsedProfileIfLoaded();
  unified_consent::UnifiedConsentService* consent_service =
      UnifiedConsentServiceFactory::GetForProfile(profile);
  std::unique_ptr<SyncServiceImplHarness> harness =
      EnableSyncForProfile(profile);
  Browser* sync_browser = CreateBrowser(profile);
  ASSERT_TRUE(embedded_test_server()->Start());

  const std::vector<GURL> test_urls = {
      embedded_test_server()->GetURL("/title1.html"),
      embedded_test_server()->GetURL("/title2.html"),
      embedded_test_server()->GetURL("/title3.html")};

  // Verify all consents are enabled.
  EXPECT_TRUE(ukm_service->recording_enabled(ukm::MSBB));
  EXPECT_TRUE(ukm_service->recording_enabled(ukm::EXTENSIONS));
  EXPECT_TRUE(ukm_service->recording_enabled(ukm::APPS));

  int tab_index = 1;
  // Generate MSBB ukm entries by navigating to some test webpages.
  for (const auto& url : test_urls) {
    ASSERT_TRUE(AddTabAtIndexToBrowser(sync_browser, tab_index++,
                                       GURL(url::kAboutBlankURL),
                                       ui::PAGE_TRANSITION_TYPED, true));
    NavigateAndGetSource(url, sync_browser, &ukm_test_helper);
  }

  // Revoke MSBB consent.
  consent_service->SetUrlKeyedAnonymizedDataCollectionEnabled(false);

  // Verify that MSBB consent was revoked.
  EXPECT_FALSE(ukm_service->recording_enabled(ukm::MSBB));
  EXPECT_FALSE(ukm_service->recording_enabled(ukm::EXTENSIONS));
  EXPECT_TRUE(ukm_service->recording_enabled(ukm::APPS));

  ukm_test_helper.BuildAndStoreLog();
  const std::unique_ptr<ukm::Report> report = ukm_test_helper.GetUkmReport();

  // Verify that the only sources in the report are APP_ID.
  // NOTE(crbug/1395143): It was noticed that there was an APP_ID source
  // generated despite not being explicitly created. No entries are associated
  // with it though.
  for (int i = 0; i < report->sources_size(); ++i) {
    const auto id = report->sources(i).id();
    EXPECT_EQ(ukm::GetSourceIdType(id), ukm::SourceIdType::APP_ID);
  }
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

}  // namespace metrics