blob: 7744f81a4e8487f1013d3402cf59a4fda1b4cddd [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/glic/test_support/glic_test_util.h"
#include "base/task/current_thread.h"
#include "chrome/browser/glic/glic_pref_names.h"
#include "chrome/browser/glic/public/glic_keyed_service.h"
#include "chrome/browser/glic/service/glic_instance_coordinator_impl.h"
#include "chrome/browser/glic/widget/glic_window_controller.h"
#include "chrome/browser/glic/widget/local_hotkey_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface_iterator.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/account_capabilities_test_mutator.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace glic {
namespace {
GlicInstanceCoordinatorImpl& GetInstanceCoordinator(GlicKeyedService& service) {
CHECK(base::FeatureList::IsEnabled(features::kGlicMultiInstance));
return static_cast<GlicInstanceCoordinatorImpl&>(service.window_controller());
}
} // namespace
BrowserActivator::BrowserActivator() {
BrowserList::AddObserver(this);
}
BrowserActivator::~BrowserActivator() {
BrowserList::RemoveObserver(this);
}
void BrowserActivator::SetMode(Mode mode) {
mode_ = mode;
}
void BrowserActivator::OnBrowserAdded(Browser* browser) {
switch (mode_) {
case Mode::kSingleBrowser:
CHECK(!active_browser_) << "BrowserActivator::kSingleBrowser found "
"second active browser.";
break;
case Mode::kFirst:
if (active_browser_) {
return;
}
break;
case Mode::kManual:
return;
}
SetActivePrivate(browser);
}
void BrowserActivator::OnBrowserRemoved(Browser* browser) {
if (active_browser_.get() == browser || active_browser_.WasInvalidated()) {
active_lock_.reset();
if (mode_ == Mode::kFirst) {
if (auto* const browser_window_interface =
GetLastActiveBrowserWindowInterfaceWithAnyProfile()) {
SetActivePrivate(browser_window_interface);
}
}
}
}
void BrowserActivator::SetActive(Browser* browser) {
mode_ = Mode::kManual;
if (!browser) {
active_lock_.reset();
active_browser_ = nullptr;
} else {
SetActivePrivate(browser);
}
}
void BrowserActivator::SetActivePrivate(
BrowserWindowInterface* browser_window_interface) {
CHECK(browser_window_interface);
if (auto* const browser_view =
BrowserView::GetBrowserViewForBrowser(browser_window_interface)) {
active_lock_ = browser_view->GetWidget()->LockPaintAsActive();
active_browser_ = browser_window_interface->GetWeakPtr();
}
}
GlicInstanceTracker::GlicInstanceTracker(Profile* profile)
: profile_(profile) {}
GlicInstanceTracker::~GlicInstanceTracker() = default;
void GlicInstanceTracker::SetProfile(Profile* profile) {
profile_ = profile;
}
Host* GlicInstanceTracker::GetHost() {
auto* instance = GetGlicInstance();
if (!instance) {
return nullptr;
}
return &instance->host();
}
GlicInstance* GlicInstanceTracker::GetGlicInstance() {
if (!profile_) {
return nullptr;
}
auto* service = GlicKeyedService::Get(profile_);
if (!service) {
return nullptr;
}
if (tracked_instance_id_) {
for (GlicInstance* instance : service->window_controller().GetInstances()) {
if (instance->id() == *tracked_instance_id_) {
return instance;
}
}
return nullptr;
}
if (base::FeatureList::IsEnabled(features::kGlicMultiInstance)) {
if (track_floating_glic_instance_) {
return GetInstanceCoordinator(*service).GetInstanceWithFloaty();
}
if (glic_instance_tab_handle_) {
if (glic_instance_tab_handle_->Get()) {
return service->GetInstanceForTab(glic_instance_tab_handle_->Get());
}
return nullptr;
}
if (glic_instance_tab_index_ != std::nullopt) {
return service->GetInstanceForTab(
GetBrowser()->GetTabStripModel()->GetTabAtIndex(
*glic_instance_tab_index_));
}
return service->GetInstanceForTab(
GetBrowser()->GetTabStripModel()->GetTabAtIndex(0));
}
return service->GetInstanceForActiveTab(GetBrowser());
}
BrowserWindowInterface* GlicInstanceTracker::GetBrowser() {
BrowserWindowInterface* found = nullptr;
ForEachCurrentBrowserWindowInterfaceOrderedByActivation(
[this, &found](BrowserWindowInterface* browser) {
if (browser->GetProfile() == profile_) {
found = browser;
}
return !found;
});
return found;
}
std::string GlicInstanceTracker::DescribeGlicTracking() {
if (tracked_instance_id_) {
return base::StrCat({"Tracking glic instance with id ",
tracked_instance_id_->AsLowercaseString()});
} else if (glic_instance_tab_index_) {
return base::StrCat({"Tracking glic instance at tab index ",
base::NumberToString(*glic_instance_tab_index_)});
} else if (glic_instance_tab_handle_) {
if (!glic_instance_tab_handle_->Get()) {
return "Tracking glic instance with INVALID tab handle";
}
return "Tracking glic instance with tab handle";
} else if (track_floating_glic_instance_) {
return "Tracking floating glic instance";
}
NOTREACHED();
}
void GlicInstanceTracker::Clear() {
tracked_instance_id_ = std::nullopt;
glic_instance_tab_index_ = std::nullopt;
glic_instance_tab_handle_ = std::nullopt;
track_floating_glic_instance_ = false;
}
[[nodiscard]] bool GlicInstanceTracker::WaitForPanelState(
mojom::PanelStateKind state) {
// TODO(harringtond): Use observers instead of polling.
return base::test::RunUntil([&]() {
auto* instance = GetGlicInstance();
if (!instance) {
return false;
}
return instance->GetPanelState().kind == state;
});
}
[[nodiscard]] bool GlicInstanceTracker::WaitForShow() {
// TODO(harringtond): Use observers instead of polling.
return base::test::RunUntil([&]() {
auto* instance = GetGlicInstance();
if (!instance) {
return false;
}
return instance->IsShowing();
});
}
void ForceSigninAndModelExecutionCapability(Profile* profile) {
SetFRECompletion(profile, prefs::FreStatus::kCompleted);
SigninWithPrimaryAccount(profile);
SetModelExecutionCapability(profile, true);
}
void SigninWithPrimaryAccount(Profile* profile) {
// Sign-in and enable account capability.
auto* const identity_manager = IdentityManagerFactory::GetForProfile(profile);
auto account_info = signin::MakePrimaryAccountAvailable(
identity_manager, "glic-test@example.com", signin::ConsentLevel::kSignin);
ASSERT_FALSE(account_info.IsEmpty());
account_info.full_name = "Glic Testing";
account_info.given_name = "Glic";
signin::UpdateAccountInfoForAccount(identity_manager, account_info);
}
void SetModelExecutionCapability(Profile* profile, bool enabled) {
auto* const identity_manager = IdentityManagerFactory::GetForProfile(profile);
AccountInfo primary_account =
identity_manager->FindExtendedAccountInfoByAccountId(
identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin));
ASSERT_FALSE(primary_account.IsEmpty());
AccountCapabilitiesTestMutator mutator(&primary_account.capabilities);
mutator.set_can_use_model_execution_features(enabled);
signin::UpdateAccountInfoForAccount(identity_manager, primary_account);
}
void SetFRECompletion(Profile* profile, prefs::FreStatus fre_status) {
profile->GetPrefs()->SetInteger(prefs::kGlicCompletedFre,
static_cast<int>(fre_status));
}
void InvalidateAccount(Profile* profile) {
auto* const identity_manager = IdentityManagerFactory::GetForProfile(profile);
signin::UpdatePersistentErrorOfRefreshTokenForAccount(
identity_manager,
identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin),
GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
ASSERT_TRUE(
identity_manager->HasAccountWithRefreshTokenInPersistentErrorState(
identity_manager->GetPrimaryAccountId(
signin::ConsentLevel::kSignin)));
ASSERT_FALSE(
identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync));
ASSERT_TRUE(
identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin));
}
void ReauthAccount(Profile* profile) {
auto* const identity_manager = IdentityManagerFactory::GetForProfile(profile);
signin::UpdatePersistentErrorOfRefreshTokenForAccount(
identity_manager,
identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin),
GoogleServiceAuthError::AuthErrorNone());
}
} // namespace glic