1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/toolbar/recent_tabs_builder_test_helper.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <string>
11
12 #include "base/rand_util.h"
13 #include "base/run_loop.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "components/sync/base/client_tag_hash.h"
18 #include "components/sync/engine/commit_and_get_updates_types.h"
19 #include "components/sync/engine/model_type_processor.h"
20 #include "components/sync/model/entity_data.h"
21 #include "components/sync/model_impl/in_memory_metadata_change_list.h"
22 #include "components/sync/protocol/session_specifics.pb.h"
23 #include "components/sync_sessions/open_tabs_ui_delegate.h"
24 #include "components/sync_sessions/session_store.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 namespace {
28
29 const char kBaseSessionTag[] = "session_tag";
30 const char kBaseSessionName[] = "session_name";
31 const char kBaseTabUrl[] = "http://foo/?";
32 const char kTabTitleFormat[] = "session=%d;window=%d;tab=%d";
33 const uint64_t kMaxMinutesRange = 1000;
34
35 struct TitleTimestampPair {
36 base::string16 title;
37 base::Time timestamp;
38 };
39
SortTabTimesByRecency(const TitleTimestampPair & t1,const TitleTimestampPair & t2)40 bool SortTabTimesByRecency(const TitleTimestampPair& t1,
41 const TitleTimestampPair& t2) {
42 return t1.timestamp > t2.timestamp;
43 }
44
ToSessionTag(SessionID session_id)45 std::string ToSessionTag(SessionID session_id) {
46 return std::string(kBaseSessionTag + base::NumberToString(session_id.id()));
47 }
48
ToSessionName(SessionID session_id)49 std::string ToSessionName(SessionID session_id) {
50 return std::string(kBaseSessionName + base::NumberToString(session_id.id()));
51 }
52
ToTabTitle(SessionID session_id,SessionID window_id,SessionID tab_id)53 std::string ToTabTitle(SessionID session_id,
54 SessionID window_id,
55 SessionID tab_id) {
56 return base::StringPrintf(kTabTitleFormat, session_id.id(), window_id.id(),
57 tab_id.id());
58 }
59
ToTabUrl(SessionID session_id,SessionID window_id,SessionID tab_id)60 std::string ToTabUrl(SessionID session_id,
61 SessionID window_id,
62 SessionID tab_id) {
63 return std::string(kBaseTabUrl + ToTabTitle(session_id, window_id, tab_id));
64 }
65
66 } // namespace
67
68 struct RecentTabsBuilderTestHelper::TabInfo {
TabInfoRecentTabsBuilderTestHelper::TabInfo69 TabInfo() : id(SessionID::InvalidValue()) {}
70 SessionID id;
71 base::Time timestamp;
72 base::string16 title;
73 };
74 struct RecentTabsBuilderTestHelper::WindowInfo {
WindowInfoRecentTabsBuilderTestHelper::WindowInfo75 WindowInfo() : id(SessionID::InvalidValue()) {}
~WindowInfoRecentTabsBuilderTestHelper::WindowInfo76 ~WindowInfo() {}
77 SessionID id;
78 std::vector<TabInfo> tabs;
79 };
80 struct RecentTabsBuilderTestHelper::SessionInfo {
SessionInfoRecentTabsBuilderTestHelper::SessionInfo81 SessionInfo() : id(SessionID::InvalidValue()) {}
~SessionInfoRecentTabsBuilderTestHelper::SessionInfo82 ~SessionInfo() {}
83 SessionID id;
84 std::vector<WindowInfo> windows;
85 };
86
RecentTabsBuilderTestHelper()87 RecentTabsBuilderTestHelper::RecentTabsBuilderTestHelper() {
88 start_time_ = base::Time::Now();
89 }
90
~RecentTabsBuilderTestHelper()91 RecentTabsBuilderTestHelper::~RecentTabsBuilderTestHelper() {
92 }
93
AddSession()94 void RecentTabsBuilderTestHelper::AddSession() {
95 SessionInfo info;
96 info.id = SessionID::NewUnique();
97 sessions_.push_back(info);
98 }
99
GetSessionCount()100 int RecentTabsBuilderTestHelper::GetSessionCount() {
101 return sessions_.size();
102 }
103
GetSessionID(int session_index)104 SessionID RecentTabsBuilderTestHelper::GetSessionID(int session_index) {
105 return sessions_[session_index].id;
106 }
107
GetSessionTimestamp(int session_index)108 base::Time RecentTabsBuilderTestHelper::GetSessionTimestamp(int session_index) {
109 std::vector<base::Time> timestamps;
110 for (int w = 0; w < GetWindowCount(session_index); ++w) {
111 for (int t = 0; t < GetTabCount(session_index, w); ++t)
112 timestamps.push_back(GetTabTimestamp(session_index, w, t));
113 }
114
115 if (timestamps.empty())
116 return base::Time::Now();
117
118 sort(timestamps.begin(), timestamps.end());
119 return timestamps[0];
120 }
121
AddWindow(int session_index)122 void RecentTabsBuilderTestHelper::AddWindow(int session_index) {
123 WindowInfo window_info;
124 window_info.id = SessionID::NewUnique();
125 sessions_[session_index].windows.push_back(window_info);
126 }
127
GetWindowCount(int session_index)128 int RecentTabsBuilderTestHelper::GetWindowCount(int session_index) {
129 return sessions_[session_index].windows.size();
130 }
131
GetWindowID(int session_index,int window_index)132 SessionID RecentTabsBuilderTestHelper::GetWindowID(int session_index,
133 int window_index) {
134 return sessions_[session_index].windows[window_index].id;
135 }
136
AddTab(int session_index,int window_index)137 void RecentTabsBuilderTestHelper::AddTab(int session_index, int window_index) {
138 base::Time timestamp =
139 start_time_ +
140 base::TimeDelta::FromMinutes(base::RandGenerator(kMaxMinutesRange));
141 AddTabWithInfo(session_index, window_index, timestamp, base::string16());
142 }
143
AddTabWithInfo(int session_index,int window_index,base::Time timestamp,const base::string16 & title)144 void RecentTabsBuilderTestHelper::AddTabWithInfo(int session_index,
145 int window_index,
146 base::Time timestamp,
147 const base::string16& title) {
148 TabInfo tab_info;
149 tab_info.id = SessionID::NewUnique();
150 tab_info.timestamp = timestamp;
151 tab_info.title = title;
152 sessions_[session_index].windows[window_index].tabs.push_back(tab_info);
153 }
154
GetTabCount(int session_index,int window_index)155 int RecentTabsBuilderTestHelper::GetTabCount(int session_index,
156 int window_index) {
157 return sessions_[session_index].windows[window_index].tabs.size();
158 }
159
GetTabID(int session_index,int window_index,int tab_index)160 SessionID RecentTabsBuilderTestHelper::GetTabID(int session_index,
161 int window_index,
162 int tab_index) {
163 return sessions_[session_index].windows[window_index].tabs[tab_index].id;
164 }
165
GetTabTimestamp(int session_index,int window_index,int tab_index)166 base::Time RecentTabsBuilderTestHelper::GetTabTimestamp(int session_index,
167 int window_index,
168 int tab_index) {
169 return sessions_[session_index].windows[window_index]
170 .tabs[tab_index].timestamp;
171 }
172
GetTabTitle(int session_index,int window_index,int tab_index)173 base::string16 RecentTabsBuilderTestHelper::GetTabTitle(int session_index,
174 int window_index,
175 int tab_index) {
176 base::string16 title =
177 sessions_[session_index].windows[window_index].tabs[tab_index].title;
178 if (title.empty()) {
179 title = base::UTF8ToUTF16(ToTabTitle(
180 GetSessionID(session_index),
181 GetWindowID(session_index, window_index),
182 GetTabID(session_index, window_index, tab_index)));
183 }
184 return title;
185 }
186
ExportToSessionSync(syncer::ModelTypeProcessor * processor)187 void RecentTabsBuilderTestHelper::ExportToSessionSync(
188 syncer::ModelTypeProcessor* processor) {
189 syncer::UpdateResponseDataList updates;
190
191 for (int s = 0; s < GetSessionCount(); ++s) {
192 sync_pb::SessionSpecifics header_specifics = BuildHeaderSpecifics(s);
193 for (int w = 0; w < GetWindowCount(s); ++w) {
194 AddWindowToHeaderSpecifics(s, w, &header_specifics);
195 for (int t = 0; t < GetTabCount(s, w); ++t) {
196 updates.push_back(BuildUpdateResponseData(BuildTabSpecifics(s, w, t),
197 GetTabTimestamp(s, w, t)));
198 }
199 }
200
201 updates.push_back(
202 BuildUpdateResponseData(header_specifics, GetSessionTimestamp(s)));
203 }
204
205 sync_pb::ModelTypeState model_type_state;
206 model_type_state.set_initial_sync_done(true);
207 processor->OnUpdateReceived(model_type_state, std::move(updates));
208 // ClientTagBasedModelTypeProcessor uses ModelTypeProcessorProxy during
209 // activation, which involves task posting for receiving updates.
210 base::RunLoop().RunUntilIdle();
211 }
212
VerifyExport(sync_sessions::OpenTabsUIDelegate * delegate)213 void RecentTabsBuilderTestHelper::VerifyExport(
214 sync_sessions::OpenTabsUIDelegate* delegate) {
215 DCHECK(delegate);
216 // Make sure data is populated correctly in SessionModelAssociator.
217 std::vector<const sync_sessions::SyncedSession*> sessions;
218 ASSERT_TRUE(delegate->GetAllForeignSessions(&sessions));
219 ASSERT_EQ(GetSessionCount(), static_cast<int>(sessions.size()));
220 for (int s = 0; s < GetSessionCount(); ++s) {
221 std::vector<const sessions::SessionWindow*> windows;
222 ASSERT_TRUE(delegate->GetForeignSession(ToSessionTag(GetSessionID(s)),
223 &windows));
224 ASSERT_EQ(GetWindowCount(s), static_cast<int>(windows.size()));
225 for (int w = 0; w < GetWindowCount(s); ++w)
226 ASSERT_EQ(GetTabCount(s, w), static_cast<int>(windows[w]->tabs.size()));
227 }
228 }
229
230 std::vector<base::string16>
GetTabTitlesSortedByRecency()231 RecentTabsBuilderTestHelper::GetTabTitlesSortedByRecency() {
232 std::vector<TitleTimestampPair> tabs;
233 for (int s = 0; s < GetSessionCount(); ++s) {
234 for (int w = 0; w < GetWindowCount(s); ++w) {
235 for (int t = 0; t < GetTabCount(s, w); ++t) {
236 TitleTimestampPair pair;
237 pair.title = GetTabTitle(s, w, t);
238 pair.timestamp = GetTabTimestamp(s, w, t);
239 tabs.push_back(pair);
240 }
241 }
242 }
243 sort(tabs.begin(), tabs.end(), SortTabTimesByRecency);
244
245 std::vector<base::string16> titles;
246 for (size_t i = 0; i < tabs.size(); ++i)
247 titles.push_back(tabs[i].title);
248 return titles;
249 }
250
BuildHeaderSpecifics(int session_index)251 sync_pb::SessionSpecifics RecentTabsBuilderTestHelper::BuildHeaderSpecifics(
252 int session_index) {
253 sync_pb::SessionSpecifics specifics;
254 SessionID session_id = GetSessionID(session_index);
255 specifics.set_session_tag(ToSessionTag(session_id));
256 sync_pb::SessionHeader* header = specifics.mutable_header();
257 header->set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_CROS);
258 header->set_client_name(ToSessionName(session_id));
259 return specifics;
260 }
261
AddWindowToHeaderSpecifics(int session_index,int window_index,sync_pb::SessionSpecifics * specifics)262 void RecentTabsBuilderTestHelper::AddWindowToHeaderSpecifics(
263 int session_index,
264 int window_index,
265 sync_pb::SessionSpecifics* specifics) {
266 sync_pb::SessionWindow* window = specifics->mutable_header()->add_window();
267 SessionID window_id = GetWindowID(session_index, window_index);
268 window->set_window_id(window_id.id());
269 window->set_selected_tab_index(0);
270 window->set_browser_type(sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
271 for (int i = 0; i < GetTabCount(session_index, window_index); ++i)
272 window->add_tab(GetTabID(session_index, window_index, i).id());
273 }
274
BuildTabSpecifics(int session_index,int window_index,int tab_index)275 sync_pb::SessionSpecifics RecentTabsBuilderTestHelper::BuildTabSpecifics(
276 int session_index,
277 int window_index,
278 int tab_index) {
279 sync_pb::SessionSpecifics specifics;
280
281 SessionID session_id = GetSessionID(session_index);
282 SessionID window_id = GetWindowID(session_index, window_index);
283 SessionID tab_id = GetTabID(session_index, window_index, tab_index);
284
285 specifics.set_session_tag(ToSessionTag(session_id));
286 specifics.set_tab_node_id(++max_tab_node_id_);
287 sync_pb::SessionTab* tab = specifics.mutable_tab();
288 tab->set_window_id(window_id.id());
289 tab->set_tab_id(tab_id.id());
290 tab->set_tab_visual_index(1);
291 tab->set_current_navigation_index(0);
292 tab->set_pinned(true);
293 tab->set_extension_app_id("app_id");
294 sync_pb::TabNavigation* navigation = tab->add_navigation();
295 navigation->set_virtual_url(ToTabUrl(session_id, window_id, tab_id));
296 navigation->set_referrer("referrer");
297 navigation->set_title(base::UTF16ToUTF8(GetTabTitle(
298 session_index, window_index, tab_index)));
299 navigation->set_page_transition(sync_pb::SyncEnums_PageTransition_TYPED);
300
301 return specifics;
302 }
303
BuildUpdateResponseData(const sync_pb::SessionSpecifics & specifics,base::Time timestamp)304 syncer::UpdateResponseData RecentTabsBuilderTestHelper::BuildUpdateResponseData(
305 const sync_pb::SessionSpecifics& specifics,
306 base::Time timestamp) {
307 syncer::EntityData entity;
308 *entity.specifics.mutable_session() = specifics;
309 entity.creation_time = timestamp;
310 entity.modification_time = timestamp;
311 entity.client_tag_hash = syncer::ClientTagHash::FromUnhashed(
312 syncer::SESSIONS, sync_sessions::SessionStore::GetClientTag(specifics));
313 entity.id = entity.client_tag_hash.value();
314
315 syncer::UpdateResponseData update;
316 update.entity = std::move(entity);
317 update.response_version = ++next_response_version_;
318 return update;
319 }
320