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

#include <algorithm>
#include <sstream>

#include "base/containers/to_vector.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_util.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/media/router/media_router_feature.h"
#include "chrome/browser/navigation_predictor/search_engine_preconnector.h"
#include "chrome/browser/preloading/scoped_prewarm_feature_list.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_selections.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/omnibox/omnibox_next_features.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/profile_waiter.h"
#include "components/commerce/core/commerce_feature_list.h"
#include "components/contextual_tasks/public/features.h"
#include "components/enterprise/buildflags/buildflags.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/keyed_service/core/dependency_graph.h"
#include "components/keyed_service/core/keyed_service_base_factory.h"
#include "components/omnibox/common/omnibox_features.h"
#include "components/signin/public/base/signin_switches.h"
#include "components/supervised_user/core/common/features.h"
#include "components/universal_optout/features.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_utils.h"
#include "extensions/buildflags/buildflags.h"
#include "extensions/common/extension_features.h"
#include "net/base/features.h"
#include "pdf/buildflags.h"
#include "services/network/public/cpp/features.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "third_party/blink/public/common/features.h"
#include "ui/accessibility/accessibility_features.h"
#include "ui/base/ui_base_features.h"

#if BUILDFLAG(IS_CHROMEOS)
#include "ash/constants/ash_switches.h"
#include "chrome/common/chrome_switches.h"
#include "components/user_manager/user_manager.h"
#include "components/user_manager/user_names.h"
#endif  // BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
#include "components/policy/core/common/features.h"
#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)

namespace {
#if !BUILDFLAG(IS_CHROMEOS)
// Creates a Profile and its underlying OTR Profile for testing.
// Waits for all tasks to be done to get as many services created as possible.
// Returns the Original Profile.
Profile* CreateProfileAndWaitForAllTasks(const base::FilePath& profile_path) {
  ProfileManager* profile_manager = g_browser_process->profile_manager();
  ProfileWaiter profile_waiter;
  profile_manager->CreateProfileAsync(profile_path, {});
  Profile* profile = profile_waiter.WaitForProfileAdded();
  // Wait for Profile creation, and potentially other services that will be
  // created after all tasks are done.
  content::RunAllTasksUntilIdle();
  return profile;
}
#endif

// Gets all the KeyedServices from the DependencyGraph.
std::vector<KeyedServiceBaseFactory*> GetKeyedServiceBaseFactories() {
  BrowserContextDependencyManager* dependency_manager =
      BrowserContextDependencyManager::GetInstance();
  DependencyGraph& dependency_graph =
      dependency_manager->GetDependencyGraphForTesting();
  std::vector<raw_ptr<DependencyNode, VectorExperimental>> nodes;
  bool success = dependency_graph.GetConstructionOrder(&nodes);
  DCHECK(success);

  return base::ToVector(nodes, [](DependencyNode* node) {
    return static_cast<KeyedServiceBaseFactory*>(node);
  });
}

// Returns a string representation of the elements of `set1` which are absent
// from `set2`.
std::string GetDifferenceString(const std::set<std::string>& set1,
                                const std::set<std::string>& set2) {
  std::vector<std::string> differences;
  std::ranges::set_difference(set1, set2, std::back_inserter(differences));

  return differences.empty() ? "None" : base::JoinString(differences, ", ");
}

// Helper function to properly display differences between expected and reached
// service names.
std::string DisplaySetDifference(
    const std::set<std::string>& expected_active_services_names,
    const std::set<std::string>& active_services_names) {
  std::stringstream error;
  error << "Differences between expected and reached services:" << std::endl;

  error << "-- Missing Expected Services:" << std::endl;
  error << GetDifferenceString(expected_active_services_names,
                               active_services_names)
        << std::endl;

  error << "-- Added Extra Services:" << std::endl;
  error << GetDifferenceString(active_services_names,
                               expected_active_services_names)
        << std::endl;

  return error.str();
}

// The test comparing expected vs reached keyed services for the given profile.
void TestKeyedProfileServicesActives(
    Profile* profile,
    const std::set<std::string>& expected_active_services_names,
    bool force_create_services = false,
    const base::Location& location = FROM_HERE) {
  const std::vector<KeyedServiceBaseFactory*> keyedServiceFactories =
      GetKeyedServiceBaseFactories();

  if (force_create_services) {
    for (KeyedServiceBaseFactory* factory : keyedServiceFactories) {
      factory->CreateServiceNowForTesting(profile);
    }
  }

  std::set<std::string> active_services_names;
  for (KeyedServiceBaseFactory* factory : keyedServiceFactories) {
    if (factory->IsServiceCreated(profile)) {
      active_services_names.emplace(factory->name());
    }
  }

  EXPECT_EQ(active_services_names, expected_active_services_names)
      << DisplaySetDifference(expected_active_services_names,
                              active_services_names)
      << ", expected at " << location.ToString();
}

}  // namespace

TEST(ProfileKeyedService_DisplaySetDifferenceTest, UnexpectedActiveService) {
  std::string message =
      DisplaySetDifference(/*expected_active_services_names=*/{},
                           /*active_services_names=*/{"unexpected"});
  EXPECT_THAT(message,
              testing::ContainsRegex("Missing Expected Services:\\s+None"));
  EXPECT_THAT(message,
              testing::ContainsRegex("Added Extra Services:\\s+unexpected"));
}

TEST(ProfileKeyedService_DisplaySetDifferenceTest, MissingExpectedService) {
  std::string message =
      DisplaySetDifference(/*expected_active_services_names=*/{"missing"},
                           /*active_services_names=*/{});
  EXPECT_THAT(message,
              testing::ContainsRegex("Missing Expected Services:\\s+missing"));
  EXPECT_THAT(message, testing::ContainsRegex("Added Extra Services:\\s+None"));
}

// If you are adding a new keyed service and this test fails:
// - determine if your service is intended to be created for the System profile
// - if yes, add it to the list of allowed services
// - if not, update your factory class so that the service is not created for
// the system profile.
//
// Note: if your service should not be used on the system profile, but still has
// to, because other services depend on it, add a comment explaining why.
// Example:
//   // FooService is required because BarService depends on it.
//   // TODO(crbug.com/40781525): Stop creating BarService for the system
//   profile.
class ProfileKeyedServiceBrowserTest : public InProcessBrowserTest {
 public:
  ProfileKeyedServiceBrowserTest() {
    // Force features activation to make sure the test is accurate as possible.
    // Also removes differences between official and non official run of the
    // tests.
    //
    // If a feature is integrated in the fieldtrial_testing_config.json,
    // it might not be considered under an official build. Adding it under the
    // InitWithFeatures below, to activate it, will solve that difference.

    // clang-format off
    feature_list_.InitWithFeatures(
        {
#if !BUILDFLAG(IS_ANDROID)
          features::kInitialWebUI,
          features::kWebUIReloadButton,
#endif  // !BUILDFLAG(IS_ANDROID)
          features::kTrustSafetySentimentSurvey,
#if BUILDFLAG(IS_WIN)
          switches::kEnableBoundSessionCredentials,
#endif  // BUILDFLAG(IS_WIN)
          network::features::kBrowsingTopics,
          extensions_features::kForceWebRequestProxyForTest,
          network::features::kReduceAcceptLanguage,
          features::kMainNodeAnnotations,
          omnibox::kOnDeviceTailModel,
          omnibox::kOnDeviceHeadProviderNonIncognito,
          switches::kSyncEnableBookmarksInTransportMode,
          contextual_tasks::kContextualTasks,
        },
        {});
    // clang-format on
  }

 private:
  // TODO(https://crbug.com/423465927): Explore a better approach to make the
  // existing tests run with the prewarm feature enabled.
  test::ScopedPrewarmFeatureList prewarm_feature_list_{
      test::ScopedPrewarmFeatureList::PrewarmState::kDisabled};
  base::test::ScopedFeatureList feature_list_;
};

#if !BUILDFLAG(IS_CHROMEOS)
// System Profile does not exist on ChromeOS.
IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
                       SystemProfileOTR_NeededServices) {
  Profile* system_profile =
      CreateProfileAndWaitForAllTasks(ProfileManager::GetSystemProfilePath());
  ASSERT_TRUE(system_profile->HasAnyOffTheRecordProfile());
  Profile* system_profile_otr = system_profile->GetPrimaryOTRProfile(false);
  ASSERT_TRUE(system_profile_otr->IsOffTheRecord());
  ASSERT_TRUE(system_profile_otr->IsSystemProfile());
  TestKeyedProfileServicesActives(system_profile_otr,
                                  /*expected_active_services_names=*/{});
}

IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
                       SystemProfileParent_NeededServices) {
  Profile* system_profile =
      CreateProfileAndWaitForAllTasks(ProfileManager::GetSystemProfilePath());
  ASSERT_FALSE(system_profile->IsOffTheRecord());
  ASSERT_TRUE(system_profile->IsSystemProfile());
  TestKeyedProfileServicesActives(system_profile,
                                  /*expected_active_services_names=*/{});
}

IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
                       SystemProfileParent_ServicesThatCanBeCreated) {
  Profile* system_profile =
      CreateProfileAndWaitForAllTasks(ProfileManager::GetSystemProfilePath());
  ASSERT_FALSE(system_profile->IsOffTheRecord());
  ASSERT_TRUE(system_profile->IsSystemProfile());

  // clang-format off
  std::set<std::string> expected_created_services_names = {
    // in components:
    // There is no control over the creation based on the Profile types in
    // components/. These services are not created for the System Profile by
    // default, however their creation is still possible.
    "AutocompleteControllerEmitter",
    "AutofillInternalsService",
    "DataControlsRulesService",
    "HasEnrolledInstrumentQuery",
    "LocalPresentationManager",
    "OmniboxInputWatcher",
    "OmniboxSuggestionsWatcher",
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || \
    BUILDFLAG(IS_CHROMEOS)
    "PasswordManagerBlocklist",
#endif
    "PasswordManagerInternalsService",
    "PasswordRequirementsServiceFactory",
    "PolicyClipboardRestriction",
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
    "ReportingEventRouter",
#endif  // BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
    "SafeSearch",
    "WebDataService",

    // in chrome: using `BrowserContextKeyedServiceShutdownNotifierFactory`:
    // which does not yet have an implementation using `ProfileSelections`.
    "BrowserManagerService",
    "ExtensionKeybindingRegistryShutdownNotifierFactory",
#if BUILDFLAG(IS_CHROMEOS)
    "GalleryWatchManager",
    "MediaFileSystemRegistry",
#endif
    "NotificationDisplayService",
    "PermissionsUpdaterShutdownFactory",
    "PluginInfoHostImpl",
    "TurnSyncOnHelperShutdownNotifier",
    "WebRequestProxyingWebTransport",

    // This service is needed to handle navigations in the Profile Picker.
    "ChromePolicyBlocklistService",

    "ProfileMetricsService",
  };
  // clang-format on

  TestKeyedProfileServicesActives(system_profile,
                                  expected_created_services_names,
                                  /*force_create_services=*/true);
}

IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceBrowserTest,
                       SystemProfileOTR_ServicesThatCanBeCreated) {
  Profile* system_profile =
      CreateProfileAndWaitForAllTasks(ProfileManager::GetSystemProfilePath());
  ASSERT_TRUE(system_profile->HasAnyOffTheRecordProfile());
  Profile* system_profile_otr = system_profile->GetPrimaryOTRProfile(false);
  ASSERT_TRUE(system_profile_otr->IsOffTheRecord());
  ASSERT_TRUE(system_profile_otr->IsSystemProfile());

  // clang-format off
  std::set<std::string> exepcted_created_services_names = {
    // in components:
    // There is no control over the creation based on the Profile types in
    // components/. These services are not created for the System Profile by
    // default, however their creation is still possible.
    "AutocompleteControllerEmitter",
    "DataControlsRulesService",
    "HasEnrolledInstrumentQuery",
    "OmniboxInputWatcher",
    "OmniboxSuggestionsWatcher",
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || \
    BUILDFLAG(IS_CHROMEOS)
    "PasswordManagerBlocklist",
#endif
    "PolicyClipboardRestriction",
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
    "ReportingEventRouter",
#endif  // BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
    "SafeSearch",

    // in chrome: using `BrowserContextKeyedServiceShutdownNotifierFactory`:
    // which does not yet have an implementation using `ProfileSelections`.
    "BrowserManagerService",
    "ExtensionKeybindingRegistryShutdownNotifierFactory",
#if BUILDFLAG(IS_CHROMEOS)
    "GalleryWatchManager",
    "MediaFileSystemRegistry",
#endif
    "NotificationDisplayService",
    "PermissionsUpdaterShutdownFactory",
    "PluginInfoHostImpl",
    "TurnSyncOnHelperShutdownNotifier",
    "WebRequestProxyingWebTransport",

    // Those services are needed to be able to display IPHs in the Profile
    // Picker.
    "feature_engagement::Tracker",
    "UserEducationService",

    // This service is needed to handle navigations in the Profile Picker.
    "ChromePolicyBlocklistService",

    "ProfileMetricsService",
  };
  // clang-format on

  TestKeyedProfileServicesActives(system_profile_otr,
                                  exepcted_created_services_names,
                                  /*force_create_services=*/true);
}

#endif  // !BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(IS_CHROMEOS)
class ProfileKeyedServiceGuestBrowserTest
    : public ProfileKeyedServiceBrowserTest {
 public:
  ProfileKeyedServiceGuestBrowserTest() {
    // TODO(crbug.com/452061489): Fix tests that fail when the WebUI Omnibox is
    // enabled and then remove this.
    scoped_feature_list_.InitWithFeatures(
        /*enabled_features=*/{},
        /*disabled_features=*/
        {omnibox::internal::kWebUIOmniboxPopup,
         omnibox::internal::kWebUIOmniboxAimPopup});
  }
  ~ProfileKeyedServiceGuestBrowserTest() override = default;

  // ProfileKeyedServiceBrowserTest:
  void SetUpCommandLine(base::CommandLine* command_line) override {
    command_line->AppendSwitch(ash::switches::kGuestSession);
    command_line->AppendSwitch(::switches::kIncognito);
    command_line->AppendSwitchASCII(ash::switches::kLoginProfile, "user");
    command_line->AppendSwitchASCII(
        ash::switches::kLoginUser,
        user_manager::GuestAccountId().GetUserEmail());
  }

 private:
  base::test::ScopedFeatureList scoped_feature_list_;
};
#else
class ProfileKeyedServiceGuestBrowserTest
    : public ProfileKeyedServiceBrowserTest {
 public:
  ProfileKeyedServiceGuestBrowserTest() {
    // TODO(crbug.com/452061489): Fix tests that fail when the WebUI Omnibox is
    // enabled and then remove this.
    scoped_feature_list_.InitWithFeatures(
        /*enabled_features=*/{},
        /*disabled_features=*/{omnibox::internal::kWebUIOmniboxPopup,
                               omnibox::internal::kWebUIOmniboxAimPopup});
  }
  ~ProfileKeyedServiceGuestBrowserTest() override = default;

 private:
  base::test::ScopedFeatureList scoped_feature_list_;
};
#endif

IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceGuestBrowserTest,
                       GuestProfileOTR_NeededServices) {
  // clang-format off
  std::set<std::string> guest_otr_active_services {
    "AlarmManager",
    "AXMainNodeAnnotatorController",
    "AutocompleteActionPredictor",
    "AutocompleteClassifier",
    "AutocompleteControllerEmitter",
    "BackgroundContentsService",
    "BackgroundSyncService",
#if BUILDFLAG(IS_CHROMEOS)
    "BluetoothApiAdvertisementManager",
    "BluetoothApiSocketManager",
    "BluetoothLowEnergyConnectionManager",
    "BluetoothLowEnergyNotifySessionManager",
    "BluetoothSocketEventDispatcher",
#endif  // BUILDFLAG(IS_CHROMEOS)
    "BrowserManagerService",
    "BrowsingDataLifetimeManager",

    "ContextualSearchService",
    "ContextualTasksService",
    "ContextualTasksUiService",
    "CookieSettings",
#if BUILDFLAG(IS_WIN)
    "BoundSessionCookieRefreshService",
#endif  // BUILDFLAG(IS_WIN)
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
    "ExtensionInstallEventRouter",
#endif  // BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
    "ChromeEnterpriseRealTimeUrlLookupService",
#if !BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(IS_CHROMEOS)
    "AshPolicyBlocklistService",
#else
    "ChromePolicyBlocklistService",
#endif  // !BUILDFLAG(IS_CHROMEOS)
#endif  // !BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(IS_CHROMEOS)
    "ComponentExtensionContentSettingsAllowlist",
#endif
    "DeveloperToolsPolicyChecker",
    "EnterpriseReportingPrivateEventRouter",
    "ExtensionKeybindingRegistryShutdownNotifierFactory",
    "ExtensionNavigationRegistry",
    "ExtensionSystem",
    "ExtensionProtocolShutdownNotifierFactory",
    "FederatedIdentityPermissionContext",
    "FederatedIdentityAutoReauthnPermissionContext",
    "FeedbackPrivateAPI",
    "FileSystemAccessPermissionContext",
    "GeneratedPrefs",
    "HeavyAdService",
#if BUILDFLAG(ENABLE_EXTENSIONS)
    "HidConnectionResourceManager",
#endif
    "HidDeviceManager",
    "HostContentSettingsMap",
    "LiveCaptionController",
#if !BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946): Investigate if this is necessary on CrOS.
    "LiveTranslateController",
#endif  // !BUILDFLAG(IS_CHROMEOS)

    "MediaRouter",
    "MediaRouterUIService",
    "NotificationDisplayService",
    "OnDeviceTailModelService",
    "OneTimePermissionsTrackerKeyedService",
    "OptimizationGuideGlobalStateHolderKeyedService",
    "OptimizationGuideKeyedService",
    "PermissionDecisionAutoBlocker",
    "PinnedToolbarActionsModel",
    "PlatformNotificationService",
    "PredictionModelHandlerProvider",
    "PrefWatcher",
    "PrivacySandboxSettings",
    "ProcessManager",
    "ProfileNetworkContextService",
    "ProtocolHandlersManager",
    "ProtocolHandlerRegistry",
    "ReadAnythingServiceFactory",
    "RealtimeReportingClient",
    "ReduceAcceptLanguage",
    "RendererUpdater",
    "ResumableTCPServerSocketManager",
    "ResumableTCPSocketManager",
    "ResumableUDPSocketManager",
    "RulesRegistryService",
    "SafeBrowsingPrivateEventRouter",

#if BUILDFLAG(IS_CHROMEOS)
    "SerialConnectionManager",
    "SerialPortManager",
#endif
    "SettingsPrivateEventRouter",
    "SiteDataCacheFacadeFactory",
    "SiteEngagementService",
    "SocketManager",
    "StorageNotificationService",
    "TCPServerSocketEventDispatcher",
    "TCPSocketEventDispatcher",
    "TabGroupsEventRouter",
    "ToolbarActionsModel",
    "UDPSocketEventDispatcher",
    "UkmBackgroundRecorderService",
#if BUILDFLAG(IS_WIN)
    "UnexportableKeyService",
#endif  // BUILDFLAG(IS_WIN)
    "UsbDeviceManager",
    "UsbDeviceResourceManager",
#if !BUILDFLAG(IS_ANDROID)
    "WaapUIMetricsService",
#endif  // !BUILDFLAG(IS_ANDROID)
    "sct_reporting::Factory",

    "BtmBrowserSigninDetector",
    "ClientHints",
    "ConnectorsService",
    "DataControlsRulesService",
#if !BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946): This is most likely unnesssary on CrOS because
    // it has its own UI, but factory is created, which should probably be
    // removed.
    "DownloadBubbleUpdateService",
#endif
    "EnterpriseManagementService",
    "FindBarState",
    "HistoryClustersService",
    "InstantService",
    "LanguageDetectionModelService",
    "MediaEngagementServiceFactory",
    "MediaNotificationService",
    "NoStatePrefetchManager",
#if !BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946): Investigate if this is necessary on CrOS.
    "OfflineItemModelManager",
#endif
    "OmniboxInputWatcher",
    "PermissionManagerFactory",
    "SafeBrowsingNavigationObserverManager",
    "StatefulSSLHostStateDelegate",
    "StorageAccessAPIService",
    "SubresourceFilterProfileContext",
    "V5GetHashProtocolManager",
    "V5SearchHashesCache",
    "VerdictCacheManager",
    "WebRequestProxyingURLLoaderFactory",
    "captive_portal::CaptivePortalService",

#if BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946):
    // Verify these are necessary: then reorder or remove.

    "AppListSyncableService",
    "AppServiceProxy",
    "CupsPrintersManagerFactory",
    "DownloadCoreService",
    "EventRouter",
    "FileChangeService",
    "FileSuggestKeyedService",
    "HoldingSpaceService",
    "LogSourceResource",
    "PolicyCertService",
    "PrimaryProfileServices",
    "PrinterEventTracker",
    "SharesheetService",
    "SupervisedUserUrlFilteringService",
    "SystemWebAppManager",
    "VirtualKeyboardAPI",
    "VolumeManagerFactory",
    "WebAppProvider",
#endif  // BUILDFLAG(IS_CHROMEOS)
  };
  // clang-format on
  if (SearchEnginePreconnector::ShouldBeEnabledAsKeyedService() &&
      SearchEnginePreconnector::ShouldBeEnabledForOffTheRecord()) {
    guest_otr_active_services.insert("SearchEnginePreconnector");
  }
  if (base::FeatureList::IsEnabled(
          omnibox::kAimEligibilityComponentExtension)) {
    guest_otr_active_services.insert("AimEligibilityExtensionBridge");
    guest_otr_active_services.insert("ExtensionMojoBinderRegistry");
  }

  // On ChromeOS, Guest session startup navigates to chrome://newtab (a WebUI)
  // by default, whereas Desktop CreateGuestBrowser() navigates to about:blank.
  // Loading a WebUI initializes the embedded WebUI toolbar
  // (WebUIToolbarWebView), which opts into V2 resource loading and
  // instantiates ThemeColorsSourceManager for the Guest OTR profile.
  if (base::FeatureList::IsEnabled(
          features::kWebUIInProcessResourceLoadingV2)) {
    guest_otr_active_services.insert("ThemeColorsSourceManager");
  }

#if BUILDFLAG(IS_CHROMEOS)
  EXPECT_TRUE(user_manager::UserManager::Get()->IsLoggedInAsGuest());
  // ChromeOS Guest mode starts with the guest otr profile.
  Profile* guest_otr_profile = browser()->GetProfile();
  // Some key services are created asynchronosly. Wait util they're ready.
#else
  BrowserWindowInterface* guest_browser = CreateGuestBrowser();
  Profile* guest_otr_profile = guest_browser->GetProfile();
#endif  // BUILDFLAG(IS_CHROMEOS)
  content::RunAllTasksUntilIdle();

  ASSERT_FALSE(guest_otr_profile->IsRegularProfile());
  ASSERT_TRUE(guest_otr_profile->IsOffTheRecord());
  ASSERT_TRUE(guest_otr_profile->IsGuestSession());
  TestKeyedProfileServicesActives(guest_otr_profile, guest_otr_active_services);
}

IN_PROC_BROWSER_TEST_F(ProfileKeyedServiceGuestBrowserTest,
                       GuestProfileParent_NeededServices) {
  // clang-format off
  std::set<std::string> guest_active_services {
    "AccountBookmarkSyncServiceFactory",
    "AccountExtensionTracker",
    "ActivityLog",
    "ActivityLogPrivateAPI",
    "AdvancedProtectionStatusManager",
    "AiModeButtonService",
    "AimEligibilityService",
    "AlarmManager",
    "AnnouncementNotificationService",
    "AppLifetimeMonitor",
    "AppLoadService",
    "AppRestoreService",
#if !BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946): Investigate if this is necessary on CrOS.
    "AppServiceProxy",
#endif  // !BUILDFLAG(IS_CHROMEOS)
    "AppSessionService",
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
    "AppShortcutManager",
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)|| BUILDFLAG(IS_WIN)
    "ManualTestHeartbeatEvent",
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)|| BUILDFLAG(IS_WIN)
    "AppTerminationObserver",
    "AppWindowRegistry",
    "AudioAPI",
    "AutocompleteActionPredictor",
    "AutocompleteHistoryManager",
    "AutocompleteScoringModelService",
    "AutofillClientProvider",
    "AutofillImageFetcher",
    "AutofillPrivateEventRouter",
    "AutofillStrikeDatabase",
    "BackgroundContentsService",
    "BackgroundSyncService",
    "Blocklist",
#if BUILDFLAG(IS_CHROMEOS)
    "BluetoothAPI",
    "BluetoothApiSocketManager",
    "BluetoothApiAdvertisementManager",
    "BluetoothLowEnergyAPI",
    "BluetoothLowEnergyConnectionManager",
    "BluetoothLowEnergyNotifySessionManager",
    "BluetoothPrivateAPI",
    "BluetoothSocketEventDispatcher",
#endif  // BUILDFLAG(IS_CHROMEOS)
    "BookmarkManagerPrivateAPI",
#if defined(TOOLKIT_VIEWS)
    "BookmarkExpandedStateTracker",
    "BookmarkMergedSurfaceService",
#endif
    "BookmarkModel",
    "BookmarkUndoService",
    "BookmarksAPI",
    "BrailleDisplayPrivateAPI",
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
    "BrowserBoundKeyDeleterService",
#endif
    "ChildAccountService",
    "ChromeSigninClient",
    "CommandService",
#if BUILDFLAG(IS_CHROMEOS)
    "ComponentExtensionContentSettingsAllowlist",
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
    "ComponentLoader",
#endif
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
    "ConnectorsService",
#endif  // BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
    "ContentIndexProvider",
    "ContentSettingsService",
    "ContextualTasksService",
    "ContextualTasksUiService",
    "CookieSettings",
    "CookiesAPI",
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
    "CorruptedExtensionReinstaller",
#endif
    "CWSInfoService",
    "DataTypeStoreService",
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
    "DelayedInstallManager",
#endif
    "DeveloperPrivateAPI",
#if !BUILDFLAG(IS_CHROMEOS)
    "DownloadCoreService",
#endif
    "EventRouter",
    "ExtensionActionDispatcher",
    "ExtensionActionManager",
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
    "ExtensionAllowlist",
#endif
    "ExtensionCommandsGlobalRegistry",
    "ExtensionErrorController",
    "ExtensionGCMAppHandler",
    "ExtensionGarbageCollector",
    "ExtensionHostRegistry",
#if BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
    "ExtensionInstallEventRouter",
#endif  // BUILDFLAG(ENTERPRISE_CONTENT_ANALYSIS)
    "ExtensionKeybindingRegistryShutdownNotifierFactory",
    "ExtensionManagement",
    "ExtensionNavigationRegistry",
    "ExtensionPrefValueMap",
    "ExtensionPrefs",
    "ExtensionRegistrar",
    "ExtensionRegistry",
    "ExtensionSyncService",
    "ExtensionSystem",
    "ExtensionSystemShared",
    "ExtensionUpdater",
    "ExtensionProtocolShutdownNotifierFactory",
    "ExtensionUrlOverridesRegistrar",
    "ExternalInstallManager",
  #if BUILDFLAG(ENABLE_EXTENSIONS)
    "ExternalProviderManager",
  #endif
    "FaviconService",
    "FederatedIdentityPermissionContext",
    "FederatedIdentityAutoReauthnPermissionContext",
    "FeedbackPrivateAPI",
    "FileSystemAccessPermissionContext",
    "FirstPartySetsPolicyService",
    "FontPrefChangeNotifier",
    "FontSettingsAPI",
#if !BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946): Investigate if this is necessary on CrOS.
    "GAIAInfoUpdateService",
#endif  // !BUILDFLAG(IS_CHROMEOS)
    "GCMProfileService",
    "GeneratedPrefs",
    "GlobalErrorService",
    "HeavyAdService",
#if BUILDFLAG(ENABLE_EXTENSIONS)
    "HidConnectionResourceManager",
#endif
    "HidDeviceManager",
    "HistoryAPI",
    "HistoryService",
    "HostContentSettingsMap",
    "HttpEngagementKeyService",
    "IdentityAPI",
    "IdentityManager",
    "IdleManager",
    "InMemoryURLIndex",
    "InstallStageTracker",
    "InstallTracker",
    "InstallVerifier",
    "InstanceIDProfileService",
#if !BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946): Investigate if this is necessary on CrOS.
    "InvalidationService",
#endif
    "LanguageModelManager",
    "LanguageSettingsPrivateDelegate",
    "LazyBackgroundTaskQueue",
    "ListFamilyMembersService",
    "LocalOrSyncableBookmarkSyncServiceFactory",
    "LoginDetectionKeyedService",
    "LoginUIServiceFactory",
    "MDnsAPI",
    "ManagedBookmarkService",
    "ManagedConfigurationAPI",
    "ManagementAPI",
#if BUILDFLAG(ENABLE_EXTENSIONS)
    "ManifestV2Handler",
#endif
#if BUILDFLAG(IS_CHROMEOS)
    "MediaGalleriesAPI",
#endif
    "MediaRouter",
    "MediaRouterUIService",
    "MenuManager",

    "NavigationPredictorKeyedService",
    "NetworkingPrivateEventRouter",
    "NotificationDisplayService",
    "NtpBackgroundService",
    "NtpCustomBackgroundService",
#if BUILDFLAG(IS_CHROMEOS)
    "NssServiceFactory",
#endif // BUILDFLAG(IS_CHROMEOS)
    "OmniboxAPI",
    "OmniboxSuggestionsWatcher",
    "OnDeviceTailModelService",
    "OneTimePermissionsTrackerKeyedService",
    "OperationManager",
    "OptimizationGuideGlobalStateHolderKeyedService",
    "OptimizationGuideKeyedService",
#if !BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946): Investigate if this is necessary on CrOS.
    "PageContentAnnotationsService",
#endif  // !BUILDFLAG(IS_CHROMEOS)
    "PasswordsPrivateEventRouter",
    "PendingExtensionManager",
    "PermissionDecisionAutoBlocker",
    "PermissionHelper",
#if BUILDFLAG(ENABLE_EXTENSIONS)
    "PermissionsEventRouter",
#endif
    "PermissionsManager",
    "PermissionsUpdaterShutdownFactory",
    "PersonalDataManager",
    "PinnedTabService",
    "PinnedToolbarActionsModel",
    "PlatformNotificationService",
    "PluginManager",
    "PluginPrefs",
    "PowerBookmarkService",
    "PredictionModelHandlerProvider",
    "PredictorDatabase",
    "PrefWatcher",
    "PreferenceAPI",
    "PrinterProviderInternal",
    "PrivacySandboxService",
    "PrivacySandboxSettings",
    "ProcessManager",
    "ProcessMap",
    "ProcessesAPI",
    "ProfileMetricsService",
    "ProfileNetworkContextService",
#if BUILDFLAG(ENABLE_EXTENSIONS)
    "ProtocolHandlersManager",
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
    "ProtocolHandlerRegistry",
    "RealtimeReportingClient",
    "RegionalCapabilitiesService",
    "RendererStartupHelper",
    "RendererUpdater",
    "ResumableTCPServerSocketManager",
    "ResumableTCPSocketManager",
    "ResumableUDPSocketManager",
    "RulesMonitorService",
    "RulesRegistryService",
    "RuntimeAPI",
    "SafeBrowsingMetricsCollector",
    "SafeBrowsingNetworkContextService",

    "SafeBrowsingPrivateEventRouter",
    "SafeBrowsingTailoredSecurityService",
    "SearchEngineChoiceServiceFactory",
#if BUILDFLAG(IS_CHROMEOS)
    "SerialConnectionManager",
    "SerialPortManager",
#endif
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
    "ServerCertificateDatabaseService",
#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
    "SessionDataService",
    "SessionProtoDBFactory",
    "SessionsAPI",
    "sessions::TabRestoreService",
    "SettingsOverridesAPI",
    "SettingsPrivateEventRouter",
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
    "SharedModuleService",
#endif
    "ShoppingService",
    "SidePanelService",
    "SiteDataCacheFacadeFactory",
    "SiteEngagementService",
    "SocketManager",
#if !BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946): Desktop chrome create this via
    // ShoppingService->SyncService->Spellchecker. Investigate if this is
    // expected on desktop chrome.
    "SpellcheckService",
#endif
    "StorageFrontend",
    "StorageNotificationService",
    "SystemInfoAPI",
    "TCPServerSocketEventDispatcher",
    "TCPSocketEventDispatcher",
    "TabGroupsEventRouter",
    "TabsWindowsAPI",
    "TemplateURLPrepopulateDataResolver",
    "TemplateURLServiceFactory",
    "ThemeService",
    "ToolbarActionsModel",
    "TranslateRanker",
    "TriggeredProfileResetter",
    "TtsAPI",
    "UDPSocketEventDispatcher",
    "UkmBackgroundRecorderService",
    "UsbDeviceManager",
    "UsbDeviceResourceManager",
#if !BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946): Investigate if this is necessary on CrOS.
    "UserCloudPolicyInvalidator",
    "UserFmRegistrationTokenUploader",
    "UserPolicySigninService",
#endif  // !BUILDFLAG(IS_CHROMEOS)
    "UserScriptWorldConfigurationManager",
    "WarningBadgeService",
    "WarningService",
#if !BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946): Investigate if this is necessary on CrOS.
    "WebAppProvider",
#endif  // !BUILDFLAG(IS_CHROMEOS)
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX)
    "WebAuthenticationProxyAPI",
#endif
#if BUILDFLAG(IS_CHROMEOS)
    "WebcamPrivateAPI",
#endif  // BUILDFLAG(IS_CHROMEOS)
    "WebDataService",
    "WebNavigationAPI",
    "WebRequestAPI",
    "WebRequestEventRouter",
    "WebRtcEventLogManagerKeyedService",
    "WriteQuotaChecker",
    "feedback::FeedbackUploaderChrome",
    "sct_reporting::Factory",
#if !BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946): Investigate if this is necessary on CrOS.
    "ZeroSuggestCacheServiceFactory",
#endif  // !BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(IS_CHROMEOS)
    // TODO(crbug.com/374351946):
    // Verify these are necessary: then reorder or remove.

    "AccountManagerPolicyController",
    "ArcAppsPrivateAPI",
    "AuthTokenValidatorFactory",
    "AutotestPrivateAPI",
    "CastMediaNotificationProducerKeyedService",
    "ClientAppMetadataProviderService",
    "ClipboardAPI",
    "CrostiniMetricsService",
    "CupsPrintJobManagerFactory",
    "DebugLogsManagerFactory",
    "DeviceSyncClient",
    "DriveIntegrationService",
    "EasyUnlockService",
    "InputImeAPI",
    "InputMethodAPI",
    "KcerFactoryAsh",
    "LogSourceResource",
    "LorgnetteScannerManager",
    "MediaNotificationService",
    "MediaPerceptionAPIManager",
    "MediaPlayerAPI",
    "MultiDeviceSetupClient",
    "MultiDeviceSetupService",
    "NearbyConnector",
    "NearbyProcessManager",
    "OAuth2LoginManager",
    "OobeCompletionTrackerFactory",
    "OwnerSettingsService",
    "Pkcs12Migrator",
    "PlatformKeysService",
    "PolicyCertService",
    "PrintJobHistoryService",
    "PrintJobReportingServiceFactory",
    "PrintingManager",
    "Service",
    "SessionStateChangedEventDispatcher",
    "SmbService",
    "SyncedPrintersManager",
    "TerminalPrivateAPI",
    "TtsEngineExtensionObserverChromeOS",
    "UserNetworkConfigurationUpdater",
    "UserPrivateTokenKeyPermissionsManagerService",
    "VirtualKeyboardAPI",
    "VolumeManagerFactory",
    "VpnService",
#endif // BUILDFLAG(IS_CHROMEOS)
  };
  // clang-format on

  if (SearchEnginePreconnector::ShouldBeEnabledAsKeyedService()) {
    guest_active_services.insert("SearchEnginePreconnector");
  }
  if (base::FeatureList::IsEnabled(
          omnibox::kAimEligibilityComponentExtension)) {
    guest_active_services.insert("AimEligibilityExtensionBridge");
    guest_active_services.insert("ExtensionMojoBinderRegistry");
  }
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)
  if (base::FeatureList::IsEnabled(
          policy::features::kEnableExtensionInstallPolicyFetching)) {
    guest_active_services.insert("ExtensionInstallPolicyService");
  }
#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
  if (base::FeatureList::IsEnabled(
          universal_optout::features::kUniversalOptOut)) {
    guest_active_services.insert("UniversalOptOutService");
  }
#if BUILDFLAG(IS_CHROMEOS)
  EXPECT_TRUE(user_manager::UserManager::Get()->IsLoggedInAsGuest());
  // ChromeOS Guest mode starts with the guest otr profile.
  Profile* guest_otr_profile = browser()->GetProfile();
  Profile* guest_parent_profile = guest_otr_profile->GetOriginalProfile();
  // Some key services are created asynchronosly. Wait util they're ready.
#else
  BrowserWindowInterface* guest_browser = CreateGuestBrowser();
  Profile* guest_parent_profile =
      guest_browser->GetProfile()->GetOriginalProfile();
#endif  // BUILDFLAG(IS_CHROMEOS)
  content::RunAllTasksUntilIdle();

  ASSERT_FALSE(guest_parent_profile->IsRegularProfile());
  ASSERT_FALSE(guest_parent_profile->IsOffTheRecord());
  ASSERT_TRUE(guest_parent_profile->IsGuestSession());
  TestKeyedProfileServicesActives(guest_parent_profile, guest_active_services);
}
