blob: f4f6ff4c51a877051713ab73943a2820608e3b91 [file]
// 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 "components/visited_url_ranking/internal/session_url_visit_data_fetcher.h"
#include <memory>
#include <vector>
#include "base/callback_list.h"
#include "base/functional/callback.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "components/sync_sessions/open_tabs_ui_delegate.h"
#include "components/sync_sessions/session_sync_service.h"
#include "components/visited_url_ranking/public/fetch_options.h"
#include "components/visited_url_ranking/public/fetcher_config.h"
#include "components/visited_url_ranking/public/url_visit.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
constexpr char kSampleSearchUrl[] = "https://www.google.com/search?q=sample";
constexpr char kSampleSearchUrl2[] = "https://www.google.com/search?q=sample2";
std::unique_ptr<sync_sessions::SyncedSession> BuildSampleSession(
const char* session_name,
std::vector<std::unique_ptr<sync_sessions::SyncedSessionWindow>>
session_windows,
base::Time modified_time = base::Time::Now()) {
auto sample_session = std::make_unique<sync_sessions::SyncedSession>();
sample_session->SetSessionName(session_name);
sample_session->SetModifiedTime(modified_time);
for (size_t i = 0; i < session_windows.size(); i++) {
sample_session->windows[SessionID::FromSerializedValue(i)] =
std::move(session_windows[i]);
}
return sample_session;
}
std::unique_ptr<sync_sessions::SyncedSessionWindow> SampleSessionWindow(
std::vector<std::unique_ptr<sessions::SessionTab>> tabs,
base::Time time = base::Time::Now()) {
auto synced_session_window =
std::make_unique<sync_sessions::SyncedSessionWindow>();
synced_session_window->wrapped_window.timestamp = time;
synced_session_window->wrapped_window.tabs = std::move(tabs);
return synced_session_window;
}
std::unique_ptr<sessions::SessionTab> SampleSessionTab(
int tab_id,
std::u16string title,
GURL url,
bool pinned,
base::Time timestamp = base::Time::Now()) {
sessions::SerializedNavigationEntry navigation;
navigation.set_title(title);
navigation.set_virtual_url(url);
navigation.set_timestamp(timestamp);
navigation.set_favicon_url(url);
auto session_tab = std::make_unique<sessions::SessionTab>();
session_tab->tab_id = SessionID::FromSerializedValue(tab_id);
session_tab->current_navigation_index = 0;
session_tab->navigations.push_back(navigation);
session_tab->timestamp = timestamp;
session_tab->pinned = pinned;
return session_tab;
}
std::unique_ptr<sync_sessions::SyncedSession> GetSampleSession() {
auto now = base::Time::Now();
std::vector<std::unique_ptr<sessions::SessionTab>> session_window_tabs = {};
session_window_tabs.emplace_back(SampleSessionTab(
1, u"Tab 1", GURL(kSampleSearchUrl), true, now - base::Hours(1)));
session_window_tabs.emplace_back(SampleSessionTab(
2, u"Tab 2", GURL(kSampleSearchUrl2), false, now - base::Hours(2)));
std::vector<std::unique_ptr<sync_sessions::SyncedSessionWindow>>
session_windows = {};
session_windows.emplace_back(
SampleSessionWindow(std::move(session_window_tabs)));
return BuildSampleSession("Sample Session", std::move(session_windows));
}
} // namespace
namespace sync_sessions {
class MockOpenTabsUIDelegate : public OpenTabsUIDelegate {
public:
MockOpenTabsUIDelegate() = default;
MockOpenTabsUIDelegate(const MockOpenTabsUIDelegate&) = delete;
MockOpenTabsUIDelegate& operator=(const MockOpenTabsUIDelegate&) = delete;
~MockOpenTabsUIDelegate() override = default;
MOCK_METHOD1(
GetAllForeignSessions,
bool(std::vector<raw_ptr<const SyncedSession, VectorExperimental>>*
sessions));
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));
MOCK_METHOD2(GetForeignSessionTabs,
bool(const std::string& tag,
std::vector<const sessions::SessionTab*>* tabs));
MOCK_METHOD1(GetLocalSession, bool(const SyncedSession** local_session));
};
class MockSessionSyncService : public SessionSyncService {
public:
MockSessionSyncService() = default;
MockSessionSyncService(const MockSessionSyncService&) = delete;
MockSessionSyncService& operator=(const MockSessionSyncService&) = delete;
~MockSessionSyncService() override = default;
MOCK_CONST_METHOD0(GetGlobalIdMapper, syncer::GlobalIdMapper*());
MOCK_METHOD0(GetOpenTabsUIDelegate, OpenTabsUIDelegate*());
base::CallbackListSubscription SubscribeToForeignSessionsChanged(
const base::RepeatingClosure& cb) override {
return subscriber_list_.Add(cb);
}
MOCK_METHOD0(GetControllerDelegate,
base::WeakPtr<syncer::DataTypeControllerDelegate>());
private:
base::RepeatingClosureList subscriber_list_;
};
} // namespace sync_sessions
namespace visited_url_ranking {
using Source = URLVisit::Source;
using URLType = visited_url_ranking::URLVisitAggregate::URLType;
using ResultOption = visited_url_ranking::FetchOptions::ResultOption;
class SessionURLVisitDataFetcherTest
: public testing::Test,
public ::testing::WithParamInterface<Source> {
public:
SessionURLVisitDataFetcherTest() = default;
void SetSessionSyncServiceExpectations() {
EXPECT_CALL(mock_session_sync_service_, GetOpenTabsUIDelegate())
.WillOnce([this]() { return &open_tabs_ui_delegate_; });
}
FetchResult FetchAndGetResult(const FetchOptions& options) {
FetchResult result = FetchResult(FetchResult::Status::kError, {});
base::RunLoop wait_loop;
auto session_url_visit_data_fetcher =
SessionURLVisitDataFetcher(&mock_session_sync_service_);
session_url_visit_data_fetcher.FetchURLVisitData(
options, FetcherConfig(),
base::BindOnce(
[](base::OnceClosure stop_waiting, FetchResult* result,
FetchResult result_arg) {
result->status = result_arg.status;
result->data = std::move(result_arg.data);
std::move(stop_waiting).Run();
},
wait_loop.QuitClosure(), &result));
wait_loop.Run();
return result;
}
protected:
sync_sessions::MockOpenTabsUIDelegate open_tabs_ui_delegate_;
sync_sessions::MockSessionSyncService mock_session_sync_service_;
private:
base::test::TaskEnvironment task_env_;
};
TEST_F(SessionURLVisitDataFetcherTest, FetchURLVisitDataNoOpenTabsUIDelegate) {
EXPECT_CALL(mock_session_sync_service_, GetOpenTabsUIDelegate())
.WillOnce([]() { return nullptr; });
std::vector<std::unique_ptr<sync_sessions::SyncedSession>> sample_sessions;
sample_sessions.push_back(GetSampleSession());
base::Time yesterday = base::Time::Now() - base::Days(1);
auto result = FetchAndGetResult(FetchOptions(
{{URLType::kActiveRemoteTab, {.age_limit = base::Days(1)}}},
{
{Fetcher::kSession,
FetchOptions::FetchSources({URLVisit::Source::kForeign})},
},
yesterday));
EXPECT_EQ(result.status, FetchResult::Status::kError);
}
TEST_F(SessionURLVisitDataFetcherTest, FetchURLVisitDataDefaultSources) {
std::vector<std::unique_ptr<sync_sessions::SyncedSession>>
local_sample_sessions;
std::vector<std::unique_ptr<sync_sessions::SyncedSession>>
foreign_sample_sessions;
local_sample_sessions.push_back(GetSampleSession());
foreign_sample_sessions.push_back(GetSampleSession());
SetSessionSyncServiceExpectations();
EXPECT_CALL(open_tabs_ui_delegate_, GetLocalSession(testing::_))
.WillOnce(
[&local_sample_sessions](const sync_sessions::SyncedSession** local) {
local_sample_sessions[0]->SetSessionName("Local Session");
*local = local_sample_sessions[0].get();
return true;
});
EXPECT_CALL(open_tabs_ui_delegate_, GetAllForeignSessions(testing::_))
.WillOnce([&foreign_sample_sessions](
std::vector<raw_ptr<const sync_sessions::SyncedSession,
VectorExperimental>>* sessions) {
for (auto& sample_session : foreign_sample_sessions) {
sessions->push_back(sample_session.get());
}
return true;
});
base::Time yesterday = base::Time::Now() - base::Days(1);
auto result = FetchAndGetResult(FetchOptions(
{
{URLType::kActiveRemoteTab, {.age_limit = base::Days(1)}},
},
{
{Fetcher::kSession, FetchOptions::kOriginSources},
},
yesterday));
EXPECT_EQ(result.status, FetchResult::Status::kSuccess);
EXPECT_EQ(result.data.size(), 2u);
for (const auto& url_key : {kSampleSearchUrl, kSampleSearchUrl2}) {
const auto& tab_data =
std::get<URLVisitAggregate::TabData>(result.data.at(url_key));
EXPECT_EQ(tab_data.tab_count, 2u);
}
}
INSTANTIATE_TEST_SUITE_P(All,
SessionURLVisitDataFetcherTest,
::testing::Values(Source::kLocal, Source::kForeign));
TEST_P(SessionURLVisitDataFetcherTest, FetchURLVisitData) {
std::vector<std::unique_ptr<sync_sessions::SyncedSession>> sample_sessions;
sample_sessions.push_back(GetSampleSession());
SetSessionSyncServiceExpectations();
const auto source = GetParam();
if (source == Source::kLocal) {
EXPECT_CALL(open_tabs_ui_delegate_, GetLocalSession(testing::_))
.WillOnce(
[&sample_sessions](const sync_sessions::SyncedSession** local) {
*local = sample_sessions[0].get();
return true;
});
} else if (source == Source::kForeign) {
EXPECT_CALL(open_tabs_ui_delegate_, GetAllForeignSessions(testing::_))
.WillOnce([&sample_sessions](
std::vector<raw_ptr<const sync_sessions::SyncedSession,
VectorExperimental>>* sessions) {
for (auto& sample_session : sample_sessions) {
sessions->push_back(sample_session.get());
}
return true;
});
}
auto options = FetchOptions(
{
{URLType::kActiveRemoteTab, {.age_limit = base::Days(1)}},
},
{
{Fetcher::kSession, FetchOptions::FetchSources({source})},
},
base::Time::Now() - base::Days(1));
auto result = FetchAndGetResult(options);
EXPECT_EQ(result.status, FetchResult::Status::kSuccess);
EXPECT_EQ(result.data.size(), 2u);
for (const auto& url_key : {kSampleSearchUrl, kSampleSearchUrl2}) {
const auto& tab_data =
std::get<URLVisitAggregate::TabData>(result.data.at(url_key));
EXPECT_EQ(tab_data.tab_count, 1u);
EXPECT_EQ(tab_data.last_active_tab.visit.source, source);
}
EXPECT_EQ(
std::get<URLVisitAggregate::TabData>(result.data.at(kSampleSearchUrl))
.pinned,
true);
EXPECT_EQ(
std::get<URLVisitAggregate::TabData>(result.data.at(kSampleSearchUrl2))
.pinned,
false);
}
TEST_F(SessionURLVisitDataFetcherTest,
FetchURLVisitDataDefaultSourcesSameSession) {
std::vector<std::unique_ptr<sync_sessions::SyncedSession>> sample_sessions;
sample_sessions.push_back(GetSampleSession());
SetSessionSyncServiceExpectations();
EXPECT_CALL(open_tabs_ui_delegate_, GetLocalSession(testing::_))
.WillOnce([&sample_sessions](const sync_sessions::SyncedSession** local) {
*local = sample_sessions[0].get();
return true;
});
EXPECT_CALL(open_tabs_ui_delegate_, GetAllForeignSessions(testing::_))
.WillOnce([&sample_sessions](
std::vector<raw_ptr<const sync_sessions::SyncedSession,
VectorExperimental>>* sessions) {
for (auto& sample_session : sample_sessions) {
sessions->push_back(sample_session.get());
}
return true;
});
base::Time yesterday = base::Time::Now() - base::Days(1);
auto result = FetchAndGetResult(FetchOptions(
{
{URLType::kActiveRemoteTab, {.age_limit = base::Days(1)}},
},
{
{Fetcher::kSession, {Source::kForeign}},
},
yesterday));
EXPECT_EQ(result.status, FetchResult::Status::kSuccess);
EXPECT_EQ(result.data.size(), 0u);
}
} // namespace visited_url_ranking