// Copyright 2024 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/ui/ash/birch/birch_keyed_service.h"
#include <memory>
#include <optional>
#include "ash/birch/birch_item.h"
#include "ash/birch/birch_model.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/shell.h"
#include "ash/system/focus_mode/focus_mode_controller.h"
#include "ash/system/focus_mode/focus_mode_util.h"
#include "ash/system/focus_mode/sounds/focus_mode_sounds_controller.h"
#include "ash/system/video_conference/fake_video_conference_tray_controller.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "base/version_info/version_info.h"
#include "chrome/browser/ash/file_suggest/file_suggest_keyed_service.h"
#include "chrome/browser/ash/file_suggest/file_suggest_keyed_service_factory.h"
#include "chrome/browser/ash/file_suggest/file_suggest_test_util.h"
#include "chrome/browser/ash/file_suggest/mock_file_suggest_keyed_service.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/ash/release_notes/release_notes_storage.h"
#include "chrome/browser/favicon/favicon_service_factory.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/sync/send_tab_to_self_sync_service_factory.h"
#include "chrome/browser/sync/session_sync_service_factory.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/browser/ui/ash/birch/birch_file_suggest_provider.h"
#include "chrome/browser/ui/ash/birch/birch_keyed_service_factory.h"
#include "chrome/browser/ui/ash/birch/birch_lost_media_provider.h"
#include "chrome/browser/ui/ash/birch/birch_self_share_provider.h"
#include "chrome/browser/ui/ash/holding_space/scoped_test_mount_point.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "components/favicon/core/test/mock_favicon_service.h"
#include "components/send_tab_to_self/send_tab_to_self_entry.h"
#include "components/send_tab_to_self/send_tab_to_self_model.h"
#include "components/send_tab_to_self/target_device_info.h"
#include "components/send_tab_to_self/test_send_tab_to_self_model.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "components/sync/test/fake_data_type_controller_delegate.h"
#include "components/sync/test/test_sync_service.h"
#include "components/sync_device_info/device_info_util.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/sync_sessions/open_tabs_ui_delegate.h"
#include "components/sync_sessions/session_sync_service.h"
#include "components/sync_sessions/synced_session.h"
#include "components/user_manager/scoped_user_manager.h"
#include "services/media_session/public/cpp/test/test_media_controller.h"
#include "services/media_session/public/mojom/media_session.mojom-shared.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ash {
namespace {
constexpr char kSessionName1[] = "test_session_name 1";
constexpr char kSessionName2[] = "test_session_name 2";
constexpr char kSessionTag1[] = "SessionTag1";
constexpr char kSessionTag2[] = "SessionTag2";
constexpr char kExampleURL1[] = "http://www.example.com/1";
constexpr char kExampleURL2[] = "http://www.example.com/2";
constexpr char16_t kTabTitle1[] = u"Tab Title 1";
constexpr char16_t kTabTitle2[] = u"Tab Title 2";
constexpr char kTargetDeviceFullName[] = "Device_1";
constexpr char kTargetDeviceShortName[] = "Device_1";
constexpr char kTargetDeviceCacheGuid[] = "device_guid_1";
constexpr char kChromeSyncGuid[] = "Entry Guid";
constexpr char kChromeSyncDeviceName[] = "Device Name";
constexpr char kChromeSyncUrl[] = "https://www.example.com";
constexpr char16_t kSessionMetadataTitle[] = u"Media Title";
constexpr char16_t kSessionMetadataSourceTitle[] = u"youtube.com";
constexpr char16_t kSessionMetadataSourceTitleFull[] =
u"https://www.youtube.com";
constexpr char kMediaAppUrl[] = "https://meet.google.com";
constexpr char16_t kMediaAppTitle[] = u"Google Meet";
std::unique_ptr<sync_sessions::SyncedSession> CreateNewSession(
const std::string& session_name,
const std::string& session_tag,
syncer::DeviceInfo::FormFactor form_factor) {
auto session = std::make_unique<sync_sessions::SyncedSession>();
auto window = std::make_unique<sync_sessions::SyncedSessionWindow>();
auto tab = std::make_unique<sessions::SessionTab>();
session->SetSessionName(session_name);
session->SetDeviceTypeAndFormFactor(sync_pb::SyncEnums::TYPE_UNSET,
form_factor);
window->wrapped_window.tabs.push_back(std::move(tab));
session->windows[SessionID::NewUnique()] = std::move(window);
session->SetSessionTag(session_tag);
return session;
}
class MockSessionSyncService : public sync_sessions::SessionSyncService {
public:
MockSessionSyncService() = default;
~MockSessionSyncService() override = default;
MOCK_METHOD(syncer::GlobalIdMapper*,
GetGlobalIdMapper,
(),
(const, override));
MOCK_METHOD(sync_sessions::OpenTabsUIDelegate*,
GetOpenTabsUIDelegate,
(),
(override));
base::CallbackListSubscription SubscribeToForeignSessionsChanged(
const base::RepeatingClosure& cb) override {
return subscriber_list_.Add(cb);
}
MOCK_METHOD(base::WeakPtr<syncer::DataTypeControllerDelegate>,
GetControllerDelegate,
());
void NotifyMockForeignSessionsChanged() { subscriber_list_.Notify(); }
bool IsSubscribersEmpty() { return subscriber_list_.empty(); }
private:
base::RepeatingClosureList subscriber_list_;
};
class MockOpenTabsUIDelegate : public sync_sessions::OpenTabsUIDelegate {
public:
MockOpenTabsUIDelegate() {
foreign_sessions_owned_.push_back(CreateNewSession(
kSessionName1, kSessionTag1, syncer::DeviceInfo::FormFactor::kDesktop));
foreign_sessions_.push_back(foreign_sessions_owned_.back().get());
foreign_sessions_owned_.push_back(CreateNewSession(
kSessionName2, kSessionTag2, syncer::DeviceInfo::FormFactor::kPhone));
foreign_sessions_.push_back(foreign_sessions_owned_.back().get());
std::vector<std::unique_ptr<sessions::SessionTab>> session_tabs_one;
auto tab = std::make_unique<sessions::SessionTab>();
tab->timestamp = base::Time::Now();
tab->navigations.push_back(sessions::SerializedNavigationEntryTestHelper::
CreateNavigationForTest());
tab->navigations[0].set_timestamp(base::Time::Now());
tab->navigations[0].set_title(kTabTitle1);
tab->navigations[0].set_virtual_url(GURL(kExampleURL1));
session_tabs_one.push_back(std::move(tab));
std::vector<std::unique_ptr<sessions::SessionTab>> session_tabs_two;
tab = std::make_unique<sessions::SessionTab>();
tab->timestamp = base::Time::Now();
tab->navigations.push_back(sessions::SerializedNavigationEntryTestHelper::
CreateNavigationForTest());
tab->navigations[0].set_timestamp(base::Time::Now() + base::Minutes(5));
tab->navigations[0].set_title(kTabTitle2);
tab->navigations[0].set_virtual_url(GURL(kExampleURL2));
session_tabs_two.push_back(std::move(tab));
session_tabs_.emplace(kSessionTag1, std::move(session_tabs_one));
session_tabs_.emplace(kSessionTag2, std::move(session_tabs_two));
}
bool GetAllForeignSessions(
std::vector<raw_ptr<const sync_sessions::SyncedSession,
VectorExperimental>>* sessions) override {
*sessions = foreign_sessions_;
base::ranges::sort(*sessions, std::greater(),
[](const sync_sessions::SyncedSession* session) {
return session->GetModifiedTime();
});
return !sessions->empty();
}
MOCK_METHOD1(GetLocalSession,
bool(const sync_sessions::SyncedSession** local_session));
MOCK_METHOD3(GetForeignTab,
bool(const std::string& tag,
const SessionID tab_id,
const sessions::SessionTab** tab));
MOCK_METHOD1(DeleteForeignSession, void(const std::string& tag));
MOCK_METHOD1(
GetForeignSession,
std::vector<const sessions::SessionWindow*>(const std::string& tag));
bool GetForeignSessionTabs(
const std::string& tag,
std::vector<const sessions::SessionTab*>* tabs) override {
auto it = session_tabs_.find(tag);
if (it != session_tabs_.end()) {
for (auto& tab : it->second) {
tabs->push_back(tab.get());
}
}
return true;
}
private:
std::vector<std::unique_ptr<sync_sessions::SyncedSession>>
foreign_sessions_owned_;
std::vector<raw_ptr<const sync_sessions::SyncedSession, VectorExperimental>>
foreign_sessions_;
std::map<std::string, std::vector<std::unique_ptr<sessions::SessionTab>>>
session_tabs_;
};
std::unique_ptr<KeyedService> BuildMockSessionSyncService(
content::BrowserContext* context) {
return std::make_unique<testing::NiceMock<MockSessionSyncService>>();
}
std::unique_ptr<KeyedService> BuildTestSyncService(
content::BrowserContext* context) {
return std::make_unique<syncer::TestSyncService>();
}
class SendTabToSelfModelMock : public send_tab_to_self::TestSendTabToSelfModel {
public:
SendTabToSelfModelMock() = default;
~SendTabToSelfModelMock() override = default;
MOCK_METHOD1(DeleteEntry, void(const std::string&));
MOCK_METHOD1(DismissEntry, void(const std::string&));
send_tab_to_self::SendTabToSelfEntry* AddEntry(
const GURL& url,
const std::string& title,
const std::string& target_device_cache_guid) override {
auto entry = std::make_unique<send_tab_to_self::SendTabToSelfEntry>(
kChromeSyncGuid, url, title, base::Time::Now(), kChromeSyncDeviceName,
target_device_cache_guid);
auto* result = entry.get();
entries_.emplace(kChromeSyncGuid, std::move(entry));
return result;
}
const send_tab_to_self::SendTabToSelfEntry* GetEntryByGUID(
const std::string& guid) const override {
auto it = entries_.find(guid);
return it != entries_.end() ? it->second.get() : nullptr;
}
std::vector<std::string> GetAllGuids() const override {
std::vector<std::string> keys;
for (const auto& it : entries_) {
DCHECK_EQ(it.first, it.second->GetGUID());
keys.push_back(it.first);
}
return keys;
}
void MarkEntryOpened(const std::string& guid) override {
auto it = entries_.find(guid);
if (it != entries_.end()) {
if (auto* entry = it->second.get()) {
entry->MarkOpened();
}
}
}
std::vector<send_tab_to_self::TargetDeviceInfo>
GetTargetDeviceInfoSortedList() override {
return devices_;
}
void AddMockTargetDevice(syncer::DeviceInfo::FormFactor form_factor) {
devices_.emplace_back(kTargetDeviceFullName, kTargetDeviceShortName,
kTargetDeviceCacheGuid, form_factor,
base::Time::Now());
}
private:
std::map<std::string, std::unique_ptr<send_tab_to_self::SendTabToSelfEntry>>
entries_;
std::vector<send_tab_to_self::TargetDeviceInfo> devices_;
};
class TestSendTabToSelfSyncService
: public send_tab_to_self::SendTabToSelfSyncService {
public:
TestSendTabToSelfSyncService() : fake_delegate_(syncer::SEND_TAB_TO_SELF) {}
~TestSendTabToSelfSyncService() override = default;
send_tab_to_self::SendTabToSelfModel* GetSendTabToSelfModel() override {
return &model_mock_;
}
base::WeakPtr<syncer::DataTypeControllerDelegate> GetControllerDelegate()
override {
return fake_delegate_.GetWeakPtr();
}
protected:
syncer::FakeDataTypeControllerDelegate fake_delegate_;
SendTabToSelfModelMock model_mock_;
};
std::unique_ptr<KeyedService> BuildTestSendTabToSelfSyncService(
content::BrowserContext* context) {
return std::make_unique<TestSendTabToSelfSyncService>();
}
class FaviconServiceMock : public favicon::MockFaviconService {
public:
FaviconServiceMock() {
// This default implementation is provided to satisfy both actual
// functionality and the ability to set expectations in tests.
ON_CALL(*this,
GetLargestRawFaviconForPageURL(testing::_, testing::_, testing::_,
testing::_, testing::_))
.WillByDefault(testing::Invoke(
this, &FaviconServiceMock::DefaultGetLargestRawFaviconForPageURL));
ON_CALL(*this, GetRawFavicon(testing::_, testing::_, testing::_, testing::_,
testing::_))
.WillByDefault(
testing::Invoke(this, &FaviconServiceMock::DefaultGetRawFavicon));
}
~FaviconServiceMock() override = default;
FaviconServiceMock(const FaviconServiceMock&) = delete;
FaviconServiceMock& operator=(const FaviconServiceMock&) = delete;
private:
base::CancelableTaskTracker::TaskId DefaultGetLargestRawFaviconForPageURL(
const GURL& page_url,
const std::vector<favicon_base::IconTypeSet>& icon_types,
int minimum_size_in_pixels,
favicon_base::FaviconRawBitmapCallback callback,
base::CancelableTaskTracker* tracker) {
favicon_base::FaviconRawBitmapResult result;
std::move(callback).Run(result);
return base::CancelableTaskTracker::kBadTaskId;
}
base::CancelableTaskTracker::TaskId DefaultGetRawFavicon(
const GURL& icon_url,
const favicon_base::IconType& icon_type,
int desired_size_in_pixels,
favicon_base::FaviconRawBitmapCallback callback,
base::CancelableTaskTracker* tracker) {
favicon_base::FaviconRawBitmapResult result;
std::move(callback).Run(result);
return base::CancelableTaskTracker::kBadTaskId;
}
};
std::unique_ptr<KeyedService> BuildFaviconServiceMock(
content::BrowserContext* context) {
return std::make_unique<FaviconServiceMock>();
}
} // namespace
// TODO(https://crbug.com/1370774): move `ScopedTestMountPoint` out of holding
// space to remove the dependency on holding space code.
using ash::holding_space::ScopedTestMountPoint;
using media_session::test::TestMediaController;
class BirchKeyedServiceTest : public BrowserWithTestWindowTest {
public:
BirchKeyedServiceTest()
: BrowserWithTestWindowTest(
base::test::TaskEnvironment::TimeSource::MOCK_TIME),
fake_user_manager_(std::make_unique<FakeChromeUserManager>()) {
feature_list_.InitWithFeatures(
{features::kForestFeature,
ash::features::kReleaseNotesNotificationAllChannels,
ash::features::kBirchVideoConferenceSuggestions},
{});
}
void SetUp() override {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
BrowserWithTestWindowTest::SetUp();
file_suggest_service_ = static_cast<MockFileSuggestKeyedService*>(
FileSuggestKeyedServiceFactory::GetInstance()->GetService(
GetProfile()));
mount_point_ = std::make_unique<ScopedTestMountPoint>(
"test_mount", storage::kFileSystemTypeLocal,
file_manager::VOLUME_TYPE_TESTING);
mount_point_->Mount(GetProfile());
birch_keyed_service_ =
BirchKeyedServiceFactory::GetInstance()->GetService(GetProfile());
session_sync_service_ = static_cast<MockSessionSyncService*>(
SessionSyncServiceFactory::GetInstance()->GetForProfile(GetProfile()));
sync_service_ = static_cast<syncer::TestSyncService*>(
SyncServiceFactory::GetForProfile(profile()));
SetSessionServiceToReturnOpenTabsDelegate(true);
send_tab_to_self_model_ = static_cast<SendTabToSelfModelMock*>(
SendTabToSelfSyncServiceFactory::GetForProfile(GetProfile())
->GetSendTabToSelfModel());
favicon_service_ =
static_cast<FaviconServiceMock*>(FaviconServiceFactory::GetForProfile(
GetProfile(), ServiceAccessType::EXPLICIT_ACCESS));
// Inject the test media controller into the media controls view.
media_controller_ = std::make_unique<TestMediaController>();
GetLostMediaProvider()->set_fake_media_controller_for_testing(
media_controller_->CreateMediaControllerRemote());
vc_controller_ = std::make_unique<FakeVideoConferenceTrayController>();
GetLostMediaProvider()->set_fake_video_conference_controller_for_testing(
vc_controller_.get());
}
void SetSessionServiceToReturnOpenTabsDelegate(bool return_delegate) {
EXPECT_CALL(*session_sync_service_, GetOpenTabsUIDelegate())
.WillRepeatedly(
testing::Return(return_delegate ? &open_tabs_delegate_ : nullptr));
}
void TearDown() override {
GetLostMediaProvider()->set_fake_video_conference_controller_for_testing(
nullptr);
vc_controller_.reset();
media_controller_.reset();
send_tab_to_self_model_ = nullptr;
mount_point_.reset();
birch_keyed_service_ = nullptr;
file_suggest_service_ = nullptr;
session_sync_service_ = nullptr;
sync_service_ = nullptr;
release_notes_storage_ = nullptr;
favicon_service_ = nullptr;
BrowserWithTestWindowTest::TearDown();
}
void LogIn(const std::string& email) override {
// TODO(crbug.com/40286020): merge into BrowserWithTestWindowTest.
const AccountId account_id(AccountId::FromUserEmail(email));
fake_user_manager_->AddUser(account_id);
fake_user_manager_->LoginUser(account_id);
GetSessionControllerClient()->AddUserSession(email);
GetSessionControllerClient()->SwitchActiveUser(account_id);
}
TestingProfile* CreateProfile(const std::string& profile_name) override {
return profile_manager()->CreateTestingProfile(
profile_name, {}, u"user_name", /*avatar_id=*/0, GetTestingFactories());
}
void SetUpReleaseNotesStorage() {
release_notes_storage_ =
std::make_unique<ReleaseNotesStorage>(GetProfile());
}
void MakePrimaryAccountAvailable() {
auto* identity_manager =
IdentityManagerFactory::GetForProfile(GetProfile());
signin::MakePrimaryAccountAvailable(identity_manager, "[email protected]",
signin::ConsentLevel::kSignin);
}
void AddNewChromeSyncEntry() {
const GURL kUrl(kChromeSyncUrl);
const std::string kTitle("Chrome Sync Title");
const std::string kTargetDeviceSyncCacheGuid(kTargetDeviceCacheGuid);
send_tab_to_self_model_->AddEntry(kUrl, kTitle, kTargetDeviceSyncCacheGuid);
}
void SimulateMediaMetadataInit() {
media_session::MediaMetadata metadata;
metadata.source_title = kSessionMetadataSourceTitle;
metadata.title = kSessionMetadataTitle;
GetLostMediaProvider()->MediaSessionMetadataChanged(metadata);
}
void SimulateMediaMetadataEnd() {
media_session::MediaMetadata metadata;
GetLostMediaProvider()->MediaSessionMetadataChanged(metadata);
}
void SimulateMediaSessionInfoChanged(bool is_playing,
SecondaryIconType type) {
media_session::mojom::MediaSessionInfoPtr info(
media_session::mojom::MediaSessionInfo::New());
info->playback_state =
is_playing ? media_session::mojom::MediaPlaybackState::kPlaying
: media_session::mojom::MediaPlaybackState::kPaused;
info->audio_video_states =
std::vector<media_session::mojom::MediaAudioVideoState>();
media_session::mojom::MediaAudioVideoState state;
switch (type) {
case SecondaryIconType::kLostMediaAudio:
state = media_session::mojom::MediaAudioVideoState::kAudioOnly;
break;
case SecondaryIconType::kLostMediaVideo:
state = media_session::mojom::MediaAudioVideoState::kVideoOnly;
break;
case SecondaryIconType::kLostMediaVideoConference:
case SecondaryIconType::kTabFromDesktop:
case SecondaryIconType::kTabFromTablet:
case SecondaryIconType::kTabFromPhone:
case SecondaryIconType::kTabFromUnknown:
case SecondaryIconType::kNoIcon:
state = media_session::mojom::MediaAudioVideoState::kDeprecatedUnknown;
break;
}
info->audio_video_states->emplace_back(state);
GetLostMediaProvider()->MediaSessionInfoChanged(std::move(info));
}
void AddMediaApp() {
vc_controller_->AddMediaApp(
crosapi::mojom::VideoConferenceMediaAppInfo::New(
/*id=*/base::UnguessableToken::Create(),
/*last_activity_time=*/base::Time::Now(),
/*is_capturing_camera=*/true, /*is_capturing_microphone=*/false,
/*is_capturing_screen=*/false, /*title=*/kMediaAppTitle,
/*url=*/GURL(kMediaAppUrl)));
}
void ClearMediaApps() { vc_controller_->ClearMediaApps(); }
void ClearReleaseNotesSurfacesTimesLeftToShowPref() {
GetProfile()->GetPrefs()->ClearPref(
::prefs::kReleaseNotesSuggestionChipTimesLeftToShow);
}
void MarkMilestoneUpToDate() {
release_notes_storage_->MarkNotificationShown();
}
void MarkReleaseNotesSurfacesTimesLeftToShow(int times_left_to_show) {
GetProfile()->GetPrefs()->SetInteger(
::prefs::kReleaseNotesSuggestionChipTimesLeftToShow,
times_left_to_show);
}
int GetCurrentMilestone() {
return version_info::GetVersion().components()[0];
}
TestSessionControllerClient* GetSessionControllerClient() {
return ash_test_helper()->test_session_controller_client();
}
BirchLostMediaProvider* GetLostMediaProvider() {
return static_cast<BirchLostMediaProvider*>(
birch_keyed_service()->GetLostMediaProvider());
}
MockFileSuggestKeyedService* file_suggest_service() {
return file_suggest_service_;
}
MockSessionSyncService* session_sync_service() {
return session_sync_service_;
}
SendTabToSelfModelMock* send_tab_to_self_model() {
return send_tab_to_self_model_;
}
FaviconServiceMock* favicon_service() { return favicon_service_; }
TestMediaController* media_controller() const {
return media_controller_.get();
}
FakeVideoConferenceTrayController* vc_controller() const {
return vc_controller_.get();
}
syncer::TestSyncService* sync_service() { return sync_service_; }
BirchKeyedService* birch_keyed_service() { return birch_keyed_service_; }
ScopedTestMountPoint* mount_point() { return mount_point_.get(); }
TestingProfile::TestingFactories GetTestingFactories() override {
return {
TestingProfile::TestingFactory{
SyncServiceFactory::GetInstance(),
base::BindRepeating(&BuildTestSyncService)},
TestingProfile::TestingFactory{
FileSuggestKeyedServiceFactory::GetInstance(),
base::BindRepeating(
&MockFileSuggestKeyedService::BuildMockFileSuggestKeyedService,
temp_dir_.GetPath())},
TestingProfile::TestingFactory{
SessionSyncServiceFactory::GetInstance(),
base::BindRepeating(&BuildMockSessionSyncService)},
TestingProfile::TestingFactory{
SendTabToSelfSyncServiceFactory::GetInstance(),
base::BindRepeating(&BuildTestSendTabToSelfSyncService)},
TestingProfile::TestingFactory{
FaviconServiceFactory::GetInstance(),
base::BindRepeating(&BuildFaviconServiceMock)},
};
}
sync_preferences::TestingPrefServiceSyncable* GetDefaultPrefs() const {
return profile()->GetTestingPrefService();
}
private:
user_manager::TypedScopedUserManager<FakeChromeUserManager>
fake_user_manager_;
base::ScopedTempDir temp_dir_;
std::unique_ptr<ScopedTestMountPoint> mount_point_;
raw_ptr<MockFileSuggestKeyedService> file_suggest_service_ = nullptr;
raw_ptr<BirchKeyedService> birch_keyed_service_ = nullptr;
raw_ptr<MockSessionSyncService> session_sync_service_;
raw_ptr<syncer::TestSyncService> sync_service_;
raw_ptr<SendTabToSelfModelMock> send_tab_to_self_model_;
raw_ptr<FaviconServiceMock> favicon_service_;
std::unique_ptr<TestMediaController> media_controller_;
std::unique_ptr<FakeVideoConferenceTrayController> vc_controller_;
MockOpenTabsUIDelegate open_tabs_delegate_;
std::unique_ptr<ReleaseNotesStorage> release_notes_storage_;
base::test::ScopedFeatureList feature_list_;
};
// A test harness that enables focus mode.
class BirchKeyedServiceFocusModeTest : public BirchKeyedServiceTest {
public:
BirchKeyedServiceFocusModeTest() {
scoped_feature_list_.InitAndEnableFeature(features::kFocusMode);
}
BirchKeyedServiceFocusModeTest(const BirchKeyedServiceFocusModeTest&) =
delete;
BirchKeyedServiceFocusModeTest& operator=(
const BirchKeyedServiceFocusModeTest&) = delete;
~BirchKeyedServiceFocusModeTest() override = default;
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
TEST_F(BirchKeyedServiceTest, HasDataProviders) {
WaitUntilFileSuggestServiceReady(
ash::FileSuggestKeyedServiceFactory::GetInstance()->GetService(
GetProfile()));
EXPECT_TRUE(birch_keyed_service()->GetCalendarProvider());
EXPECT_TRUE(birch_keyed_service()->GetFileSuggestProvider());
EXPECT_TRUE(birch_keyed_service()->GetRecentTabsProvider());
EXPECT_TRUE(birch_keyed_service()->GetSelfShareProvider());
EXPECT_TRUE(birch_keyed_service()->GetLostMediaProvider());
}
TEST_F(BirchKeyedServiceTest, BirchFileSuggestProvider) {
WaitUntilFileSuggestServiceReady(
ash::FileSuggestKeyedServiceFactory::GetInstance()->GetService(
GetProfile()));
EXPECT_EQ(Shell::Get()->birch_model()->GetFileSuggestItemsForTest().size(),
0u);
const base::FilePath file_path_1 = mount_point()->CreateArbitraryFile();
const base::FilePath file_path_2 = mount_point()->CreateArbitraryFile();
file_suggest_service()->SetSuggestionsForType(
FileSuggestionType::kDriveFile,
/*suggestions=*/std::vector<FileSuggestData>{
{FileSuggestionType::kDriveFile, file_path_1,
/*title=*/std::nullopt,
/*new_prediction_reason=*/std::nullopt,
/*modified_time=*/std::nullopt,
/*viewed_time=*/std::nullopt,
/*shared_time=*/std::nullopt,
/*new_score=*/std::nullopt,
/*drive_file_id=*/std::nullopt,
/*icon_url=*/std::nullopt},
{FileSuggestionType::kDriveFile, file_path_2,
/*title=*/std::nullopt,
/*new_prediction_reason=*/std::nullopt,
/*modified_time=*/std::nullopt,
/*viewed_time=*/std::nullopt,
/*shared_time=*/std::nullopt,
/*new_score=*/std::nullopt,
/*drive_file_id=*/std::nullopt,
/*icon_url=*/std::nullopt}});
birch_keyed_service()
->GetFileSuggestProviderForTest()
->OnFileSuggestionUpdated(FileSuggestionType::kDriveFile);
task_environment()->RunUntilIdle();
// Check that the birch model now has two file suggestions.
EXPECT_EQ(Shell::Get()->birch_model()->GetFileSuggestItemsForTest().size(),
2u);
}
TEST_F(BirchKeyedServiceTest, BirchFileSuggestProvider_NoFilesAvailable) {
WaitUntilFileSuggestServiceReady(
ash::FileSuggestKeyedServiceFactory::GetInstance()->GetService(
GetProfile()));
BirchModel* model = Shell::Get()->birch_model();
model->SetCalendarItems({});
model->SetRecentTabItems({});
model->SetLastActiveItems({});
model->SetMostVisitedItems({});
model->SetSelfShareItems({});
model->SetLostMediaItems({});
model->SetWeatherItems({});
model->SetReleaseNotesItems({});
model->SetAttachmentItems({});
// Trigger a file update, with no available files.
birch_keyed_service()
->GetFileSuggestProviderForTest()
->OnFileSuggestionUpdated(FileSuggestionType::kDriveFile);
task_environment()->RunUntilIdle();
// Check that model data is not fresh, because no file items have yet
// been provided.
EXPECT_EQ(model->GetFileSuggestItemsForTest().size(), 0u);
EXPECT_FALSE(model->IsDataFresh());
const base::FilePath file_path_1 = mount_point()->CreateArbitraryFile();
// Once file suggest data has been set and updated, the data should be marked
// fresh after the file provider has notified of the change.
file_suggest_service()->SetSuggestionsForType(
FileSuggestionType::kDriveFile,
/*suggestions=*/std::vector<FileSuggestData>{
{FileSuggestionType::kDriveFile, file_path_1,
/*title=*/std::nullopt,
/*new_prediction_reason=*/std::nullopt,
/*modified_time=*/std::nullopt,
/*viewed_time=*/std::nullopt,
/*shared_time=*/std::nullopt,
/*new_score=*/std::nullopt,
/*drive_file_id=*/std::nullopt,
/*icon_url=*/std::nullopt}});
birch_keyed_service()
->GetFileSuggestProviderForTest()
->OnFileSuggestionUpdated(FileSuggestionType::kDriveFile);
task_environment()->RunUntilIdle();
EXPECT_EQ(Shell::Get()->birch_model()->GetFileSuggestItemsForTest().size(),
1u);
EXPECT_TRUE(model->IsDataFresh());
}
TEST_F(BirchKeyedServiceTest, BirchRecentTabProvider) {
WaitUntilFileSuggestServiceReady(
ash::FileSuggestKeyedServiceFactory::GetInstance()->GetService(
GetProfile()));
// No tabs data exists before a data fetch has occurred.
EXPECT_EQ(Shell::Get()->birch_model()->GetTabsForTest().size(), 0u);
// Request birch data fetch, then verify that tabs data is correct.
birch_keyed_service()->GetRecentTabsProvider()->RequestBirchDataFetch();
auto& tabs = Shell::Get()->birch_model()->GetTabsForTest();
ASSERT_EQ(tabs.size(), 2u);
EXPECT_EQ(tabs[0].title(), kTabTitle1);
EXPECT_EQ(tabs[0].url(), GURL(kExampleURL1));
EXPECT_EQ(tabs[0].session_name(), kSessionName1);
EXPECT_EQ(tabs[0].form_factor(), BirchTabItem::DeviceFormFactor::kDesktop);
EXPECT_EQ(tabs[0].secondary_icon_type(), SecondaryIconType::kTabFromDesktop);
EXPECT_EQ(tabs[1].title(), kTabTitle2);
EXPECT_EQ(tabs[1].url(), GURL(kExampleURL2));
EXPECT_EQ(tabs[1].session_name(), kSessionName2);
EXPECT_EQ(tabs[1].form_factor(), BirchTabItem::DeviceFormFactor::kPhone);
EXPECT_EQ(tabs[1].secondary_icon_type(), SecondaryIconType::kTabFromPhone);
// Disable tab sync, then try fetching again and expect an empty list of tabs.
sync_service()->GetUserSettings()->SetSelectedTypes(
/*sync_everything = */ false, /*types=*/{});
birch_keyed_service()->GetRecentTabsProvider()->RequestBirchDataFetch();
EXPECT_EQ(Shell::Get()->birch_model()->GetTabsForTest().size(), 0u);
EXPECT_TRUE(session_sync_service()->IsSubscribersEmpty());
}
TEST_F(BirchKeyedServiceTest, ReleaseNotesProvider) {
BirchModel* model = Shell::Get()->birch_model();
BirchDataProvider* release_notes_provider =
birch_keyed_service()->GetReleaseNotesProvider();
SetUpReleaseNotesStorage();
MakePrimaryAccountAvailable();
EXPECT_EQ(model->GetReleaseNotesItemsForTest().size(), 0u);
release_notes_provider->RequestBirchDataFetch();
model->SetCalendarItems(std::vector<BirchCalendarItem>());
model->SetRecentTabItems(std::vector<BirchTabItem>());
model->SetSelfShareItems(std::vector<BirchSelfShareItem>());
model->SetFileSuggestItems(std::vector<BirchFileItem>());
auto& release_notes_items = model->GetReleaseNotesItemsForTest();
ASSERT_EQ(release_notes_items.size(), 1u);
EXPECT_EQ(release_notes_items[0].title(), u"Chromebook Updated");
EXPECT_EQ(release_notes_items[0].subtitle(), u"See what's new");
EXPECT_EQ(release_notes_items[0].url(), GURL("chrome://help-app/updates"));
EXPECT_EQ(GetProfile()->GetPrefs()->GetInteger(
::prefs::kReleaseNotesSuggestionChipTimesLeftToShow),
3);
MarkMilestoneUpToDate();
MarkReleaseNotesSurfacesTimesLeftToShow(1);
task_environment()->FastForwardBy(base::Hours(23));
release_notes_provider->RequestBirchDataFetch();
model->SetCalendarItems({});
model->SetRecentTabItems(std::vector<BirchTabItem>());
model->SetFileSuggestItems(std::vector<BirchFileItem>());
model->SetSelfShareItems(std::vector<BirchSelfShareItem>());
EXPECT_EQ(model->GetReleaseNotesItemsForTest().size(), 1u);
EXPECT_EQ(GetProfile()->GetPrefs()->GetInteger(
::prefs::kHelpAppNotificationLastShownMilestone),
GetCurrentMilestone());
EXPECT_EQ(GetProfile()->GetPrefs()->GetInteger(
::prefs::kReleaseNotesSuggestionChipTimesLeftToShow),
1);
ClearReleaseNotesSurfacesTimesLeftToShowPref();
release_notes_provider->RequestBirchDataFetch();
model->SetCalendarItems(std::vector<BirchCalendarItem>());
model->SetRecentTabItems(std::vector<BirchTabItem>());
model->SetFileSuggestItems(std::vector<BirchFileItem>());
model->SetSelfShareItems(std::vector<BirchSelfShareItem>());
EXPECT_EQ(model->GetReleaseNotesItemsForTest().size(), 0u);
EXPECT_EQ(GetProfile()->GetPrefs()->GetInteger(
::prefs::kHelpAppNotificationLastShownMilestone),
GetCurrentMilestone());
EXPECT_TRUE(
GetProfile()
->GetPrefs()
->FindPreference(::prefs::kReleaseNotesSuggestionChipTimesLeftToShow)
->IsDefaultValue());
}
TEST_F(BirchKeyedServiceTest, BirchRecentTabsWaitForForeignSessionsChange) {
SetSessionServiceToReturnOpenTabsDelegate(false);
// Request tab data, and check that no tabs are set when no open tabs delegate
// is available.
birch_keyed_service()->GetRecentTabsProvider()->RequestBirchDataFetch();
EXPECT_EQ(Shell::Get()->birch_model()->GetTabsForTest().size(), 0u);
EXPECT_FALSE(session_sync_service()->IsSubscribersEmpty());
SetSessionServiceToReturnOpenTabsDelegate(true);
// Notify session service of foreign session change, and check that tabs have
// been set by the recent tabs provider.
session_sync_service()->NotifyMockForeignSessionsChanged();
EXPECT_EQ(Shell::Get()->birch_model()->GetTabsForTest().size(), 2u);
EXPECT_TRUE(session_sync_service()->IsSubscribersEmpty());
}
TEST_F(BirchKeyedServiceTest, SelfShareProvider_FromTablet) {
BirchModel* model = Shell::Get()->birch_model();
BirchDataProvider* self_share_provider =
birch_keyed_service()->GetSelfShareProvider();
EXPECT_EQ(model->GetSelfShareItemsForTest().size(), 0u);
AddNewChromeSyncEntry();
send_tab_to_self_model()->AddMockTargetDevice(
syncer::DeviceInfo::FormFactor::kTablet);
self_share_provider->RequestBirchDataFetch();
model->SetCalendarItems(std::vector<BirchCalendarItem>());
model->SetRecentTabItems(std::vector<BirchTabItem>());
model->SetFileSuggestItems(std::vector<BirchFileItem>());
model->SetReleaseNotesItems(std::vector<BirchReleaseNotesItem>());
model->SetLostMediaItems(std::vector<BirchLostMediaItem>());
auto& self_share_items = model->GetSelfShareItemsForTest();
EXPECT_EQ(self_share_items.size(), 1u);
EXPECT_EQ(self_share_items[0].title(), u"Chrome Sync Title");
EXPECT_EQ(self_share_items[0].secondary_icon_type(),
SecondaryIconType::kTabFromTablet);
// Mark Self Share Item as opened, the provider should now return zero items.
model->GetSelfShareItemsForTest()[0].PerformAction();
self_share_provider->RequestBirchDataFetch();
EXPECT_EQ(model->GetSelfShareItemsForTest().size(), 0u);
}
TEST_F(BirchKeyedServiceTest, SelfShareProvider_FromPhone) {
BirchModel* model = Shell::Get()->birch_model();
BirchDataProvider* self_share_provider =
birch_keyed_service()->GetSelfShareProvider();
EXPECT_EQ(model->GetSelfShareItemsForTest().size(), 0u);
AddNewChromeSyncEntry();
send_tab_to_self_model()->AddMockTargetDevice(
syncer::DeviceInfo::FormFactor::kPhone);
self_share_provider->RequestBirchDataFetch();
model->SetCalendarItems(std::vector<BirchCalendarItem>());
model->SetRecentTabItems(std::vector<BirchTabItem>());
model->SetFileSuggestItems(std::vector<BirchFileItem>());
model->SetReleaseNotesItems(std::vector<BirchReleaseNotesItem>());
model->SetLostMediaItems(std::vector<BirchLostMediaItem>());
auto& self_share_items = model->GetSelfShareItemsForTest();
EXPECT_EQ(self_share_items.size(), 1u);
EXPECT_EQ(self_share_items[0].secondary_icon_type(),
SecondaryIconType::kTabFromPhone);
// Mark Self Share Item as opened, the provider should now return zero items.
model->GetSelfShareItemsForTest()[0].PerformAction();
self_share_provider->RequestBirchDataFetch();
EXPECT_EQ(model->GetSelfShareItemsForTest().size(), 0u);
}
TEST_F(BirchKeyedServiceTest, SelfShareProvider_FromDesktop) {
BirchModel* model = Shell::Get()->birch_model();
BirchDataProvider* self_share_provider =
birch_keyed_service()->GetSelfShareProvider();
EXPECT_EQ(model->GetSelfShareItemsForTest().size(), 0u);
AddNewChromeSyncEntry();
send_tab_to_self_model()->AddMockTargetDevice(
syncer::DeviceInfo::FormFactor::kDesktop);
self_share_provider->RequestBirchDataFetch();
model->SetCalendarItems(std::vector<BirchCalendarItem>());
model->SetRecentTabItems(std::vector<BirchTabItem>());
model->SetFileSuggestItems(std::vector<BirchFileItem>());
model->SetReleaseNotesItems(std::vector<BirchReleaseNotesItem>());
model->SetLostMediaItems(std::vector<BirchLostMediaItem>());
auto& self_share_items = model->GetSelfShareItemsForTest();
EXPECT_EQ(self_share_items.size(), 1u);
EXPECT_EQ(self_share_items[0].secondary_icon_type(),
SecondaryIconType::kTabFromDesktop);
// Mark Self Share Item as opened, the provider should now return zero items.
model->GetSelfShareItemsForTest()[0].PerformAction();
self_share_provider->RequestBirchDataFetch();
EXPECT_EQ(model->GetSelfShareItemsForTest().size(), 0u);
}
TEST_F(BirchKeyedServiceTest, LostMediaProvider_AudioItem) {
BirchModel* model = Shell::Get()->birch_model();
BirchDataProvider* lost_media_provider =
birch_keyed_service()->GetLostMediaProvider();
ClearMediaApps();
EXPECT_EQ(model->GetLostMediaItemsForTest().size(), 0u);
SimulateMediaMetadataInit();
SimulateMediaSessionInfoChanged(/*is_playing=*/true,
SecondaryIconType::kLostMediaAudio);
lost_media_provider->RequestBirchDataFetch();
model->SetCalendarItems(std::vector<BirchCalendarItem>());
model->SetRecentTabItems(std::vector<BirchTabItem>());
model->SetFileSuggestItems(std::vector<BirchFileItem>());
model->SetReleaseNotesItems(std::vector<BirchReleaseNotesItem>());
model->SetSelfShareItems(std::vector<BirchSelfShareItem>());
auto& lost_media_items = model->GetLostMediaItemsForTest();
EXPECT_EQ(lost_media_items.size(), 1u);
EXPECT_EQ(lost_media_items[0].source_url(),
GURL(kSessionMetadataSourceTitleFull));
EXPECT_EQ(lost_media_items[0].title(), kSessionMetadataTitle);
EXPECT_EQ(lost_media_items[0].secondary_icon_type(),
SecondaryIconType::kLostMediaAudio);
// Media item should still show after activation.
lost_media_items[0].PerformAction();
lost_media_items = model->GetLostMediaItemsForTest();
lost_media_provider->RequestBirchDataFetch();
EXPECT_EQ(lost_media_items.size(), 1u);
EXPECT_EQ(lost_media_items[0].source_url(),
GURL(kSessionMetadataSourceTitleFull));
EXPECT_EQ(lost_media_items[0].title(), kSessionMetadataTitle);
EXPECT_EQ(lost_media_items[0].secondary_icon_type(),
SecondaryIconType::kLostMediaAudio);
// There should be no items if metadata does not have a valid `source_url`
// or `title`.
SimulateMediaMetadataEnd();
lost_media_provider->RequestBirchDataFetch();
lost_media_items = model->GetLostMediaItemsForTest();
ASSERT_EQ(lost_media_items.size(), 0u);
}
TEST_F(BirchKeyedServiceTest, LostMediaProvider_PausedDoesNotShow) {
BirchModel* model = Shell::Get()->birch_model();
BirchDataProvider* lost_media_provider =
birch_keyed_service()->GetLostMediaProvider();
ClearMediaApps();
// Simulate a piece of media.
SimulateMediaMetadataInit();
// Simulate a paused audio stream.
SimulateMediaSessionInfoChanged(/*is_playing=*/false,
SecondaryIconType::kLostMediaAudio);
lost_media_provider->RequestBirchDataFetch();
auto& lost_media_items = model->GetLostMediaItemsForTest();
// The media item does not appear in the model.
EXPECT_EQ(lost_media_items.size(), 0u);
// Simulate a playing audio stream.
SimulateMediaSessionInfoChanged(/*is_playing=*/true,
SecondaryIconType::kLostMediaAudio);
lost_media_provider->RequestBirchDataFetch();
lost_media_items = model->GetLostMediaItemsForTest();
// The media item appears in the model.
EXPECT_EQ(lost_media_items.size(), 1u);
}
TEST_F(BirchKeyedServiceFocusModeTest, LostMediaProvider_FocusModeDoesNotShow) {
BirchModel* model = Shell::Get()->birch_model();
BirchDataProvider* lost_media_provider =
birch_keyed_service()->GetLostMediaProvider();
ClearMediaApps();
// Simulate a playing audio stream.
SimulateMediaMetadataInit();
SimulateMediaSessionInfoChanged(/*is_playing=*/true,
SecondaryIconType::kLostMediaAudio);
// Simulate that the audio is coming from a focus mode playlist.
focus_mode_util::SelectedPlaylist playlist;
playlist.id = "123";
playlist.state = focus_mode_util::SoundState::kPlaying;
FocusModeController::Get()
->focus_mode_sounds_controller()
->set_selected_playlist_for_testing(playlist);
// Fetch the birch items.
lost_media_provider->RequestBirchDataFetch();
auto& lost_media_items = model->GetLostMediaItemsForTest();
// The lost media item does not appear in the model.
EXPECT_EQ(lost_media_items.size(), 0u);
}
TEST_F(BirchKeyedServiceTest, LostMediaProvider_VideoItem) {
BirchModel* model = Shell::Get()->birch_model();
BirchDataProvider* lost_media_provider =
birch_keyed_service()->GetLostMediaProvider();
ClearMediaApps();
EXPECT_EQ(model->GetLostMediaItemsForTest().size(), 0u);
SimulateMediaMetadataInit();
SimulateMediaSessionInfoChanged(/*is_playing=*/true,
SecondaryIconType::kLostMediaVideo);
lost_media_provider->RequestBirchDataFetch();
model->SetCalendarItems(std::vector<BirchCalendarItem>());
model->SetRecentTabItems(std::vector<BirchTabItem>());
model->SetFileSuggestItems(std::vector<BirchFileItem>());
model->SetReleaseNotesItems(std::vector<BirchReleaseNotesItem>());
model->SetSelfShareItems(std::vector<BirchSelfShareItem>());
auto& lost_media_items = model->GetLostMediaItemsForTest();
EXPECT_EQ(lost_media_items.size(), 1u);
EXPECT_EQ(lost_media_items[0].source_url(),
GURL(kSessionMetadataSourceTitleFull));
EXPECT_EQ(lost_media_items[0].title(), kSessionMetadataTitle);
EXPECT_EQ(lost_media_items[0].secondary_icon_type(),
SecondaryIconType::kLostMediaVideo);
// Media item should still show after activation.
lost_media_items[0].PerformAction();
lost_media_items = model->GetLostMediaItemsForTest();
lost_media_provider->RequestBirchDataFetch();
EXPECT_EQ(lost_media_items.size(), 1u);
EXPECT_EQ(lost_media_items[0].source_url(),
GURL(kSessionMetadataSourceTitleFull));
EXPECT_EQ(lost_media_items[0].title(), kSessionMetadataTitle);
EXPECT_EQ(lost_media_items[0].secondary_icon_type(),
SecondaryIconType::kLostMediaVideo);
// There should be no items if metadata does not have a valid `source_url`
// or `title`.
SimulateMediaMetadataEnd();
lost_media_provider->RequestBirchDataFetch();
lost_media_items = model->GetLostMediaItemsForTest();
ASSERT_EQ(lost_media_items.size(), 0u);
}
TEST_F(BirchKeyedServiceTest, LostMediaProvider_VideoConferenceItem) {
BirchModel* model = Shell::Get()->birch_model();
BirchDataProvider* lost_media_provider =
birch_keyed_service()->GetLostMediaProvider();
ClearMediaApps();
EXPECT_EQ(model->GetLostMediaItemsForTest().size(), 0u);
// There should be one video conference item if there is both vc and
// media items available.
SimulateMediaMetadataInit();
AddMediaApp();
lost_media_provider->RequestBirchDataFetch();
model->SetCalendarItems(std::vector<BirchCalendarItem>());
model->SetRecentTabItems(std::vector<BirchTabItem>());
model->SetFileSuggestItems(std::vector<BirchFileItem>());
model->SetReleaseNotesItems(std::vector<BirchReleaseNotesItem>());
model->SetSelfShareItems(std::vector<BirchSelfShareItem>());
auto& lost_media_items = model->GetLostMediaItemsForTest();
ASSERT_EQ(lost_media_items.size(), 1u);
EXPECT_EQ(lost_media_items[0].source_url(), GURL(kMediaAppUrl));
EXPECT_EQ(lost_media_items[0].title(), kMediaAppTitle);
EXPECT_EQ(lost_media_items[0].secondary_icon_type(),
SecondaryIconType::kLostMediaVideoConference);
// VC item still should show after activation.
lost_media_items[0].PerformAction();
lost_media_items = model->GetLostMediaItemsForTest();
lost_media_provider->RequestBirchDataFetch();
model->SetCalendarItems(std::vector<BirchCalendarItem>());
model->SetRecentTabItems(std::vector<BirchTabItem>());
model->SetFileSuggestItems(std::vector<BirchFileItem>());
model->SetReleaseNotesItems(std::vector<BirchReleaseNotesItem>());
model->SetSelfShareItems(std::vector<BirchSelfShareItem>());
ASSERT_EQ(lost_media_items.size(), 1u);
EXPECT_EQ(lost_media_items[0].source_url(), GURL(kMediaAppUrl));
EXPECT_EQ(lost_media_items[0].title(), kMediaAppTitle);
EXPECT_EQ(lost_media_items[0].secondary_icon_type(),
SecondaryIconType::kLostMediaVideoConference);
}
TEST_F(BirchKeyedServiceTest, NoTabSuggestionsWithDisabledChromeSyncPref) {
BirchModel* model = Shell::Get()->birch_model();
// Request birch data fetch, verify that tabs are populated.
birch_keyed_service()->GetRecentTabsProvider()->RequestBirchDataFetch();
AddNewChromeSyncEntry();
birch_keyed_service()->GetSelfShareProvider()->RequestBirchDataFetch();
EXPECT_EQ(model->GetTabsForTest().size(), 2u);
EXPECT_EQ(model->GetSelfShareItemsForTest().size(), 1u);
// Disable ChromeSync integrations by policy, no tabs should be fetched.
GetDefaultPrefs()->SetList(prefs::kContextualGoogleIntegrationsConfiguration,
{});
birch_keyed_service()->GetRecentTabsProvider()->RequestBirchDataFetch();
birch_keyed_service()->GetSelfShareProvider()->RequestBirchDataFetch();
EXPECT_EQ(model->GetTabsForTest().size(), 0u);
EXPECT_EQ(model->GetSelfShareItemsForTest().size(), 0u);
}
TEST_F(BirchKeyedServiceTest, RemoveFileItemFromLauncher) {
WaitUntilFileSuggestServiceReady(
ash::FileSuggestKeyedServiceFactory::GetInstance()->GetService(
GetProfile()));
// Override the default behavior in MockFileSuggestKeyedService, which calls
// into the production code and causes failures.
ON_CALL(*file_suggest_service(), RemoveSuggestionsAndNotify(testing::_))
.WillByDefault([](const std::vector<base::FilePath>& paths) {
// Do nothing.
});
base::FilePath test_path(
"/media/fuse/drivefs-48de6bc248c2f6d8e809521347ef6190/root/Test "
"doc.gdoc");
std::vector<base::FilePath> paths = {test_path};
// Removing a file item via the birch keyed service will call into file
// suggest keyed service and remove it.
EXPECT_CALL(*file_suggest_service(), RemoveSuggestionsAndNotify(paths));
birch_keyed_service()->RemoveFileItemFromLauncher(test_path);
}
// Verifies that `GetFaviconImage` for icon urls calls `GetRawFavicon` in
// favicon service.
TEST_F(BirchKeyedServiceTest, GetFaviconImage_ForIconUrl) {
GURL icon_url("http://example.com/favicon.ico");
EXPECT_CALL(
*favicon_service(),
GetRawFavicon(icon_url, testing::_, testing::_, testing::_, testing::_));
birch_keyed_service()->GetFaviconImage(icon_url, /*is_page_url=*/false,
base::DoNothing());
}
// Verifies that `GetFaviconImage` for page urls calls
// `GetLargestRawFaviconForPageURL` in favicon service.
TEST_F(BirchKeyedServiceTest, GetFaviconImage_ForPageUrl) {
GURL page_url("http://example.com/");
EXPECT_CALL(*favicon_service(),
GetLargestRawFaviconForPageURL(page_url, testing::_, testing::_,
testing::_, testing::_));
birch_keyed_service()->GetFaviconImage(page_url, /*is_page_url=*/true,
base::DoNothing());
}
} // namespace ash