[go: nahoru, domu]

blob: a26788cb6f241d0860a4128edbc8470fec9b5ff1 [file] [log] [blame]
// 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 "ash/birch/birch_item.h"
#include "ash/birch/birch_model.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_switches.h"
#include "ash/shell.h"
#include "base/files/file_path.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.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/sync/session_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/holding_space/scoped_test_mount_point.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/sessions/core/serialized_navigation_entry_test_helper.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 "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";
std::unique_ptr<sync_sessions::SyncedSession> CreateNewSession(
const std::string& session_name,
const std::string& session_tag) {
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);
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));
MOCK_METHOD(base::CallbackListSubscription,
SubscribeToForeignSessionsChanged,
(const base::RepeatingClosure& cb),
(override));
MOCK_METHOD(base::WeakPtr<syncer::ModelTypeControllerDelegate>,
GetControllerDelegate,
());
};
class MockOpenTabsUIDelegate : public sync_sessions::OpenTabsUIDelegate {
public:
MockOpenTabsUIDelegate() {
foreign_sessions_owned_.push_back(
CreateNewSession(kSessionName1, kSessionTag1));
foreign_sessions_.push_back(foreign_sessions_owned_.back().get());
foreign_sessions_owned_.push_back(
CreateNewSession(kSessionName2, kSessionTag2));
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>>();
}
} // 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;
class BirchKeyedServiceTest : public BrowserWithTestWindowTest {
// public testing::Test {
public:
BirchKeyedServiceTest()
: BrowserWithTestWindowTest(
base::test::TaskEnvironment::TimeSource::MOCK_TIME),
fake_user_manager_(std::make_unique<FakeChromeUserManager>()) {}
void SetUp() override {
switches::SetIgnoreForestSecretKeyForTest(true);
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()));
EXPECT_CALL(*session_sync_service_, GetOpenTabsUIDelegate())
.WillRepeatedly(testing::Return(&open_tabs_delegate_));
}
void TearDown() override {
mount_point_.reset();
birch_keyed_service_ = nullptr;
file_suggest_service_ = nullptr;
session_sync_service_ = nullptr;
fake_user_manager_.Reset();
BrowserWithTestWindowTest::TearDown();
switches::SetIgnoreForestSecretKeyForTest(false);
}
void LogIn(const std::string& email) override {
// TODO(crbug.com/1494005): 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,
GetTestingFactories());
}
TestSessionControllerClient* GetSessionControllerClient() {
return ash_test_helper()->test_session_controller_client();
}
MockFileSuggestKeyedService* file_suggest_service() {
return file_suggest_service_;
}
BirchKeyedService* birch_keyed_service() { return birch_keyed_service_; }
ScopedTestMountPoint* mount_point() { return mount_point_.get(); }
TestingProfile::TestingFactories GetTestingFactories() override {
return {
{FileSuggestKeyedServiceFactory::GetInstance(),
base::BindRepeating(
&MockFileSuggestKeyedService::BuildMockFileSuggestKeyedService,
temp_dir_.GetPath())},
{SessionSyncServiceFactory::GetInstance(),
base::BindRepeating(&BuildMockSessionSyncService)},
};
}
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_;
MockOpenTabsUIDelegate open_tabs_delegate_;
base::test::ScopedFeatureList feature_list_{features::kForestFeature};
};
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,
/*new_prediction_reason=*/std::nullopt,
/*timestamp=*/std::nullopt,
/*secondary_timestamp=*/std::nullopt,
/*new_score=*/std::nullopt},
{FileSuggestionType::kDriveFile, file_path_2,
/*new_prediction_reason=*/std::nullopt,
/*timestamp=*/std::nullopt,
/*secondary_timestamp=*/std::nullopt,
/*new_score=*/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, BirchRecentTabProvider) {
WaitUntilFileSuggestServiceReady(
ash::FileSuggestKeyedServiceFactory::GetInstance()->GetService(
GetProfile()));
task_environment()->RunUntilIdle();
// 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.
Shell::Get()->birch_model()->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[1].title, kTabTitle2);
EXPECT_EQ(tabs[1].url, GURL(kExampleURL2));
EXPECT_EQ(tabs[1].session_name, kSessionName2);
}
} // namespace ash