1 // Copyright 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.
6 #include "base/bind_helpers.h"
7 #include "base/files/file_util.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/location.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/memory/scoped_vector.h"
12 #include "base/run_loop.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/time/time.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/chrome_notification_types.h"
21 #include "chrome/browser/defaults.h"
22 #include "chrome/browser/profiles/profile_manager.h"
23 #include "chrome/browser/sessions/session_service.h"
24 #include "chrome/browser/sessions/session_service_test_helper.h"
25 #include "chrome/common/chrome_paths.h"
26 #include "chrome/common/url_constants.h"
27 #include "chrome/test/base/browser_with_test_window_test.h"
28 #include "chrome/test/base/testing_browser_process.h"
29 #include "chrome/test/base/testing_profile.h"
30 #include "chrome/test/base/testing_profile_manager.h"
31 #include "components/sessions/serialized_navigation_entry_test_helper.h"
32 #include "components/sessions/session_command.h"
33 #include "components/sessions/session_types.h"
34 #include "content/public/browser/navigation_entry.h"
35 #include "content/public/browser/notification_observer.h"
36 #include "content/public/browser/notification_registrar.h"
37 #include "content/public/browser/notification_service.h"
38 #include "content/public/common/page_state.h"
39 #include "testing/gtest/include/gtest/gtest.h"
41 using content::NavigationEntry
;
42 using sessions::SerializedNavigationEntry
;
43 using sessions::SerializedNavigationEntryTestHelper
;
45 class SessionServiceTest
: public BrowserWithTestWindowTest
,
46 public content::NotificationObserver
{
48 SessionServiceTest() : window_bounds(0, 1, 2, 3), sync_save_count_(0) {}
51 void SetUp() override
{
52 BrowserWithTestWindowTest::SetUp();
54 profile_manager_
.reset(
55 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
56 ASSERT_TRUE(profile_manager_
->SetUp());
58 std::string b
= base::Int64ToString(base::Time::Now().ToInternalValue());
59 TestingProfile
* profile
= profile_manager_
->CreateTestingProfile(b
);
60 SessionService
* session_service
= new SessionService(profile
);
61 path_
= profile
->GetPath();
63 helper_
.SetService(session_service
);
65 service()->SetWindowType(window_id
,
67 SessionService::TYPE_NORMAL
);
68 service()->SetWindowBounds(window_id
,
70 ui::SHOW_STATE_NORMAL
);
73 // Upon notification, increment the sync_save_count variable
74 void Observe(int type
,
75 const content::NotificationSource
& source
,
76 const content::NotificationDetails
& details
) override
{
77 ASSERT_EQ(type
, chrome::NOTIFICATION_SESSION_SERVICE_SAVED
);
81 void TearDown() override
{
82 helper_
.SetService(NULL
);
83 BrowserWithTestWindowTest::TearDown();
86 void UpdateNavigation(
87 const SessionID
& window_id
,
88 const SessionID
& tab_id
,
89 const SerializedNavigationEntry
& navigation
,
91 service()->UpdateTabNavigation(window_id
, tab_id
, navigation
);
93 service()->SetSelectedNavigationIndex(
94 window_id
, tab_id
, navigation
.index());
98 void ReadWindows(std::vector
<sessions::SessionWindow
*>* windows
,
99 SessionID::id_type
* active_window_id
) {
100 // Forces closing the file.
101 helper_
.SetService(NULL
);
103 SessionService
* session_service
= new SessionService(path_
);
104 helper_
.SetService(session_service
);
106 SessionID::id_type
* non_null_active_window_id
= active_window_id
;
107 SessionID::id_type dummy_active_window_id
= 0;
108 if (!non_null_active_window_id
)
109 non_null_active_window_id
= &dummy_active_window_id
;
110 helper_
.ReadWindows(windows
, non_null_active_window_id
);
113 // Configures the session service with one window with one tab and a single
114 // navigation. If |pinned_state| is true or |write_always| is true, the
115 // pinned state of the tab is updated. The session service is then recreated
116 // and the pinned state of the read back tab is returned.
117 bool CreateAndWriteSessionWithOneTab(bool pinned_state
, bool write_always
) {
119 SerializedNavigationEntry nav1
=
120 SerializedNavigationEntryTestHelper::CreateNavigation(
121 "http://google.com", "abc");
123 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
124 UpdateNavigation(window_id
, tab_id
, nav1
, true);
126 if (pinned_state
|| write_always
)
127 helper_
.service()->SetPinnedState(window_id
, tab_id
, pinned_state
);
129 ScopedVector
<sessions::SessionWindow
> windows
;
130 ReadWindows(&(windows
.get()), NULL
);
132 EXPECT_EQ(1U, windows
.size());
133 if (HasFatalFailure())
135 EXPECT_EQ(1U, windows
[0]->tabs
.size());
136 if (HasFatalFailure())
139 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
140 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
145 void CreateAndWriteSessionWithTwoWindows(
146 const SessionID
& window2_id
,
147 const SessionID
& tab1_id
,
148 const SessionID
& tab2_id
,
149 SerializedNavigationEntry
* nav1
,
150 SerializedNavigationEntry
* nav2
) {
151 *nav1
= SerializedNavigationEntryTestHelper::CreateNavigation(
152 "http://google.com", "abc");
153 *nav2
= SerializedNavigationEntryTestHelper::CreateNavigation(
154 "http://google2.com", "abcd");
156 helper_
.PrepareTabInWindow(window_id
, tab1_id
, 0, true);
157 UpdateNavigation(window_id
, tab1_id
, *nav1
, true);
159 const gfx::Rect
window2_bounds(3, 4, 5, 6);
160 service()->SetWindowType(window2_id
,
161 Browser::TYPE_TABBED
,
162 SessionService::TYPE_NORMAL
);
163 service()->SetWindowBounds(window2_id
,
165 ui::SHOW_STATE_MAXIMIZED
);
166 helper_
.PrepareTabInWindow(window2_id
, tab2_id
, 0, true);
167 UpdateNavigation(window2_id
, tab2_id
, *nav2
, true);
170 SessionService
* service() { return helper_
.service(); }
172 const gfx::Rect window_bounds
;
176 int sync_save_count_
;
178 // Path used in testing.
179 base::ScopedTempDir temp_dir_
;
180 base::FilePath path_
;
182 SessionServiceTestHelper helper_
;
183 scoped_ptr
<TestingProfileManager
> profile_manager_
;
186 TEST_F(SessionServiceTest
, Basic
) {
188 ASSERT_NE(window_id
.id(), tab_id
.id());
190 SerializedNavigationEntry nav1
=
191 SerializedNavigationEntryTestHelper::CreateNavigation(
192 "http://google.com", "abc");
193 SerializedNavigationEntryTestHelper::SetOriginalRequestURL(
194 GURL("http://original.request.com"), &nav1
);
196 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
197 UpdateNavigation(window_id
, tab_id
, nav1
, true);
199 ScopedVector
<sessions::SessionWindow
> windows
;
200 ReadWindows(&(windows
.get()), NULL
);
202 ASSERT_EQ(1U, windows
.size());
203 ASSERT_TRUE(window_bounds
== windows
[0]->bounds
);
204 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
205 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
206 ASSERT_EQ(1U, windows
[0]->tabs
.size());
207 ASSERT_EQ(sessions::SessionWindow::TYPE_TABBED
, windows
[0]->type
);
209 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
210 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
212 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
215 // Make sure we persist post entries.
216 TEST_F(SessionServiceTest
, PersistPostData
) {
218 ASSERT_NE(window_id
.id(), tab_id
.id());
220 SerializedNavigationEntry nav1
=
221 SerializedNavigationEntryTestHelper::CreateNavigation(
222 "http://google.com", "abc");
223 SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1
);
225 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
226 UpdateNavigation(window_id
, tab_id
, nav1
, true);
228 ScopedVector
<sessions::SessionWindow
> windows
;
229 ReadWindows(&(windows
.get()), NULL
);
231 helper_
.AssertSingleWindowWithSingleTab(windows
.get(), 1);
234 TEST_F(SessionServiceTest
, ClosingTabStaysClosed
) {
237 ASSERT_NE(tab_id
.id(), tab2_id
.id());
239 SerializedNavigationEntry nav1
=
240 SerializedNavigationEntryTestHelper::CreateNavigation(
241 "http://google.com", "abc");
242 SerializedNavigationEntry nav2
=
243 SerializedNavigationEntryTestHelper::CreateNavigation(
244 "http://google2.com", "abcd");
246 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
247 UpdateNavigation(window_id
, tab_id
, nav1
, true);
249 helper_
.PrepareTabInWindow(window_id
, tab2_id
, 1, false);
250 UpdateNavigation(window_id
, tab2_id
, nav2
, true);
251 service()->TabClosed(window_id
, tab2_id
, false);
253 ScopedVector
<sessions::SessionWindow
> windows
;
254 ReadWindows(&(windows
.get()), NULL
);
256 ASSERT_EQ(1U, windows
.size());
257 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
258 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
259 ASSERT_EQ(1U, windows
[0]->tabs
.size());
261 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
262 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
264 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
267 TEST_F(SessionServiceTest
, Pruning
) {
270 SerializedNavigationEntry nav1
=
271 SerializedNavigationEntryTestHelper::CreateNavigation(
272 "http://google.com", "abc");
273 SerializedNavigationEntry nav2
=
274 SerializedNavigationEntryTestHelper::CreateNavigation(
275 "http://google2.com", "abcd");
277 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
278 for (int i
= 0; i
< 6; ++i
) {
279 SerializedNavigationEntry
* nav
= (i
% 2) == 0 ? &nav1
: &nav2
;
281 UpdateNavigation(window_id
, tab_id
, *nav
, true);
283 service()->TabNavigationPathPrunedFromBack(window_id
, tab_id
, 3);
285 ScopedVector
<sessions::SessionWindow
> windows
;
286 ReadWindows(&(windows
.get()), NULL
);
288 ASSERT_EQ(1U, windows
.size());
289 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
290 ASSERT_EQ(1U, windows
[0]->tabs
.size());
292 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
293 // We left the selected index at 5, then pruned. When rereading the
294 // index should get reset to last valid navigation, which is 2.
295 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 2, 3, *tab
);
297 ASSERT_EQ(3u, tab
->navigations
.size());
298 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
299 helper_
.AssertNavigationEquals(nav2
, tab
->navigations
[1]);
300 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[2]);
303 TEST_F(SessionServiceTest
, TwoWindows
) {
304 SessionID window2_id
;
307 SerializedNavigationEntry nav1
;
308 SerializedNavigationEntry nav2
;
310 CreateAndWriteSessionWithTwoWindows(
311 window2_id
, tab1_id
, tab2_id
, &nav1
, &nav2
);
313 ScopedVector
<sessions::SessionWindow
> windows
;
314 ReadWindows(&(windows
.get()), NULL
);
316 ASSERT_EQ(2U, windows
.size());
317 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
318 ASSERT_EQ(0, windows
[1]->selected_tab_index
);
319 ASSERT_EQ(1U, windows
[0]->tabs
.size());
320 ASSERT_EQ(1U, windows
[1]->tabs
.size());
322 sessions::SessionTab
* rt1
;
323 sessions::SessionTab
* rt2
;
324 if (windows
[0]->window_id
.id() == window_id
.id()) {
325 ASSERT_EQ(window2_id
.id(), windows
[1]->window_id
.id());
326 ASSERT_EQ(ui::SHOW_STATE_NORMAL
, windows
[0]->show_state
);
327 ASSERT_EQ(ui::SHOW_STATE_MAXIMIZED
, windows
[1]->show_state
);
328 rt1
= windows
[0]->tabs
[0];
329 rt2
= windows
[1]->tabs
[0];
331 ASSERT_EQ(window2_id
.id(), windows
[0]->window_id
.id());
332 ASSERT_EQ(window_id
.id(), windows
[1]->window_id
.id());
333 ASSERT_EQ(ui::SHOW_STATE_MAXIMIZED
, windows
[0]->show_state
);
334 ASSERT_EQ(ui::SHOW_STATE_NORMAL
, windows
[1]->show_state
);
335 rt1
= windows
[1]->tabs
[0];
336 rt2
= windows
[0]->tabs
[0];
338 sessions::SessionTab
* tab
= rt1
;
339 helper_
.AssertTabEquals(window_id
, tab1_id
, 0, 0, 1, *tab
);
340 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
343 helper_
.AssertTabEquals(window2_id
, tab2_id
, 0, 0, 1, *tab
);
344 helper_
.AssertNavigationEquals(nav2
, tab
->navigations
[0]);
347 TEST_F(SessionServiceTest
, WindowWithNoTabsGetsPruned
) {
348 SessionID window2_id
;
352 SerializedNavigationEntry nav1
=
353 SerializedNavigationEntryTestHelper::CreateNavigation(
354 "http://google.com", "abc");
356 helper_
.PrepareTabInWindow(window_id
, tab1_id
, 0, true);
357 UpdateNavigation(window_id
, tab1_id
, nav1
, true);
359 const gfx::Rect
window2_bounds(3, 4, 5, 6);
360 service()->SetWindowType(window2_id
,
361 Browser::TYPE_TABBED
,
362 SessionService::TYPE_NORMAL
);
363 service()->SetWindowBounds(window2_id
,
365 ui::SHOW_STATE_NORMAL
);
366 helper_
.PrepareTabInWindow(window2_id
, tab2_id
, 0, true);
368 ScopedVector
<sessions::SessionWindow
> windows
;
369 ReadWindows(&(windows
.get()), NULL
);
371 ASSERT_EQ(1U, windows
.size());
372 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
373 ASSERT_EQ(1U, windows
[0]->tabs
.size());
374 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
376 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
377 helper_
.AssertTabEquals(window_id
, tab1_id
, 0, 0, 1, *tab
);
378 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
381 TEST_F(SessionServiceTest
, ClosingWindowDoesntCloseTabs
) {
384 ASSERT_NE(tab_id
.id(), tab2_id
.id());
386 SerializedNavigationEntry nav1
=
387 SerializedNavigationEntryTestHelper::CreateNavigation(
388 "http://google.com", "abc");
389 SerializedNavigationEntry nav2
=
390 SerializedNavigationEntryTestHelper::CreateNavigation(
391 "http://google2.com", "abcd");
393 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
394 UpdateNavigation(window_id
, tab_id
, nav1
, true);
396 helper_
.PrepareTabInWindow(window_id
, tab2_id
, 1, false);
397 UpdateNavigation(window_id
, tab2_id
, nav2
, true);
399 service()->WindowClosing(window_id
);
401 ScopedVector
<sessions::SessionWindow
> windows
;
402 ReadWindows(&(windows
.get()), NULL
);
404 ASSERT_EQ(1U, windows
.size());
405 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
406 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
407 ASSERT_EQ(2U, windows
[0]->tabs
.size());
409 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
410 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
411 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
413 tab
= windows
[0]->tabs
[1];
414 helper_
.AssertTabEquals(window_id
, tab2_id
, 1, 0, 1, *tab
);
415 helper_
.AssertNavigationEquals(nav2
, tab
->navigations
[0]);
418 TEST_F(SessionServiceTest
, LockingWindowRemembersAll
) {
419 SessionID window2_id
;
422 SerializedNavigationEntry nav1
;
423 SerializedNavigationEntry nav2
;
425 CreateAndWriteSessionWithTwoWindows(
426 window2_id
, tab1_id
, tab2_id
, &nav1
, &nav2
);
428 ASSERT_TRUE(service()->profile() != NULL
);
429 ASSERT_TRUE(g_browser_process
->profile_manager() != NULL
);
430 ProfileInfoCache
& profile_info
=
431 g_browser_process
->profile_manager()->GetProfileInfoCache();
432 size_t profile_index
= profile_info
.GetIndexOfProfileWithPath(
433 service()->profile()->GetPath());
434 ASSERT_NE(std::string::npos
, profile_index
);
435 profile_info
.SetProfileSigninRequiredAtIndex(profile_index
, true);
437 service()->WindowClosing(window_id
);
438 service()->WindowClosed(window_id
);
439 service()->WindowClosing(window2_id
);
440 service()->WindowClosed(window2_id
);
442 ScopedVector
<sessions::SessionWindow
> windows
;
443 ReadWindows(&(windows
.get()), NULL
);
445 ASSERT_EQ(2U, windows
.size());
446 ASSERT_EQ(1U, windows
[0]->tabs
.size());
447 ASSERT_EQ(1U, windows
[1]->tabs
.size());
450 TEST_F(SessionServiceTest
, WindowCloseCommittedAfterNavigate
) {
451 SessionID window2_id
;
454 ASSERT_NE(window2_id
.id(), window_id
.id());
456 service()->SetWindowType(window2_id
,
457 Browser::TYPE_TABBED
,
458 SessionService::TYPE_NORMAL
);
459 service()->SetWindowBounds(window2_id
,
461 ui::SHOW_STATE_NORMAL
);
463 SerializedNavigationEntry nav1
=
464 SerializedNavigationEntryTestHelper::CreateNavigation(
465 "http://google.com", "abc");
466 SerializedNavigationEntry nav2
=
467 SerializedNavigationEntryTestHelper::CreateNavigation(
468 "http://google2.com", "abcd");
470 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
471 UpdateNavigation(window_id
, tab_id
, nav1
, true);
473 helper_
.PrepareTabInWindow(window2_id
, tab2_id
, 0, false);
474 UpdateNavigation(window2_id
, tab2_id
, nav2
, true);
476 service()->WindowClosing(window2_id
);
477 service()->TabClosed(window2_id
, tab2_id
, false);
478 service()->WindowClosed(window2_id
);
480 ScopedVector
<sessions::SessionWindow
> windows
;
481 ReadWindows(&(windows
.get()), NULL
);
483 ASSERT_EQ(1U, windows
.size());
484 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
485 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
486 ASSERT_EQ(1U, windows
[0]->tabs
.size());
488 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
489 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
490 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
493 // Makes sure we don't track popups.
494 TEST_F(SessionServiceTest
, IgnorePopups
) {
495 SessionID window2_id
;
498 ASSERT_NE(window2_id
.id(), window_id
.id());
500 service()->SetWindowType(window2_id
,
502 SessionService::TYPE_NORMAL
);
503 service()->SetWindowBounds(window2_id
,
505 ui::SHOW_STATE_NORMAL
);
507 SerializedNavigationEntry nav1
=
508 SerializedNavigationEntryTestHelper::CreateNavigation(
509 "http://google.com", "abc");
510 SerializedNavigationEntry nav2
=
511 SerializedNavigationEntryTestHelper::CreateNavigation(
512 "http://google2.com", "abcd");
514 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
515 UpdateNavigation(window_id
, tab_id
, nav1
, true);
517 helper_
.PrepareTabInWindow(window2_id
, tab2_id
, 0, false);
518 UpdateNavigation(window2_id
, tab2_id
, nav2
, true);
520 ScopedVector
<sessions::SessionWindow
> windows
;
521 ReadWindows(&(windows
.get()), NULL
);
523 ASSERT_EQ(1U, windows
.size());
524 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
525 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
526 ASSERT_EQ(1U, windows
[0]->tabs
.size());
528 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
529 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
530 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
533 TEST_F(SessionServiceTest
, RemoveUnusedRestoreWindowsTest
) {
534 ScopedVector
<sessions::SessionWindow
> windows_list
;
535 windows_list
.push_back(new sessions::SessionWindow());
536 windows_list
.back()->type
= sessions::SessionWindow::TYPE_TABBED
;
537 windows_list
.push_back(new sessions::SessionWindow());
538 windows_list
.back()->type
= sessions::SessionWindow::TYPE_POPUP
;
540 service()->RemoveUnusedRestoreWindows(&(windows_list
.get()));
541 ASSERT_EQ(1U, windows_list
.size());
542 EXPECT_EQ(sessions::SessionWindow::TYPE_TABBED
, windows_list
[0]->type
);
545 #if defined (OS_CHROMEOS)
546 // Makes sure we track apps. Only applicable on chromeos.
547 TEST_F(SessionServiceTest
, RestoreApp
) {
548 SessionID window2_id
;
551 ASSERT_NE(window2_id
.id(), window_id
.id());
553 service()->SetWindowType(window2_id
,
555 SessionService::TYPE_APP
);
556 service()->SetWindowBounds(window2_id
,
558 ui::SHOW_STATE_NORMAL
);
559 service()->SetWindowAppName(window2_id
, "TestApp");
561 SerializedNavigationEntry nav1
=
562 SerializedNavigationEntryTestHelper::CreateNavigation(
563 "http://google.com", "abc");
564 SerializedNavigationEntry nav2
=
565 SerializedNavigationEntryTestHelper::CreateNavigation(
566 "http://google2.com", "abcd");
568 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
569 UpdateNavigation(window_id
, tab_id
, nav1
, true);
571 helper_
.PrepareTabInWindow(window2_id
, tab2_id
, 0, false);
572 UpdateNavigation(window2_id
, tab2_id
, nav2
, true);
574 ScopedVector
<sessions::SessionWindow
> windows
;
575 ReadWindows(&(windows
.get()), NULL
);
577 ASSERT_EQ(2U, windows
.size());
578 int tabbed_index
= windows
[0]->type
== sessions::SessionWindow::TYPE_TABBED
?
580 int app_index
= tabbed_index
== 0 ? 1 : 0;
581 ASSERT_EQ(0, windows
[tabbed_index
]->selected_tab_index
);
582 ASSERT_EQ(window_id
.id(), windows
[tabbed_index
]->window_id
.id());
583 ASSERT_EQ(1U, windows
[tabbed_index
]->tabs
.size());
585 sessions::SessionTab
* tab
= windows
[tabbed_index
]->tabs
[0];
586 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
587 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
589 ASSERT_EQ(0, windows
[app_index
]->selected_tab_index
);
590 ASSERT_EQ(window2_id
.id(), windows
[app_index
]->window_id
.id());
591 ASSERT_EQ(1U, windows
[app_index
]->tabs
.size());
592 ASSERT_TRUE(windows
[app_index
]->type
== sessions::SessionWindow::TYPE_POPUP
);
593 ASSERT_EQ("TestApp", windows
[app_index
]->app_name
);
595 tab
= windows
[app_index
]->tabs
[0];
596 helper_
.AssertTabEquals(window2_id
, tab2_id
, 0, 0, 1, *tab
);
597 helper_
.AssertNavigationEquals(nav2
, tab
->navigations
[0]);
599 #endif // defined (OS_CHROMEOS)
601 // Tests pruning from the front.
602 TEST_F(SessionServiceTest
, PruneFromFront
) {
603 const std::string
base_url("http://google.com/");
606 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
608 // Add 5 navigations, with the 4th selected.
609 for (int i
= 0; i
< 5; ++i
) {
610 SerializedNavigationEntry nav
=
611 SerializedNavigationEntryTestHelper::CreateNavigation(
612 base_url
+ base::IntToString(i
), "a");
614 UpdateNavigation(window_id
, tab_id
, nav
, (i
== 3));
617 // Prune the first two navigations from the front.
618 helper_
.service()->TabNavigationPathPrunedFromFront(window_id
, tab_id
, 2);
621 ScopedVector
<sessions::SessionWindow
> windows
;
622 ReadWindows(&(windows
.get()), NULL
);
624 ASSERT_EQ(1U, windows
.size());
625 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
626 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
627 ASSERT_EQ(1U, windows
[0]->tabs
.size());
629 // There shouldn't be an app id.
630 EXPECT_TRUE(windows
[0]->tabs
[0]->extension_app_id
.empty());
632 // We should be left with three navigations, the 2nd selected.
633 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
634 ASSERT_EQ(1, tab
->current_navigation_index
);
635 EXPECT_EQ(3U, tab
->navigations
.size());
636 EXPECT_TRUE(GURL(base_url
+ base::IntToString(2)) ==
637 tab
->navigations
[0].virtual_url());
638 EXPECT_TRUE(GURL(base_url
+ base::IntToString(3)) ==
639 tab
->navigations
[1].virtual_url());
640 EXPECT_TRUE(GURL(base_url
+ base::IntToString(4)) ==
641 tab
->navigations
[2].virtual_url());
644 // Prunes from front so that we have no entries.
645 TEST_F(SessionServiceTest
, PruneToEmpty
) {
646 const std::string
base_url("http://google.com/");
649 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
651 // Add 5 navigations, with the 4th selected.
652 for (int i
= 0; i
< 5; ++i
) {
653 SerializedNavigationEntry nav
=
654 SerializedNavigationEntryTestHelper::CreateNavigation(
655 base_url
+ base::IntToString(i
), "a");
657 UpdateNavigation(window_id
, tab_id
, nav
, (i
== 3));
660 // Prune the first two navigations from the front.
661 helper_
.service()->TabNavigationPathPrunedFromFront(window_id
, tab_id
, 5);
664 ScopedVector
<sessions::SessionWindow
> windows
;
665 ReadWindows(&(windows
.get()), NULL
);
667 ASSERT_EQ(0U, windows
.size());
670 // Don't set the pinned state and make sure the pinned value is false.
671 TEST_F(SessionServiceTest
, PinnedDefaultsToFalse
) {
672 EXPECT_FALSE(CreateAndWriteSessionWithOneTab(false, false));
675 // Explicitly set the pinned state to false and make sure we get back false.
676 TEST_F(SessionServiceTest
, PinnedFalseWhenSetToFalse
) {
677 EXPECT_FALSE(CreateAndWriteSessionWithOneTab(false, true));
680 // Explicitly set the pinned state to true and make sure we get back true.
681 TEST_F(SessionServiceTest
, PinnedTrue
) {
682 EXPECT_TRUE(CreateAndWriteSessionWithOneTab(true, true));
685 // Make sure application extension ids are persisted.
686 TEST_F(SessionServiceTest
, PersistApplicationExtensionID
) {
688 ASSERT_NE(window_id
.id(), tab_id
.id());
689 std::string
app_id("foo");
691 SerializedNavigationEntry nav1
=
692 SerializedNavigationEntryTestHelper::CreateNavigation(
693 "http://google.com", "abc");
695 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
696 UpdateNavigation(window_id
, tab_id
, nav1
, true);
697 helper_
.SetTabExtensionAppID(window_id
, tab_id
, app_id
);
699 ScopedVector
<sessions::SessionWindow
> windows
;
700 ReadWindows(&(windows
.get()), NULL
);
702 helper_
.AssertSingleWindowWithSingleTab(windows
.get(), 1);
703 EXPECT_TRUE(app_id
== windows
[0]->tabs
[0]->extension_app_id
);
706 // Check that user agent overrides are persisted.
707 TEST_F(SessionServiceTest
, PersistUserAgentOverrides
) {
709 ASSERT_NE(window_id
.id(), tab_id
.id());
710 std::string user_agent_override
= "Mozilla/5.0 (X11; Linux x86_64) "
711 "AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.45 "
714 SerializedNavigationEntry nav1
=
715 SerializedNavigationEntryTestHelper::CreateNavigation(
716 "http://google.com", "abc");
717 SerializedNavigationEntryTestHelper::SetIsOverridingUserAgent(true, &nav1
);
719 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
720 UpdateNavigation(window_id
, tab_id
, nav1
, true);
721 helper_
.SetTabUserAgentOverride(window_id
, tab_id
, user_agent_override
);
723 ScopedVector
<sessions::SessionWindow
> windows
;
724 ReadWindows(&(windows
.get()), NULL
);
725 helper_
.AssertSingleWindowWithSingleTab(windows
.get(), 1);
727 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
728 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
729 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
730 EXPECT_TRUE(user_agent_override
== tab
->user_agent_override
);
733 // Test that the notification for SESSION_SERVICE_SAVED is working properly.
734 TEST_F(SessionServiceTest
, SavedSessionNotification
) {
735 content::NotificationRegistrar registrar_
;
736 registrar_
.Add(this, chrome::NOTIFICATION_SESSION_SERVICE_SAVED
,
737 content::NotificationService::AllSources());
738 service()->GetBaseSessionServiceForTest()->Save();
739 EXPECT_EQ(sync_save_count_
, 1);
742 // Makes sure a tab closed by a user gesture is not restored.
743 TEST_F(SessionServiceTest
, CloseTabUserGesture
) {
745 ASSERT_NE(window_id
.id(), tab_id
.id());
747 SerializedNavigationEntry nav1
=
748 SerializedNavigationEntryTestHelper::CreateNavigation(
749 "http://google.com", "abc");
751 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
752 UpdateNavigation(window_id
, tab_id
, nav1
, true);
753 service()->TabClosed(window_id
, tab_id
, true);
755 ScopedVector
<sessions::SessionWindow
> windows
;
756 ReadWindows(&(windows
.get()), NULL
);
758 ASSERT_TRUE(windows
.empty());
761 // Verifies SetWindowBounds maps SHOW_STATE_DEFAULT to SHOW_STATE_NORMAL.
762 TEST_F(SessionServiceTest
, DontPersistDefault
) {
764 ASSERT_NE(window_id
.id(), tab_id
.id());
765 SerializedNavigationEntry nav1
=
766 SerializedNavigationEntryTestHelper::CreateNavigation(
767 "http://google.com", "abc");
768 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
769 UpdateNavigation(window_id
, tab_id
, nav1
, true);
770 service()->SetWindowBounds(window_id
,
772 ui::SHOW_STATE_DEFAULT
);
774 ScopedVector
<sessions::SessionWindow
> windows
;
775 ReadWindows(&(windows
.get()), NULL
);
776 ASSERT_EQ(1U, windows
.size());
777 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, windows
[0]->show_state
);
780 TEST_F(SessionServiceTest
, KeepPostDataWithoutPasswords
) {
782 ASSERT_NE(window_id
.id(), tab_id
.id());
784 // Create a page state representing a HTTP body without posted passwords.
785 content::PageState page_state
=
786 content::PageState::CreateForTesting(GURL(), false, "data", NULL
);
788 // Create a TabNavigation containing page_state and representing a POST
790 SerializedNavigationEntry nav1
=
791 SerializedNavigationEntryTestHelper::CreateNavigation(
792 "http://google.com", "title");
793 SerializedNavigationEntryTestHelper::SetEncodedPageState(
794 page_state
.ToEncodedData(), &nav1
);
795 SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1
);
797 // Create a TabNavigation containing page_state and representing a normal
799 SerializedNavigationEntry nav2
=
800 SerializedNavigationEntryTestHelper::CreateNavigation(
801 "http://google.com/nopost", "title");
802 SerializedNavigationEntryTestHelper::SetEncodedPageState(
803 page_state
.ToEncodedData(), &nav2
);
806 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
807 UpdateNavigation(window_id
, tab_id
, nav1
, true);
808 UpdateNavigation(window_id
, tab_id
, nav2
, true);
810 ScopedVector
<sessions::SessionWindow
> windows
;
811 ReadWindows(&(windows
.get()), NULL
);
813 helper_
.AssertSingleWindowWithSingleTab(windows
.get(), 2);
815 // Expected: the page state of both navigations was saved and restored.
816 ASSERT_EQ(2u, windows
[0]->tabs
[0]->navigations
.size());
817 helper_
.AssertNavigationEquals(nav1
, windows
[0]->tabs
[0]->navigations
[0]);
818 helper_
.AssertNavigationEquals(nav2
, windows
[0]->tabs
[0]->navigations
[1]);
821 TEST_F(SessionServiceTest
, RemovePostDataWithPasswords
) {
823 ASSERT_NE(window_id
.id(), tab_id
.id());
825 // Create a page state representing a HTTP body with posted passwords.
826 content::PageState page_state
=
827 content::PageState::CreateForTesting(GURL(), true, "data", NULL
);
829 // Create a TabNavigation containing page_state and representing a POST
830 // request with passwords.
831 SerializedNavigationEntry nav1
=
832 SerializedNavigationEntryTestHelper::CreateNavigation(
833 "http://google.com", "title");
834 SerializedNavigationEntryTestHelper::SetEncodedPageState(
835 page_state
.ToEncodedData(), &nav1
);
836 SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1
);
837 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
838 UpdateNavigation(window_id
, tab_id
, nav1
, true);
840 ScopedVector
<sessions::SessionWindow
> windows
;
841 ReadWindows(&(windows
.get()), NULL
);
843 helper_
.AssertSingleWindowWithSingleTab(windows
.get(), 1);
845 // Expected: the HTTP body was removed from the page state of the POST
846 // navigation with passwords.
847 EXPECT_NE(page_state
.ToEncodedData(),
848 windows
[0]->tabs
[0]->navigations
[0].encoded_page_state());
851 TEST_F(SessionServiceTest
, ReplacePendingNavigation
) {
852 const std::string
base_url("http://google.com/");
855 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
857 // Add 5 navigations, some with the same index
858 for (int i
= 0; i
< 5; ++i
) {
859 SerializedNavigationEntry nav
=
860 SerializedNavigationEntryTestHelper::CreateNavigation(
861 base_url
+ base::IntToString(i
), "a");
862 nav
.set_index(i
/ 2);
863 UpdateNavigation(window_id
, tab_id
, nav
, true);
867 ScopedVector
<sessions::SessionWindow
> windows
;
868 ReadWindows(&(windows
.get()), NULL
);
870 // The ones with index 0, and 2 should have been replaced by 1 and 3.
871 ASSERT_EQ(1U, windows
.size());
872 ASSERT_EQ(1U, windows
[0]->tabs
.size());
873 EXPECT_EQ(3U, windows
[0]->tabs
[0]->navigations
.size());
874 EXPECT_EQ(GURL(base_url
+ base::IntToString(1)),
875 windows
[0]->tabs
[0]->navigations
[0].virtual_url());
876 EXPECT_EQ(GURL(base_url
+ base::IntToString(3)),
877 windows
[0]->tabs
[0]->navigations
[1].virtual_url());
878 EXPECT_EQ(GURL(base_url
+ base::IntToString(4)),
879 windows
[0]->tabs
[0]->navigations
[2].virtual_url());
882 TEST_F(SessionServiceTest
, ReplacePendingNavigationAndPrune
) {
883 const std::string
base_url("http://google.com/");
886 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
888 for (int i
= 0; i
< 5; ++i
) {
889 SerializedNavigationEntry nav
=
890 SerializedNavigationEntryTestHelper::CreateNavigation(
891 base_url
+ base::IntToString(i
), "a");
893 UpdateNavigation(window_id
, tab_id
, nav
, true);
896 // Prune all those navigations.
897 helper_
.service()->TabNavigationPathPrunedFromFront(window_id
, tab_id
, 5);
899 // Add another navigation to replace the last one.
900 SerializedNavigationEntry nav
=
901 SerializedNavigationEntryTestHelper::CreateNavigation(
902 base_url
+ base::IntToString(5), "a");
904 UpdateNavigation(window_id
, tab_id
, nav
, true);
907 ScopedVector
<sessions::SessionWindow
> windows
;
908 ReadWindows(&(windows
.get()), NULL
);
910 // We should still have that last navigation at the end,
911 // even though it replaced one that was set before the prune.
912 ASSERT_EQ(1U, windows
.size());
913 ASSERT_EQ(1U, windows
[0]->tabs
.size());
914 ASSERT_EQ(1U, windows
[0]->tabs
[0]->navigations
.size());
915 EXPECT_EQ(GURL(base_url
+ base::IntToString(5)),
916 windows
[0]->tabs
[0]->navigations
[0].virtual_url());
919 TEST_F(SessionServiceTest
, RestoreActivation1
) {
920 SessionID window2_id
;
923 SerializedNavigationEntry nav1
;
924 SerializedNavigationEntry nav2
;
926 CreateAndWriteSessionWithTwoWindows(
927 window2_id
, tab1_id
, tab2_id
, &nav1
, &nav2
);
929 service()->ScheduleCommand(
930 sessions::CreateSetActiveWindowCommand(window2_id
).Pass());
931 service()->ScheduleCommand(
932 sessions::CreateSetActiveWindowCommand(window_id
).Pass());
934 ScopedVector
<sessions::SessionWindow
> windows
;
935 SessionID::id_type active_window_id
= 0;
936 ReadWindows(&(windows
.get()), &active_window_id
);
937 EXPECT_EQ(window_id
.id(), active_window_id
);
940 // It's easier to have two separate tests with setup/teardown than to manualy
941 // reset the state for the different flavors of the test.
942 TEST_F(SessionServiceTest
, RestoreActivation2
) {
943 SessionID window2_id
;
946 SerializedNavigationEntry nav1
;
947 SerializedNavigationEntry nav2
;
949 CreateAndWriteSessionWithTwoWindows(
950 window2_id
, tab1_id
, tab2_id
, &nav1
, &nav2
);
952 service()->ScheduleCommand(
953 sessions::CreateSetActiveWindowCommand(window2_id
).Pass());
954 service()->ScheduleCommand(
955 sessions::CreateSetActiveWindowCommand(window_id
).Pass());
956 service()->ScheduleCommand(
957 sessions::CreateSetActiveWindowCommand(window2_id
).Pass());
959 ScopedVector
<sessions::SessionWindow
> windows
;
960 SessionID::id_type active_window_id
= 0;
961 ReadWindows(&(windows
.get()), &active_window_id
);
962 EXPECT_EQ(window2_id
.id(), active_window_id
);
965 // Makes sure we don't track blacklisted URLs.
966 TEST_F(SessionServiceTest
, IgnoreBlacklistedUrls
) {
969 SerializedNavigationEntry nav1
=
970 SerializedNavigationEntryTestHelper::CreateNavigation(
971 "http://google.com", "abc");
972 SerializedNavigationEntry nav2
=
973 SerializedNavigationEntryTestHelper::CreateNavigation(
974 chrome::kChromeUIQuitURL
, "quit");
975 SerializedNavigationEntry nav3
=
976 SerializedNavigationEntryTestHelper::CreateNavigation(
977 chrome::kChromeUIRestartURL
, "restart");
979 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
980 UpdateNavigation(window_id
, tab_id
, nav1
, true);
981 UpdateNavigation(window_id
, tab_id
, nav2
, true);
982 UpdateNavigation(window_id
, tab_id
, nav3
, true);
984 ScopedVector
<sessions::SessionWindow
> windows
;
985 ReadWindows(&(windows
.get()), NULL
);
987 ASSERT_EQ(1U, windows
.size());
988 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
989 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
990 ASSERT_EQ(1U, windows
[0]->tabs
.size());
992 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
993 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
994 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
997 // Functions used by GetSessionsAndDestroy.
1000 void OnGotPreviousSession(ScopedVector
<sessions::SessionWindow
> windows
,
1001 SessionID::id_type ignored_active_window
) {
1002 FAIL() << "SessionService was destroyed, this shouldn't be reached.";
1005 void PostBackToThread(base::MessageLoop
* message_loop
,
1006 base::RunLoop
* run_loop
) {
1007 message_loop
->task_runner()->PostTask(
1008 FROM_HERE
, base::Bind(&base::RunLoop::Quit
, base::Unretained(run_loop
)));
1013 // Verifies that SessionService::GetLastSession() works correctly if the
1014 // SessionService is deleted during processing. To verify the problematic case
1015 // does the following:
1016 // 1. Sends a task to the background thread that blocks.
1017 // 2. Asks SessionService for the last session commands. This is blocked by 1.
1018 // 3. Posts another task to the background thread, this too is blocked by 1.
1019 // 4. Deletes SessionService.
1020 // 5. Signals the semaphore that 2 and 3 are waiting on, allowing
1021 // GetLastSession() to continue.
1022 // 6. runs the message loop, this is quit when the task scheduled in 3 posts
1023 // back to the ui thread to quit the run loop.
1024 // The call to get the previous session should never be invoked because the
1025 // SessionService was destroyed before SessionService could process the results.
1026 TEST_F(SessionServiceTest
, GetSessionsAndDestroy
) {
1027 base::CancelableTaskTracker cancelable_task_tracker
;
1028 base::RunLoop run_loop
;
1029 base::WaitableEvent
event(true, false);
1030 helper_
.RunTaskOnBackendThread(FROM_HERE
,
1031 base::Bind(&base::WaitableEvent::Wait
,
1032 base::Unretained(&event
)));
1033 service()->GetLastSession(base::Bind(&OnGotPreviousSession
),
1034 &cancelable_task_tracker
);
1035 helper_
.RunTaskOnBackendThread(
1037 base::Bind(&PostBackToThread
,
1038 base::Unretained(base::MessageLoop::current()),
1039 base::Unretained(&run_loop
)));
1040 delete helper_
.ReleaseService();