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 "base/bind.h"
6 #include "base/bind_helpers.h"
7 #include "base/file_util.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/path_service.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/defaults.h"
19 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/browser/sessions/session_backend.h"
21 #include "chrome/browser/sessions/session_service.h"
22 #include "chrome/browser/sessions/session_service_test_helper.h"
23 #include "chrome/browser/sessions/session_types.h"
24 #include "chrome/common/chrome_paths.h"
25 #include "chrome/common/url_constants.h"
26 #include "chrome/test/base/browser_with_test_window_test.h"
27 #include "chrome/test/base/testing_browser_process.h"
28 #include "chrome/test/base/testing_profile.h"
29 #include "chrome/test/base/testing_profile_manager.h"
30 #include "components/sessions/serialized_navigation_entry_test_helper.h"
31 #include "content/public/browser/navigation_entry.h"
32 #include "content/public/browser/notification_observer.h"
33 #include "content/public/browser/notification_registrar.h"
34 #include "content/public/browser/notification_service.h"
35 #include "content/public/common/page_state.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37
38 using content::NavigationEntry;
39 using sessions::SerializedNavigationEntry;
40 using sessions::SerializedNavigationEntryTestHelper;
41
42 class SessionServiceTest : public BrowserWithTestWindowTest,
43 public content::NotificationObserver {
44 public:
SessionServiceTest()45 SessionServiceTest() : window_bounds(0, 1, 2, 3), sync_save_count_(0) {}
46
47 protected:
SetUp()48 virtual void SetUp() {
49 BrowserWithTestWindowTest::SetUp();
50
51 profile_manager_.reset(
52 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
53 ASSERT_TRUE(profile_manager_->SetUp());
54
55 std::string b = base::Int64ToString(base::Time::Now().ToInternalValue());
56 TestingProfile* profile = profile_manager_->CreateTestingProfile(b);
57 SessionService* session_service = new SessionService(profile);
58 path_ = profile->GetPath();
59
60 helper_.SetService(session_service);
61
62 service()->SetWindowType(
63 window_id, Browser::TYPE_TABBED, SessionService::TYPE_NORMAL);
64 service()->SetWindowBounds(window_id,
65 window_bounds,
66 ui::SHOW_STATE_NORMAL);
67 }
68
69 // Upon notification, increment the sync_save_count variable
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)70 virtual void Observe(int type,
71 const content::NotificationSource& source,
72 const content::NotificationDetails& details) OVERRIDE {
73 ASSERT_EQ(type, chrome::NOTIFICATION_SESSION_SERVICE_SAVED);
74 sync_save_count_++;
75 }
76
TearDown()77 virtual void TearDown() {
78 helper_.SetService(NULL);
79 BrowserWithTestWindowTest::TearDown();
80 }
81
UpdateNavigation(const SessionID & window_id,const SessionID & tab_id,const SerializedNavigationEntry & navigation,bool select)82 void UpdateNavigation(
83 const SessionID& window_id,
84 const SessionID& tab_id,
85 const SerializedNavigationEntry& navigation,
86 bool select) {
87 service()->UpdateTabNavigation(window_id, tab_id, navigation);
88 if (select) {
89 service()->SetSelectedNavigationIndex(
90 window_id, tab_id, navigation.index());
91 }
92 }
93
ReadWindows(std::vector<SessionWindow * > * windows,SessionID::id_type * active_window_id)94 void ReadWindows(std::vector<SessionWindow*>* windows,
95 SessionID::id_type* active_window_id) {
96 // Forces closing the file.
97 helper_.SetService(NULL);
98
99 SessionService* session_service = new SessionService(path_);
100 helper_.SetService(session_service);
101
102 SessionID::id_type* non_null_active_window_id = active_window_id;
103 SessionID::id_type dummy_active_window_id = 0;
104 if (!non_null_active_window_id)
105 non_null_active_window_id = &dummy_active_window_id;
106 helper_.ReadWindows(windows, non_null_active_window_id);
107 }
108
109 // Configures the session service with one window with one tab and a single
110 // navigation. If |pinned_state| is true or |write_always| is true, the
111 // pinned state of the tab is updated. The session service is then recreated
112 // and the pinned state of the read back tab is returned.
CreateAndWriteSessionWithOneTab(bool pinned_state,bool write_always)113 bool CreateAndWriteSessionWithOneTab(bool pinned_state, bool write_always) {
114 SessionID tab_id;
115 SerializedNavigationEntry nav1 =
116 SerializedNavigationEntryTestHelper::CreateNavigation(
117 "http://google.com", "abc");
118
119 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
120 UpdateNavigation(window_id, tab_id, nav1, true);
121
122 if (pinned_state || write_always)
123 helper_.service()->SetPinnedState(window_id, tab_id, pinned_state);
124
125 ScopedVector<SessionWindow> windows;
126 ReadWindows(&(windows.get()), NULL);
127
128 EXPECT_EQ(1U, windows.size());
129 if (HasFatalFailure())
130 return false;
131 EXPECT_EQ(1U, windows[0]->tabs.size());
132 if (HasFatalFailure())
133 return false;
134
135 SessionTab* tab = windows[0]->tabs[0];
136 helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
137
138 return tab->pinned;
139 }
140
CreateAndWriteSessionWithTwoWindows(const SessionID & window2_id,const SessionID & tab1_id,const SessionID & tab2_id,SerializedNavigationEntry * nav1,SerializedNavigationEntry * nav2)141 void CreateAndWriteSessionWithTwoWindows(
142 const SessionID& window2_id,
143 const SessionID& tab1_id,
144 const SessionID& tab2_id,
145 SerializedNavigationEntry* nav1,
146 SerializedNavigationEntry* nav2) {
147 *nav1 = SerializedNavigationEntryTestHelper::CreateNavigation(
148 "http://google.com", "abc");
149 *nav2 = SerializedNavigationEntryTestHelper::CreateNavigation(
150 "http://google2.com", "abcd");
151
152 helper_.PrepareTabInWindow(window_id, tab1_id, 0, true);
153 UpdateNavigation(window_id, tab1_id, *nav1, true);
154
155 const gfx::Rect window2_bounds(3, 4, 5, 6);
156 service()->SetWindowType(
157 window2_id, Browser::TYPE_TABBED, SessionService::TYPE_NORMAL);
158 service()->SetWindowBounds(window2_id,
159 window2_bounds,
160 ui::SHOW_STATE_MAXIMIZED);
161 helper_.PrepareTabInWindow(window2_id, tab2_id, 0, true);
162 UpdateNavigation(window2_id, tab2_id, *nav2, true);
163 }
164
service()165 SessionService* service() { return helper_.service(); }
166
backend()167 SessionBackend* backend() { return helper_.backend(); }
168
169 const gfx::Rect window_bounds;
170
171 SessionID window_id;
172
173 int sync_save_count_;
174
175 // Path used in testing.
176 base::ScopedTempDir temp_dir_;
177 base::FilePath path_;
178
179 SessionServiceTestHelper helper_;
180 scoped_ptr<TestingProfileManager> profile_manager_;
181 };
182
TEST_F(SessionServiceTest,Basic)183 TEST_F(SessionServiceTest, Basic) {
184 SessionID tab_id;
185 ASSERT_NE(window_id.id(), tab_id.id());
186
187 SerializedNavigationEntry nav1 =
188 SerializedNavigationEntryTestHelper::CreateNavigation(
189 "http://google.com", "abc");
190 SerializedNavigationEntryTestHelper::SetOriginalRequestURL(
191 GURL("http://original.request.com"), &nav1);
192
193 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
194 UpdateNavigation(window_id, tab_id, nav1, true);
195
196 ScopedVector<SessionWindow> windows;
197 ReadWindows(&(windows.get()), NULL);
198
199 ASSERT_EQ(1U, windows.size());
200 ASSERT_TRUE(window_bounds == windows[0]->bounds);
201 ASSERT_EQ(0, windows[0]->selected_tab_index);
202 ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
203 ASSERT_EQ(1U, windows[0]->tabs.size());
204 ASSERT_EQ(Browser::TYPE_TABBED, windows[0]->type);
205
206 SessionTab* tab = windows[0]->tabs[0];
207 helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
208
209 helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
210 }
211
212 // Make sure we persist post entries.
TEST_F(SessionServiceTest,PersistPostData)213 TEST_F(SessionServiceTest, PersistPostData) {
214 SessionID tab_id;
215 ASSERT_NE(window_id.id(), tab_id.id());
216
217 SerializedNavigationEntry nav1 =
218 SerializedNavigationEntryTestHelper::CreateNavigation(
219 "http://google.com", "abc");
220 SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1);
221
222 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
223 UpdateNavigation(window_id, tab_id, nav1, true);
224
225 ScopedVector<SessionWindow> windows;
226 ReadWindows(&(windows.get()), NULL);
227
228 helper_.AssertSingleWindowWithSingleTab(windows.get(), 1);
229 }
230
TEST_F(SessionServiceTest,ClosingTabStaysClosed)231 TEST_F(SessionServiceTest, ClosingTabStaysClosed) {
232 SessionID tab_id;
233 SessionID tab2_id;
234 ASSERT_NE(tab_id.id(), tab2_id.id());
235
236 SerializedNavigationEntry nav1 =
237 SerializedNavigationEntryTestHelper::CreateNavigation(
238 "http://google.com", "abc");
239 SerializedNavigationEntry nav2 =
240 SerializedNavigationEntryTestHelper::CreateNavigation(
241 "http://google2.com", "abcd");
242
243 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
244 UpdateNavigation(window_id, tab_id, nav1, true);
245
246 helper_.PrepareTabInWindow(window_id, tab2_id, 1, false);
247 UpdateNavigation(window_id, tab2_id, nav2, true);
248 service()->TabClosed(window_id, tab2_id, false);
249
250 ScopedVector<SessionWindow> windows;
251 ReadWindows(&(windows.get()), NULL);
252
253 ASSERT_EQ(1U, windows.size());
254 ASSERT_EQ(0, windows[0]->selected_tab_index);
255 ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
256 ASSERT_EQ(1U, windows[0]->tabs.size());
257
258 SessionTab* tab = windows[0]->tabs[0];
259 helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
260
261 helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
262 }
263
TEST_F(SessionServiceTest,Pruning)264 TEST_F(SessionServiceTest, Pruning) {
265 SessionID tab_id;
266
267 SerializedNavigationEntry nav1 =
268 SerializedNavigationEntryTestHelper::CreateNavigation(
269 "http://google.com", "abc");
270 SerializedNavigationEntry nav2 =
271 SerializedNavigationEntryTestHelper::CreateNavigation(
272 "http://google2.com", "abcd");
273
274 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
275 for (int i = 0; i < 6; ++i) {
276 SerializedNavigationEntry* nav = (i % 2) == 0 ? &nav1 : &nav2;
277 nav->set_index(i);
278 UpdateNavigation(window_id, tab_id, *nav, true);
279 }
280 service()->TabNavigationPathPrunedFromBack(window_id, tab_id, 3);
281
282 ScopedVector<SessionWindow> windows;
283 ReadWindows(&(windows.get()), NULL);
284
285 ASSERT_EQ(1U, windows.size());
286 ASSERT_EQ(0, windows[0]->selected_tab_index);
287 ASSERT_EQ(1U, windows[0]->tabs.size());
288
289 SessionTab* tab = windows[0]->tabs[0];
290 // We left the selected index at 5, then pruned. When rereading the
291 // index should get reset to last valid navigation, which is 2.
292 helper_.AssertTabEquals(window_id, tab_id, 0, 2, 3, *tab);
293
294 ASSERT_EQ(3u, tab->navigations.size());
295 helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
296 helper_.AssertNavigationEquals(nav2, tab->navigations[1]);
297 helper_.AssertNavigationEquals(nav1, tab->navigations[2]);
298 }
299
TEST_F(SessionServiceTest,TwoWindows)300 TEST_F(SessionServiceTest, TwoWindows) {
301 SessionID window2_id;
302 SessionID tab1_id;
303 SessionID tab2_id;
304 SerializedNavigationEntry nav1;
305 SerializedNavigationEntry nav2;
306
307 CreateAndWriteSessionWithTwoWindows(
308 window2_id, tab1_id, tab2_id, &nav1, &nav2);
309
310 ScopedVector<SessionWindow> windows;
311 ReadWindows(&(windows.get()), NULL);
312
313 ASSERT_EQ(2U, windows.size());
314 ASSERT_EQ(0, windows[0]->selected_tab_index);
315 ASSERT_EQ(0, windows[1]->selected_tab_index);
316 ASSERT_EQ(1U, windows[0]->tabs.size());
317 ASSERT_EQ(1U, windows[1]->tabs.size());
318
319 SessionTab* rt1;
320 SessionTab* rt2;
321 if (windows[0]->window_id.id() == window_id.id()) {
322 ASSERT_EQ(window2_id.id(), windows[1]->window_id.id());
323 ASSERT_EQ(ui::SHOW_STATE_NORMAL, windows[0]->show_state);
324 ASSERT_EQ(ui::SHOW_STATE_MAXIMIZED, windows[1]->show_state);
325 rt1 = windows[0]->tabs[0];
326 rt2 = windows[1]->tabs[0];
327 } else {
328 ASSERT_EQ(window2_id.id(), windows[0]->window_id.id());
329 ASSERT_EQ(window_id.id(), windows[1]->window_id.id());
330 ASSERT_EQ(ui::SHOW_STATE_MAXIMIZED, windows[0]->show_state);
331 ASSERT_EQ(ui::SHOW_STATE_NORMAL, windows[1]->show_state);
332 rt1 = windows[1]->tabs[0];
333 rt2 = windows[0]->tabs[0];
334 }
335 SessionTab* tab = rt1;
336 helper_.AssertTabEquals(window_id, tab1_id, 0, 0, 1, *tab);
337 helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
338
339 tab = rt2;
340 helper_.AssertTabEquals(window2_id, tab2_id, 0, 0, 1, *tab);
341 helper_.AssertNavigationEquals(nav2, tab->navigations[0]);
342 }
343
TEST_F(SessionServiceTest,WindowWithNoTabsGetsPruned)344 TEST_F(SessionServiceTest, WindowWithNoTabsGetsPruned) {
345 SessionID window2_id;
346 SessionID tab1_id;
347 SessionID tab2_id;
348
349 SerializedNavigationEntry nav1 =
350 SerializedNavigationEntryTestHelper::CreateNavigation(
351 "http://google.com", "abc");
352
353 helper_.PrepareTabInWindow(window_id, tab1_id, 0, true);
354 UpdateNavigation(window_id, tab1_id, nav1, true);
355
356 const gfx::Rect window2_bounds(3, 4, 5, 6);
357 service()->SetWindowType(
358 window2_id, Browser::TYPE_TABBED, SessionService::TYPE_NORMAL);
359 service()->SetWindowBounds(window2_id,
360 window2_bounds,
361 ui::SHOW_STATE_NORMAL);
362 helper_.PrepareTabInWindow(window2_id, tab2_id, 0, true);
363
364 ScopedVector<SessionWindow> windows;
365 ReadWindows(&(windows.get()), NULL);
366
367 ASSERT_EQ(1U, windows.size());
368 ASSERT_EQ(0, windows[0]->selected_tab_index);
369 ASSERT_EQ(1U, windows[0]->tabs.size());
370 ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
371
372 SessionTab* tab = windows[0]->tabs[0];
373 helper_.AssertTabEquals(window_id, tab1_id, 0, 0, 1, *tab);
374 helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
375 }
376
TEST_F(SessionServiceTest,ClosingWindowDoesntCloseTabs)377 TEST_F(SessionServiceTest, ClosingWindowDoesntCloseTabs) {
378 SessionID tab_id;
379 SessionID tab2_id;
380 ASSERT_NE(tab_id.id(), tab2_id.id());
381
382 SerializedNavigationEntry nav1 =
383 SerializedNavigationEntryTestHelper::CreateNavigation(
384 "http://google.com", "abc");
385 SerializedNavigationEntry nav2 =
386 SerializedNavigationEntryTestHelper::CreateNavigation(
387 "http://google2.com", "abcd");
388
389 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
390 UpdateNavigation(window_id, tab_id, nav1, true);
391
392 helper_.PrepareTabInWindow(window_id, tab2_id, 1, false);
393 UpdateNavigation(window_id, tab2_id, nav2, true);
394
395 service()->WindowClosing(window_id);
396
397 ScopedVector<SessionWindow> windows;
398 ReadWindows(&(windows.get()), NULL);
399
400 ASSERT_EQ(1U, windows.size());
401 ASSERT_EQ(0, windows[0]->selected_tab_index);
402 ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
403 ASSERT_EQ(2U, windows[0]->tabs.size());
404
405 SessionTab* tab = windows[0]->tabs[0];
406 helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
407 helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
408
409 tab = windows[0]->tabs[1];
410 helper_.AssertTabEquals(window_id, tab2_id, 1, 0, 1, *tab);
411 helper_.AssertNavigationEquals(nav2, tab->navigations[0]);
412 }
413
TEST_F(SessionServiceTest,LockingWindowRemembersAll)414 TEST_F(SessionServiceTest, LockingWindowRemembersAll) {
415 SessionID window2_id;
416 SessionID tab1_id;
417 SessionID tab2_id;
418 SerializedNavigationEntry nav1;
419 SerializedNavigationEntry nav2;
420
421 CreateAndWriteSessionWithTwoWindows(
422 window2_id, tab1_id, tab2_id, &nav1, &nav2);
423
424 ASSERT_TRUE(service()->profile() != NULL);
425 ASSERT_TRUE(g_browser_process->profile_manager() != NULL);
426 ProfileInfoCache& profile_info =
427 g_browser_process->profile_manager()->GetProfileInfoCache();
428 size_t profile_index = profile_info.GetIndexOfProfileWithPath(
429 service()->profile()->GetPath());
430 ASSERT_NE(std::string::npos, profile_index);
431 profile_info.SetProfileSigninRequiredAtIndex(profile_index, true);
432
433 service()->WindowClosing(window_id);
434 service()->WindowClosed(window_id);
435 service()->WindowClosing(window2_id);
436 service()->WindowClosed(window2_id);
437
438 ScopedVector<SessionWindow> windows;
439 ReadWindows(&(windows.get()), NULL);
440
441 ASSERT_EQ(2U, windows.size());
442 ASSERT_EQ(1U, windows[0]->tabs.size());
443 ASSERT_EQ(1U, windows[1]->tabs.size());
444 }
445
TEST_F(SessionServiceTest,WindowCloseCommittedAfterNavigate)446 TEST_F(SessionServiceTest, WindowCloseCommittedAfterNavigate) {
447 SessionID window2_id;
448 SessionID tab_id;
449 SessionID tab2_id;
450 ASSERT_NE(window2_id.id(), window_id.id());
451
452 service()->SetWindowType(
453 window2_id, Browser::TYPE_TABBED, SessionService::TYPE_NORMAL);
454 service()->SetWindowBounds(window2_id,
455 window_bounds,
456 ui::SHOW_STATE_NORMAL);
457
458 SerializedNavigationEntry nav1 =
459 SerializedNavigationEntryTestHelper::CreateNavigation(
460 "http://google.com", "abc");
461 SerializedNavigationEntry nav2 =
462 SerializedNavigationEntryTestHelper::CreateNavigation(
463 "http://google2.com", "abcd");
464
465 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
466 UpdateNavigation(window_id, tab_id, nav1, true);
467
468 helper_.PrepareTabInWindow(window2_id, tab2_id, 0, false);
469 UpdateNavigation(window2_id, tab2_id, nav2, true);
470
471 service()->WindowClosing(window2_id);
472 service()->TabClosed(window2_id, tab2_id, false);
473 service()->WindowClosed(window2_id);
474
475 ScopedVector<SessionWindow> windows;
476 ReadWindows(&(windows.get()), NULL);
477
478 ASSERT_EQ(1U, windows.size());
479 ASSERT_EQ(0, windows[0]->selected_tab_index);
480 ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
481 ASSERT_EQ(1U, windows[0]->tabs.size());
482
483 SessionTab* tab = windows[0]->tabs[0];
484 helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
485 helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
486 }
487
488 // Makes sure we don't track popups.
TEST_F(SessionServiceTest,IgnorePopups)489 TEST_F(SessionServiceTest, IgnorePopups) {
490 SessionID window2_id;
491 SessionID tab_id;
492 SessionID tab2_id;
493 ASSERT_NE(window2_id.id(), window_id.id());
494
495 service()->SetWindowType(
496 window2_id, Browser::TYPE_POPUP, SessionService::TYPE_NORMAL);
497 service()->SetWindowBounds(window2_id,
498 window_bounds,
499 ui::SHOW_STATE_NORMAL);
500
501 SerializedNavigationEntry nav1 =
502 SerializedNavigationEntryTestHelper::CreateNavigation(
503 "http://google.com", "abc");
504 SerializedNavigationEntry nav2 =
505 SerializedNavigationEntryTestHelper::CreateNavigation(
506 "http://google2.com", "abcd");
507
508 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
509 UpdateNavigation(window_id, tab_id, nav1, true);
510
511 helper_.PrepareTabInWindow(window2_id, tab2_id, 0, false);
512 UpdateNavigation(window2_id, tab2_id, nav2, true);
513
514 ScopedVector<SessionWindow> windows;
515 ReadWindows(&(windows.get()), NULL);
516
517 ASSERT_EQ(1U, windows.size());
518 ASSERT_EQ(0, windows[0]->selected_tab_index);
519 ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
520 ASSERT_EQ(1U, windows[0]->tabs.size());
521
522 SessionTab* tab = windows[0]->tabs[0];
523 helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
524 helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
525 }
526
527 #if defined (OS_CHROMEOS)
528 // Makes sure we track apps. Only applicable on chromeos.
TEST_F(SessionServiceTest,RestoreApp)529 TEST_F(SessionServiceTest, RestoreApp) {
530 SessionID window2_id;
531 SessionID tab_id;
532 SessionID tab2_id;
533 ASSERT_NE(window2_id.id(), window_id.id());
534
535 service()->SetWindowType(
536 window2_id, Browser::TYPE_POPUP, SessionService::TYPE_APP);
537 service()->SetWindowBounds(window2_id,
538 window_bounds,
539 ui::SHOW_STATE_NORMAL);
540 service()->SetWindowAppName(window2_id, "TestApp");
541
542 SerializedNavigationEntry nav1 =
543 SerializedNavigationEntryTestHelper::CreateNavigation(
544 "http://google.com", "abc");
545 SerializedNavigationEntry nav2 =
546 SerializedNavigationEntryTestHelper::CreateNavigation(
547 "http://google2.com", "abcd");
548
549 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
550 UpdateNavigation(window_id, tab_id, nav1, true);
551
552 helper_.PrepareTabInWindow(window2_id, tab2_id, 0, false);
553 UpdateNavigation(window2_id, tab2_id, nav2, true);
554
555 ScopedVector<SessionWindow> windows;
556 ReadWindows(&(windows.get()), NULL);
557
558 ASSERT_EQ(2U, windows.size());
559 int tabbed_index = windows[0]->type == Browser::TYPE_TABBED ?
560 0 : 1;
561 int app_index = tabbed_index == 0 ? 1 : 0;
562 ASSERT_EQ(0, windows[tabbed_index]->selected_tab_index);
563 ASSERT_EQ(window_id.id(), windows[tabbed_index]->window_id.id());
564 ASSERT_EQ(1U, windows[tabbed_index]->tabs.size());
565
566 SessionTab* tab = windows[tabbed_index]->tabs[0];
567 helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
568 helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
569
570 ASSERT_EQ(0, windows[app_index]->selected_tab_index);
571 ASSERT_EQ(window2_id.id(), windows[app_index]->window_id.id());
572 ASSERT_EQ(1U, windows[app_index]->tabs.size());
573 ASSERT_TRUE(windows[app_index]->type == Browser::TYPE_POPUP);
574 ASSERT_EQ("TestApp", windows[app_index]->app_name);
575
576 tab = windows[app_index]->tabs[0];
577 helper_.AssertTabEquals(window2_id, tab2_id, 0, 0, 1, *tab);
578 helper_.AssertNavigationEquals(nav2, tab->navigations[0]);
579 }
580 #endif // defined (OS_CHROMEOS)
581
582 // Tests pruning from the front.
TEST_F(SessionServiceTest,PruneFromFront)583 TEST_F(SessionServiceTest, PruneFromFront) {
584 const std::string base_url("http://google.com/");
585 SessionID tab_id;
586
587 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
588
589 // Add 5 navigations, with the 4th selected.
590 for (int i = 0; i < 5; ++i) {
591 SerializedNavigationEntry nav =
592 SerializedNavigationEntryTestHelper::CreateNavigation(
593 base_url + base::IntToString(i), "a");
594 nav.set_index(i);
595 UpdateNavigation(window_id, tab_id, nav, (i == 3));
596 }
597
598 // Prune the first two navigations from the front.
599 helper_.service()->TabNavigationPathPrunedFromFront(window_id, tab_id, 2);
600
601 // Read back in.
602 ScopedVector<SessionWindow> windows;
603 ReadWindows(&(windows.get()), NULL);
604
605 ASSERT_EQ(1U, windows.size());
606 ASSERT_EQ(0, windows[0]->selected_tab_index);
607 ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
608 ASSERT_EQ(1U, windows[0]->tabs.size());
609
610 // There shouldn't be an app id.
611 EXPECT_TRUE(windows[0]->tabs[0]->extension_app_id.empty());
612
613 // We should be left with three navigations, the 2nd selected.
614 SessionTab* tab = windows[0]->tabs[0];
615 ASSERT_EQ(1, tab->current_navigation_index);
616 EXPECT_EQ(3U, tab->navigations.size());
617 EXPECT_TRUE(GURL(base_url + base::IntToString(2)) ==
618 tab->navigations[0].virtual_url());
619 EXPECT_TRUE(GURL(base_url + base::IntToString(3)) ==
620 tab->navigations[1].virtual_url());
621 EXPECT_TRUE(GURL(base_url + base::IntToString(4)) ==
622 tab->navigations[2].virtual_url());
623 }
624
625 // Prunes from front so that we have no entries.
TEST_F(SessionServiceTest,PruneToEmpty)626 TEST_F(SessionServiceTest, PruneToEmpty) {
627 const std::string base_url("http://google.com/");
628 SessionID tab_id;
629
630 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
631
632 // Add 5 navigations, with the 4th selected.
633 for (int i = 0; i < 5; ++i) {
634 SerializedNavigationEntry nav =
635 SerializedNavigationEntryTestHelper::CreateNavigation(
636 base_url + base::IntToString(i), "a");
637 nav.set_index(i);
638 UpdateNavigation(window_id, tab_id, nav, (i == 3));
639 }
640
641 // Prune the first two navigations from the front.
642 helper_.service()->TabNavigationPathPrunedFromFront(window_id, tab_id, 5);
643
644 // Read back in.
645 ScopedVector<SessionWindow> windows;
646 ReadWindows(&(windows.get()), NULL);
647
648 ASSERT_EQ(0U, windows.size());
649 }
650
651 // Don't set the pinned state and make sure the pinned value is false.
TEST_F(SessionServiceTest,PinnedDefaultsToFalse)652 TEST_F(SessionServiceTest, PinnedDefaultsToFalse) {
653 EXPECT_FALSE(CreateAndWriteSessionWithOneTab(false, false));
654 }
655
656 // Explicitly set the pinned state to false and make sure we get back false.
TEST_F(SessionServiceTest,PinnedFalseWhenSetToFalse)657 TEST_F(SessionServiceTest, PinnedFalseWhenSetToFalse) {
658 EXPECT_FALSE(CreateAndWriteSessionWithOneTab(false, true));
659 }
660
661 // Explicitly set the pinned state to true and make sure we get back true.
TEST_F(SessionServiceTest,PinnedTrue)662 TEST_F(SessionServiceTest, PinnedTrue) {
663 EXPECT_TRUE(CreateAndWriteSessionWithOneTab(true, true));
664 }
665
666 // Make sure application extension ids are persisted.
TEST_F(SessionServiceTest,PersistApplicationExtensionID)667 TEST_F(SessionServiceTest, PersistApplicationExtensionID) {
668 SessionID tab_id;
669 ASSERT_NE(window_id.id(), tab_id.id());
670 std::string app_id("foo");
671
672 SerializedNavigationEntry nav1 =
673 SerializedNavigationEntryTestHelper::CreateNavigation(
674 "http://google.com", "abc");
675
676 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
677 UpdateNavigation(window_id, tab_id, nav1, true);
678 helper_.SetTabExtensionAppID(window_id, tab_id, app_id);
679
680 ScopedVector<SessionWindow> windows;
681 ReadWindows(&(windows.get()), NULL);
682
683 helper_.AssertSingleWindowWithSingleTab(windows.get(), 1);
684 EXPECT_TRUE(app_id == windows[0]->tabs[0]->extension_app_id);
685 }
686
687 // Check that user agent overrides are persisted.
TEST_F(SessionServiceTest,PersistUserAgentOverrides)688 TEST_F(SessionServiceTest, PersistUserAgentOverrides) {
689 SessionID tab_id;
690 ASSERT_NE(window_id.id(), tab_id.id());
691 std::string user_agent_override = "Mozilla/5.0 (X11; Linux x86_64) "
692 "AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.45 "
693 "Safari/535.19";
694
695 SerializedNavigationEntry nav1 =
696 SerializedNavigationEntryTestHelper::CreateNavigation(
697 "http://google.com", "abc");
698 SerializedNavigationEntryTestHelper::SetIsOverridingUserAgent(true, &nav1);
699
700 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
701 UpdateNavigation(window_id, tab_id, nav1, true);
702 helper_.SetTabUserAgentOverride(window_id, tab_id, user_agent_override);
703
704 ScopedVector<SessionWindow> windows;
705 ReadWindows(&(windows.get()), NULL);
706 helper_.AssertSingleWindowWithSingleTab(windows.get(), 1);
707
708 SessionTab* tab = windows[0]->tabs[0];
709 helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
710 helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
711 EXPECT_TRUE(user_agent_override == tab->user_agent_override);
712 }
713
714 // Test that the notification for SESSION_SERVICE_SAVED is working properly.
TEST_F(SessionServiceTest,SavedSessionNotification)715 TEST_F(SessionServiceTest, SavedSessionNotification) {
716 content::NotificationRegistrar registrar_;
717 registrar_.Add(this, chrome::NOTIFICATION_SESSION_SERVICE_SAVED,
718 content::NotificationService::AllSources());
719 service()->Save();
720 EXPECT_EQ(sync_save_count_, 1);
721 }
722
723 // Makes sure a tab closed by a user gesture is not restored.
TEST_F(SessionServiceTest,CloseTabUserGesture)724 TEST_F(SessionServiceTest, CloseTabUserGesture) {
725 SessionID tab_id;
726 ASSERT_NE(window_id.id(), tab_id.id());
727
728 SerializedNavigationEntry nav1 =
729 SerializedNavigationEntryTestHelper::CreateNavigation(
730 "http://google.com", "abc");
731
732 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
733 UpdateNavigation(window_id, tab_id, nav1, true);
734 service()->TabClosed(window_id, tab_id, true);
735
736 ScopedVector<SessionWindow> windows;
737 ReadWindows(&(windows.get()), NULL);
738
739 ASSERT_TRUE(windows.empty());
740 }
741
742 // Verifies SetWindowBounds maps SHOW_STATE_DEFAULT to SHOW_STATE_NORMAL.
TEST_F(SessionServiceTest,DontPersistDefault)743 TEST_F(SessionServiceTest, DontPersistDefault) {
744 SessionID tab_id;
745 ASSERT_NE(window_id.id(), tab_id.id());
746 SerializedNavigationEntry nav1 =
747 SerializedNavigationEntryTestHelper::CreateNavigation(
748 "http://google.com", "abc");
749 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
750 UpdateNavigation(window_id, tab_id, nav1, true);
751 service()->SetWindowBounds(window_id,
752 window_bounds,
753 ui::SHOW_STATE_DEFAULT);
754
755 ScopedVector<SessionWindow> windows;
756 ReadWindows(&(windows.get()), NULL);
757 ASSERT_EQ(1U, windows.size());
758 EXPECT_EQ(ui::SHOW_STATE_NORMAL, windows[0]->show_state);
759 }
760
TEST_F(SessionServiceTest,KeepPostDataWithoutPasswords)761 TEST_F(SessionServiceTest, KeepPostDataWithoutPasswords) {
762 SessionID tab_id;
763 ASSERT_NE(window_id.id(), tab_id.id());
764
765 // Create a page state representing a HTTP body without posted passwords.
766 content::PageState page_state =
767 content::PageState::CreateForTesting(GURL(), false, "data", NULL);
768
769 // Create a TabNavigation containing page_state and representing a POST
770 // request.
771 SerializedNavigationEntry nav1 =
772 SerializedNavigationEntryTestHelper::CreateNavigation(
773 "http://google.com", "title");
774 SerializedNavigationEntryTestHelper::SetPageState(page_state, &nav1);
775 SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1);
776
777 // Create a TabNavigation containing page_state and representing a normal
778 // request.
779 SerializedNavigationEntry nav2 =
780 SerializedNavigationEntryTestHelper::CreateNavigation(
781 "http://google.com/nopost", "title");
782 SerializedNavigationEntryTestHelper::SetPageState(page_state, &nav2);
783 nav2.set_index(1);
784
785 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
786 UpdateNavigation(window_id, tab_id, nav1, true);
787 UpdateNavigation(window_id, tab_id, nav2, true);
788
789 ScopedVector<SessionWindow> windows;
790 ReadWindows(&(windows.get()), NULL);
791
792 helper_.AssertSingleWindowWithSingleTab(windows.get(), 2);
793
794 // Expected: the page state of both navigations was saved and restored.
795 ASSERT_EQ(2u, windows[0]->tabs[0]->navigations.size());
796 helper_.AssertNavigationEquals(nav1, windows[0]->tabs[0]->navigations[0]);
797 helper_.AssertNavigationEquals(nav2, windows[0]->tabs[0]->navigations[1]);
798 }
799
TEST_F(SessionServiceTest,RemovePostDataWithPasswords)800 TEST_F(SessionServiceTest, RemovePostDataWithPasswords) {
801 SessionID tab_id;
802 ASSERT_NE(window_id.id(), tab_id.id());
803
804 // Create a page state representing a HTTP body with posted passwords.
805 content::PageState page_state =
806 content::PageState::CreateForTesting(GURL(), true, "data", NULL);
807
808 // Create a TabNavigation containing page_state and representing a POST
809 // request with passwords.
810 SerializedNavigationEntry nav1 =
811 SerializedNavigationEntryTestHelper::CreateNavigation(
812 "http://google.com", "title");
813 SerializedNavigationEntryTestHelper::SetPageState(page_state, &nav1);
814 SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1);
815 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
816 UpdateNavigation(window_id, tab_id, nav1, true);
817
818 ScopedVector<SessionWindow> windows;
819 ReadWindows(&(windows.get()), NULL);
820
821 helper_.AssertSingleWindowWithSingleTab(windows.get(), 1);
822
823 // Expected: the HTTP body was removed from the page state of the POST
824 // navigation with passwords.
825 EXPECT_NE(page_state, windows[0]->tabs[0]->navigations[0].page_state());
826 }
827
828 // This test is only applicable to chromeos.
829 #if defined(OS_CHROMEOS)
830 // Verifies migration of tab/window closed works.
TEST_F(SessionServiceTest,CanOpenV1TabClosed)831 TEST_F(SessionServiceTest, CanOpenV1TabClosed) {
832 base::FilePath v1_file_path;
833 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &v1_file_path));
834 // v1_session_file contains a tab closed command with the original id. The
835 // file was generated from ClosingTabStaysClosed. If we successfully processed
836 // the file we'll have one tab.
837 v1_file_path =
838 v1_file_path.AppendASCII("sessions").AppendASCII("v1_session_file");
839 base::FilePath dest_file_path(path_);
840 dest_file_path = dest_file_path.AppendASCII("Current Session");
841
842 // Forces closing the file.
843 helper_.SetService(NULL);
844
845 ASSERT_TRUE(base::CopyFile(v1_file_path, dest_file_path));
846
847 SessionService* session_service = new SessionService(path_);
848 helper_.SetService(session_service);
849 ScopedVector<SessionWindow> windows;
850 SessionID::id_type active_window_id = 0;
851 helper_.ReadWindows(&(windows.get()), &active_window_id);
852 ASSERT_EQ(1u, windows.size());
853 EXPECT_EQ(1u, windows[0]->tabs.size());
854 }
855 #endif // defined(OS_CHROMEOS)
856
TEST_F(SessionServiceTest,ReplacePendingNavigation)857 TEST_F(SessionServiceTest, ReplacePendingNavigation) {
858 const std::string base_url("http://google.com/");
859 SessionID tab_id;
860
861 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
862
863 // Add 5 navigations, some with the same index
864 for (int i = 0; i < 5; ++i) {
865 SerializedNavigationEntry nav =
866 SerializedNavigationEntryTestHelper::CreateNavigation(
867 base_url + base::IntToString(i), "a");
868 nav.set_index(i / 2);
869 UpdateNavigation(window_id, tab_id, nav, true);
870 }
871
872 // Read back in.
873 ScopedVector<SessionWindow> windows;
874 ReadWindows(&(windows.get()), NULL);
875
876 // The ones with index 0, and 2 should have been replaced by 1 and 3.
877 ASSERT_EQ(1U, windows.size());
878 ASSERT_EQ(1U, windows[0]->tabs.size());
879 EXPECT_EQ(3U, windows[0]->tabs[0]->navigations.size());
880 EXPECT_EQ(GURL(base_url + base::IntToString(1)),
881 windows[0]->tabs[0]->navigations[0].virtual_url());
882 EXPECT_EQ(GURL(base_url + base::IntToString(3)),
883 windows[0]->tabs[0]->navigations[1].virtual_url());
884 EXPECT_EQ(GURL(base_url + base::IntToString(4)),
885 windows[0]->tabs[0]->navigations[2].virtual_url());
886 }
887
TEST_F(SessionServiceTest,ReplacePendingNavigationAndPrune)888 TEST_F(SessionServiceTest, ReplacePendingNavigationAndPrune) {
889 const std::string base_url("http://google.com/");
890 SessionID tab_id;
891
892 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
893
894 for (int i = 0; i < 5; ++i) {
895 SerializedNavigationEntry nav =
896 SerializedNavigationEntryTestHelper::CreateNavigation(
897 base_url + base::IntToString(i), "a");
898 nav.set_index(i);
899 UpdateNavigation(window_id, tab_id, nav, true);
900 }
901
902 // Prune all those navigations.
903 helper_.service()->TabNavigationPathPrunedFromFront(window_id, tab_id, 5);
904
905 // Add another navigation to replace the last one.
906 SerializedNavigationEntry nav =
907 SerializedNavigationEntryTestHelper::CreateNavigation(
908 base_url + base::IntToString(5), "a");
909 nav.set_index(4);
910 UpdateNavigation(window_id, tab_id, nav, true);
911
912 // Read back in.
913 ScopedVector<SessionWindow> windows;
914 ReadWindows(&(windows.get()), NULL);
915
916 // We should still have that last navigation at the end,
917 // even though it replaced one that was set before the prune.
918 ASSERT_EQ(1U, windows.size());
919 ASSERT_EQ(1U, windows[0]->tabs.size());
920 ASSERT_EQ(1U, windows[0]->tabs[0]->navigations.size());
921 EXPECT_EQ(GURL(base_url + base::IntToString(5)),
922 windows[0]->tabs[0]->navigations[0].virtual_url());
923 }
924
TEST_F(SessionServiceTest,RestoreActivation1)925 TEST_F(SessionServiceTest, RestoreActivation1) {
926 SessionID window2_id;
927 SessionID tab1_id;
928 SessionID tab2_id;
929 SerializedNavigationEntry nav1;
930 SerializedNavigationEntry nav2;
931
932 CreateAndWriteSessionWithTwoWindows(
933 window2_id, tab1_id, tab2_id, &nav1, &nav2);
934
935 service()->ScheduleCommand(
936 service()->CreateSetActiveWindowCommand(window2_id));
937 service()->ScheduleCommand(
938 service()->CreateSetActiveWindowCommand(window_id));
939
940 ScopedVector<SessionWindow> windows;
941 SessionID::id_type active_window_id = 0;
942 ReadWindows(&(windows.get()), &active_window_id);
943 EXPECT_EQ(window_id.id(), active_window_id);
944 }
945
946 // It's easier to have two separate tests with setup/teardown than to manualy
947 // reset the state for the different flavors of the test.
TEST_F(SessionServiceTest,RestoreActivation2)948 TEST_F(SessionServiceTest, RestoreActivation2) {
949 SessionID window2_id;
950 SessionID tab1_id;
951 SessionID tab2_id;
952 SerializedNavigationEntry nav1;
953 SerializedNavigationEntry nav2;
954
955 CreateAndWriteSessionWithTwoWindows(
956 window2_id, tab1_id, tab2_id, &nav1, &nav2);
957
958 service()->ScheduleCommand(
959 service()->CreateSetActiveWindowCommand(window2_id));
960 service()->ScheduleCommand(
961 service()->CreateSetActiveWindowCommand(window_id));
962 service()->ScheduleCommand(
963 service()->CreateSetActiveWindowCommand(window2_id));
964
965 ScopedVector<SessionWindow> windows;
966 SessionID::id_type active_window_id = 0;
967 ReadWindows(&(windows.get()), &active_window_id);
968 EXPECT_EQ(window2_id.id(), active_window_id);
969 }
970
971 // Makes sure we don't track blacklisted URLs.
TEST_F(SessionServiceTest,IgnoreBlacklistedUrls)972 TEST_F(SessionServiceTest, IgnoreBlacklistedUrls) {
973 SessionID tab_id;
974
975 SerializedNavigationEntry nav1 =
976 SerializedNavigationEntryTestHelper::CreateNavigation(
977 "http://google.com", "abc");
978 SerializedNavigationEntry nav2 =
979 SerializedNavigationEntryTestHelper::CreateNavigation(
980 chrome::kChromeUIQuitURL, "quit");
981 SerializedNavigationEntry nav3 =
982 SerializedNavigationEntryTestHelper::CreateNavigation(
983 chrome::kChromeUIRestartURL, "restart");
984
985 helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
986 UpdateNavigation(window_id, tab_id, nav1, true);
987 UpdateNavigation(window_id, tab_id, nav2, true);
988 UpdateNavigation(window_id, tab_id, nav3, true);
989
990 ScopedVector<SessionWindow> windows;
991 ReadWindows(&(windows.get()), NULL);
992
993 ASSERT_EQ(1U, windows.size());
994 ASSERT_EQ(0, windows[0]->selected_tab_index);
995 ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
996 ASSERT_EQ(1U, windows[0]->tabs.size());
997
998 SessionTab* tab = windows[0]->tabs[0];
999 helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
1000 helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
1001 }
1002