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/memory/scoped_ptr.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/run_loop.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/synchronization/waitable_event.h"
16 #include "base/time/time.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/defaults.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/browser/sessions/session_service.h"
22 #include "chrome/browser/sessions/session_service_test_helper.h"
23 #include "chrome/common/chrome_paths.h"
24 #include "chrome/common/url_constants.h"
25 #include "chrome/test/base/browser_with_test_window_test.h"
26 #include "chrome/test/base/testing_browser_process.h"
27 #include "chrome/test/base/testing_profile.h"
28 #include "chrome/test/base/testing_profile_manager.h"
29 #include "components/sessions/serialized_navigation_entry_test_helper.h"
30 #include "components/sessions/session_command.h"
31 #include "components/sessions/session_types.h"
32 #include "content/public/browser/navigation_entry.h"
33 #include "content/public/browser/notification_observer.h"
34 #include "content/public/browser/notification_registrar.h"
35 #include "content/public/browser/notification_service.h"
36 #include "content/public/common/page_state.h"
37 #include "testing/gtest/include/gtest/gtest.h"
39 using content::NavigationEntry
;
40 using sessions::SerializedNavigationEntry
;
41 using sessions::SerializedNavigationEntryTestHelper
;
43 class SessionServiceTest
: public BrowserWithTestWindowTest
,
44 public content::NotificationObserver
{
46 SessionServiceTest() : window_bounds(0, 1, 2, 3), sync_save_count_(0) {}
49 void SetUp() override
{
50 BrowserWithTestWindowTest::SetUp();
52 profile_manager_
.reset(
53 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
54 ASSERT_TRUE(profile_manager_
->SetUp());
56 std::string b
= base::Int64ToString(base::Time::Now().ToInternalValue());
57 TestingProfile
* profile
= profile_manager_
->CreateTestingProfile(b
);
58 SessionService
* session_service
= new SessionService(profile
);
59 path_
= profile
->GetPath();
61 helper_
.SetService(session_service
);
63 service()->SetWindowType(window_id
,
65 SessionService::TYPE_NORMAL
);
66 service()->SetWindowBounds(window_id
,
68 ui::SHOW_STATE_NORMAL
);
71 // Upon notification, increment the sync_save_count variable
72 void Observe(int type
,
73 const content::NotificationSource
& source
,
74 const content::NotificationDetails
& details
) override
{
75 ASSERT_EQ(type
, chrome::NOTIFICATION_SESSION_SERVICE_SAVED
);
79 void TearDown() override
{
80 helper_
.SetService(NULL
);
81 BrowserWithTestWindowTest::TearDown();
84 void UpdateNavigation(
85 const SessionID
& window_id
,
86 const SessionID
& tab_id
,
87 const SerializedNavigationEntry
& navigation
,
89 service()->UpdateTabNavigation(window_id
, tab_id
, navigation
);
91 service()->SetSelectedNavigationIndex(
92 window_id
, tab_id
, navigation
.index());
96 void ReadWindows(std::vector
<sessions::SessionWindow
*>* windows
,
97 SessionID::id_type
* active_window_id
) {
98 // Forces closing the file.
99 helper_
.SetService(NULL
);
101 SessionService
* session_service
= new SessionService(path_
);
102 helper_
.SetService(session_service
);
104 SessionID::id_type
* non_null_active_window_id
= active_window_id
;
105 SessionID::id_type dummy_active_window_id
= 0;
106 if (!non_null_active_window_id
)
107 non_null_active_window_id
= &dummy_active_window_id
;
108 helper_
.ReadWindows(windows
, non_null_active_window_id
);
111 // Configures the session service with one window with one tab and a single
112 // navigation. If |pinned_state| is true or |write_always| is true, the
113 // pinned state of the tab is updated. The session service is then recreated
114 // and the pinned state of the read back tab is returned.
115 bool CreateAndWriteSessionWithOneTab(bool pinned_state
, bool write_always
) {
117 SerializedNavigationEntry nav1
=
118 SerializedNavigationEntryTestHelper::CreateNavigation(
119 "http://google.com", "abc");
121 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
122 UpdateNavigation(window_id
, tab_id
, nav1
, true);
124 if (pinned_state
|| write_always
)
125 helper_
.service()->SetPinnedState(window_id
, tab_id
, pinned_state
);
127 ScopedVector
<sessions::SessionWindow
> windows
;
128 ReadWindows(&(windows
.get()), NULL
);
130 EXPECT_EQ(1U, windows
.size());
131 if (HasFatalFailure())
133 EXPECT_EQ(1U, windows
[0]->tabs
.size());
134 if (HasFatalFailure())
137 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
138 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
143 void CreateAndWriteSessionWithTwoWindows(
144 const SessionID
& window2_id
,
145 const SessionID
& tab1_id
,
146 const SessionID
& tab2_id
,
147 SerializedNavigationEntry
* nav1
,
148 SerializedNavigationEntry
* nav2
) {
149 *nav1
= SerializedNavigationEntryTestHelper::CreateNavigation(
150 "http://google.com", "abc");
151 *nav2
= SerializedNavigationEntryTestHelper::CreateNavigation(
152 "http://google2.com", "abcd");
154 helper_
.PrepareTabInWindow(window_id
, tab1_id
, 0, true);
155 UpdateNavigation(window_id
, tab1_id
, *nav1
, true);
157 const gfx::Rect
window2_bounds(3, 4, 5, 6);
158 service()->SetWindowType(window2_id
,
159 Browser::TYPE_TABBED
,
160 SessionService::TYPE_NORMAL
);
161 service()->SetWindowBounds(window2_id
,
163 ui::SHOW_STATE_MAXIMIZED
);
164 helper_
.PrepareTabInWindow(window2_id
, tab2_id
, 0, true);
165 UpdateNavigation(window2_id
, tab2_id
, *nav2
, true);
168 SessionService
* service() { return helper_
.service(); }
170 const gfx::Rect window_bounds
;
174 int sync_save_count_
;
176 // Path used in testing.
177 base::ScopedTempDir temp_dir_
;
178 base::FilePath path_
;
180 SessionServiceTestHelper helper_
;
181 scoped_ptr
<TestingProfileManager
> profile_manager_
;
184 TEST_F(SessionServiceTest
, Basic
) {
186 ASSERT_NE(window_id
.id(), tab_id
.id());
188 SerializedNavigationEntry nav1
=
189 SerializedNavigationEntryTestHelper::CreateNavigation(
190 "http://google.com", "abc");
191 SerializedNavigationEntryTestHelper::SetOriginalRequestURL(
192 GURL("http://original.request.com"), &nav1
);
194 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
195 UpdateNavigation(window_id
, tab_id
, nav1
, true);
197 ScopedVector
<sessions::SessionWindow
> windows
;
198 ReadWindows(&(windows
.get()), NULL
);
200 ASSERT_EQ(1U, windows
.size());
201 ASSERT_TRUE(window_bounds
== windows
[0]->bounds
);
202 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
203 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
204 ASSERT_EQ(1U, windows
[0]->tabs
.size());
205 ASSERT_EQ(sessions::SessionWindow::TYPE_TABBED
, windows
[0]->type
);
207 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
208 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
210 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
213 // Make sure we persist post entries.
214 TEST_F(SessionServiceTest
, PersistPostData
) {
216 ASSERT_NE(window_id
.id(), tab_id
.id());
218 SerializedNavigationEntry nav1
=
219 SerializedNavigationEntryTestHelper::CreateNavigation(
220 "http://google.com", "abc");
221 SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1
);
223 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
224 UpdateNavigation(window_id
, tab_id
, nav1
, true);
226 ScopedVector
<sessions::SessionWindow
> windows
;
227 ReadWindows(&(windows
.get()), NULL
);
229 helper_
.AssertSingleWindowWithSingleTab(windows
.get(), 1);
232 TEST_F(SessionServiceTest
, ClosingTabStaysClosed
) {
235 ASSERT_NE(tab_id
.id(), tab2_id
.id());
237 SerializedNavigationEntry nav1
=
238 SerializedNavigationEntryTestHelper::CreateNavigation(
239 "http://google.com", "abc");
240 SerializedNavigationEntry nav2
=
241 SerializedNavigationEntryTestHelper::CreateNavigation(
242 "http://google2.com", "abcd");
244 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
245 UpdateNavigation(window_id
, tab_id
, nav1
, true);
247 helper_
.PrepareTabInWindow(window_id
, tab2_id
, 1, false);
248 UpdateNavigation(window_id
, tab2_id
, nav2
, true);
249 service()->TabClosed(window_id
, tab2_id
, false);
251 ScopedVector
<sessions::SessionWindow
> windows
;
252 ReadWindows(&(windows
.get()), NULL
);
254 ASSERT_EQ(1U, windows
.size());
255 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
256 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
257 ASSERT_EQ(1U, windows
[0]->tabs
.size());
259 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
260 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
262 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
265 TEST_F(SessionServiceTest
, Pruning
) {
268 SerializedNavigationEntry nav1
=
269 SerializedNavigationEntryTestHelper::CreateNavigation(
270 "http://google.com", "abc");
271 SerializedNavigationEntry nav2
=
272 SerializedNavigationEntryTestHelper::CreateNavigation(
273 "http://google2.com", "abcd");
275 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
276 for (int i
= 0; i
< 6; ++i
) {
277 SerializedNavigationEntry
* nav
= (i
% 2) == 0 ? &nav1
: &nav2
;
279 UpdateNavigation(window_id
, tab_id
, *nav
, true);
281 service()->TabNavigationPathPrunedFromBack(window_id
, tab_id
, 3);
283 ScopedVector
<sessions::SessionWindow
> windows
;
284 ReadWindows(&(windows
.get()), NULL
);
286 ASSERT_EQ(1U, windows
.size());
287 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
288 ASSERT_EQ(1U, windows
[0]->tabs
.size());
290 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
291 // We left the selected index at 5, then pruned. When rereading the
292 // index should get reset to last valid navigation, which is 2.
293 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 2, 3, *tab
);
295 ASSERT_EQ(3u, tab
->navigations
.size());
296 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
297 helper_
.AssertNavigationEquals(nav2
, tab
->navigations
[1]);
298 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[2]);
301 TEST_F(SessionServiceTest
, TwoWindows
) {
302 SessionID window2_id
;
305 SerializedNavigationEntry nav1
;
306 SerializedNavigationEntry nav2
;
308 CreateAndWriteSessionWithTwoWindows(
309 window2_id
, tab1_id
, tab2_id
, &nav1
, &nav2
);
311 ScopedVector
<sessions::SessionWindow
> windows
;
312 ReadWindows(&(windows
.get()), NULL
);
314 ASSERT_EQ(2U, windows
.size());
315 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
316 ASSERT_EQ(0, windows
[1]->selected_tab_index
);
317 ASSERT_EQ(1U, windows
[0]->tabs
.size());
318 ASSERT_EQ(1U, windows
[1]->tabs
.size());
320 sessions::SessionTab
* rt1
;
321 sessions::SessionTab
* rt2
;
322 if (windows
[0]->window_id
.id() == window_id
.id()) {
323 ASSERT_EQ(window2_id
.id(), windows
[1]->window_id
.id());
324 ASSERT_EQ(ui::SHOW_STATE_NORMAL
, windows
[0]->show_state
);
325 ASSERT_EQ(ui::SHOW_STATE_MAXIMIZED
, windows
[1]->show_state
);
326 rt1
= windows
[0]->tabs
[0];
327 rt2
= windows
[1]->tabs
[0];
329 ASSERT_EQ(window2_id
.id(), windows
[0]->window_id
.id());
330 ASSERT_EQ(window_id
.id(), windows
[1]->window_id
.id());
331 ASSERT_EQ(ui::SHOW_STATE_MAXIMIZED
, windows
[0]->show_state
);
332 ASSERT_EQ(ui::SHOW_STATE_NORMAL
, windows
[1]->show_state
);
333 rt1
= windows
[1]->tabs
[0];
334 rt2
= windows
[0]->tabs
[0];
336 sessions::SessionTab
* tab
= rt1
;
337 helper_
.AssertTabEquals(window_id
, tab1_id
, 0, 0, 1, *tab
);
338 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
341 helper_
.AssertTabEquals(window2_id
, tab2_id
, 0, 0, 1, *tab
);
342 helper_
.AssertNavigationEquals(nav2
, tab
->navigations
[0]);
345 TEST_F(SessionServiceTest
, WindowWithNoTabsGetsPruned
) {
346 SessionID window2_id
;
350 SerializedNavigationEntry nav1
=
351 SerializedNavigationEntryTestHelper::CreateNavigation(
352 "http://google.com", "abc");
354 helper_
.PrepareTabInWindow(window_id
, tab1_id
, 0, true);
355 UpdateNavigation(window_id
, tab1_id
, nav1
, true);
357 const gfx::Rect
window2_bounds(3, 4, 5, 6);
358 service()->SetWindowType(window2_id
,
359 Browser::TYPE_TABBED
,
360 SessionService::TYPE_NORMAL
);
361 service()->SetWindowBounds(window2_id
,
363 ui::SHOW_STATE_NORMAL
);
364 helper_
.PrepareTabInWindow(window2_id
, tab2_id
, 0, true);
366 ScopedVector
<sessions::SessionWindow
> windows
;
367 ReadWindows(&(windows
.get()), NULL
);
369 ASSERT_EQ(1U, windows
.size());
370 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
371 ASSERT_EQ(1U, windows
[0]->tabs
.size());
372 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
374 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
375 helper_
.AssertTabEquals(window_id
, tab1_id
, 0, 0, 1, *tab
);
376 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
379 TEST_F(SessionServiceTest
, ClosingWindowDoesntCloseTabs
) {
382 ASSERT_NE(tab_id
.id(), tab2_id
.id());
384 SerializedNavigationEntry nav1
=
385 SerializedNavigationEntryTestHelper::CreateNavigation(
386 "http://google.com", "abc");
387 SerializedNavigationEntry nav2
=
388 SerializedNavigationEntryTestHelper::CreateNavigation(
389 "http://google2.com", "abcd");
391 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
392 UpdateNavigation(window_id
, tab_id
, nav1
, true);
394 helper_
.PrepareTabInWindow(window_id
, tab2_id
, 1, false);
395 UpdateNavigation(window_id
, tab2_id
, nav2
, true);
397 service()->WindowClosing(window_id
);
399 ScopedVector
<sessions::SessionWindow
> windows
;
400 ReadWindows(&(windows
.get()), NULL
);
402 ASSERT_EQ(1U, windows
.size());
403 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
404 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
405 ASSERT_EQ(2U, windows
[0]->tabs
.size());
407 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
408 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
409 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
411 tab
= windows
[0]->tabs
[1];
412 helper_
.AssertTabEquals(window_id
, tab2_id
, 1, 0, 1, *tab
);
413 helper_
.AssertNavigationEquals(nav2
, tab
->navigations
[0]);
416 TEST_F(SessionServiceTest
, LockingWindowRemembersAll
) {
417 SessionID window2_id
;
420 SerializedNavigationEntry nav1
;
421 SerializedNavigationEntry nav2
;
423 CreateAndWriteSessionWithTwoWindows(
424 window2_id
, tab1_id
, tab2_id
, &nav1
, &nav2
);
426 ASSERT_TRUE(service()->profile() != NULL
);
427 ASSERT_TRUE(g_browser_process
->profile_manager() != NULL
);
428 ProfileInfoCache
& profile_info
=
429 g_browser_process
->profile_manager()->GetProfileInfoCache();
430 size_t profile_index
= profile_info
.GetIndexOfProfileWithPath(
431 service()->profile()->GetPath());
432 ASSERT_NE(std::string::npos
, profile_index
);
433 profile_info
.SetProfileSigninRequiredAtIndex(profile_index
, true);
435 service()->WindowClosing(window_id
);
436 service()->WindowClosed(window_id
);
437 service()->WindowClosing(window2_id
);
438 service()->WindowClosed(window2_id
);
440 ScopedVector
<sessions::SessionWindow
> windows
;
441 ReadWindows(&(windows
.get()), NULL
);
443 ASSERT_EQ(2U, windows
.size());
444 ASSERT_EQ(1U, windows
[0]->tabs
.size());
445 ASSERT_EQ(1U, windows
[1]->tabs
.size());
448 TEST_F(SessionServiceTest
, WindowCloseCommittedAfterNavigate
) {
449 SessionID window2_id
;
452 ASSERT_NE(window2_id
.id(), window_id
.id());
454 service()->SetWindowType(window2_id
,
455 Browser::TYPE_TABBED
,
456 SessionService::TYPE_NORMAL
);
457 service()->SetWindowBounds(window2_id
,
459 ui::SHOW_STATE_NORMAL
);
461 SerializedNavigationEntry nav1
=
462 SerializedNavigationEntryTestHelper::CreateNavigation(
463 "http://google.com", "abc");
464 SerializedNavigationEntry nav2
=
465 SerializedNavigationEntryTestHelper::CreateNavigation(
466 "http://google2.com", "abcd");
468 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
469 UpdateNavigation(window_id
, tab_id
, nav1
, true);
471 helper_
.PrepareTabInWindow(window2_id
, tab2_id
, 0, false);
472 UpdateNavigation(window2_id
, tab2_id
, nav2
, true);
474 service()->WindowClosing(window2_id
);
475 service()->TabClosed(window2_id
, tab2_id
, false);
476 service()->WindowClosed(window2_id
);
478 ScopedVector
<sessions::SessionWindow
> windows
;
479 ReadWindows(&(windows
.get()), NULL
);
481 ASSERT_EQ(1U, windows
.size());
482 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
483 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
484 ASSERT_EQ(1U, windows
[0]->tabs
.size());
486 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
487 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
488 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
491 // Makes sure we don't track popups.
492 TEST_F(SessionServiceTest
, IgnorePopups
) {
493 SessionID window2_id
;
496 ASSERT_NE(window2_id
.id(), window_id
.id());
498 service()->SetWindowType(window2_id
,
500 SessionService::TYPE_NORMAL
);
501 service()->SetWindowBounds(window2_id
,
503 ui::SHOW_STATE_NORMAL
);
505 SerializedNavigationEntry nav1
=
506 SerializedNavigationEntryTestHelper::CreateNavigation(
507 "http://google.com", "abc");
508 SerializedNavigationEntry nav2
=
509 SerializedNavigationEntryTestHelper::CreateNavigation(
510 "http://google2.com", "abcd");
512 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
513 UpdateNavigation(window_id
, tab_id
, nav1
, true);
515 helper_
.PrepareTabInWindow(window2_id
, tab2_id
, 0, false);
516 UpdateNavigation(window2_id
, tab2_id
, nav2
, true);
518 ScopedVector
<sessions::SessionWindow
> windows
;
519 ReadWindows(&(windows
.get()), NULL
);
521 ASSERT_EQ(1U, windows
.size());
522 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
523 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
524 ASSERT_EQ(1U, windows
[0]->tabs
.size());
526 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
527 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
528 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
531 TEST_F(SessionServiceTest
, RemoveUnusedRestoreWindowsTest
) {
532 ScopedVector
<sessions::SessionWindow
> windows_list
;
533 windows_list
.push_back(new sessions::SessionWindow());
534 windows_list
.back()->type
= sessions::SessionWindow::TYPE_TABBED
;
535 windows_list
.push_back(new sessions::SessionWindow());
536 windows_list
.back()->type
= sessions::SessionWindow::TYPE_POPUP
;
538 service()->RemoveUnusedRestoreWindows(&(windows_list
.get()));
539 ASSERT_EQ(1U, windows_list
.size());
540 EXPECT_EQ(sessions::SessionWindow::TYPE_TABBED
, windows_list
[0]->type
);
543 #if defined (OS_CHROMEOS)
544 // Makes sure we track apps. Only applicable on chromeos.
545 TEST_F(SessionServiceTest
, RestoreApp
) {
546 SessionID window2_id
;
549 ASSERT_NE(window2_id
.id(), window_id
.id());
551 service()->SetWindowType(window2_id
,
553 SessionService::TYPE_APP
);
554 service()->SetWindowBounds(window2_id
,
556 ui::SHOW_STATE_NORMAL
);
557 service()->SetWindowAppName(window2_id
, "TestApp");
559 SerializedNavigationEntry nav1
=
560 SerializedNavigationEntryTestHelper::CreateNavigation(
561 "http://google.com", "abc");
562 SerializedNavigationEntry nav2
=
563 SerializedNavigationEntryTestHelper::CreateNavigation(
564 "http://google2.com", "abcd");
566 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
567 UpdateNavigation(window_id
, tab_id
, nav1
, true);
569 helper_
.PrepareTabInWindow(window2_id
, tab2_id
, 0, false);
570 UpdateNavigation(window2_id
, tab2_id
, nav2
, true);
572 ScopedVector
<sessions::SessionWindow
> windows
;
573 ReadWindows(&(windows
.get()), NULL
);
575 ASSERT_EQ(2U, windows
.size());
576 int tabbed_index
= windows
[0]->type
== sessions::SessionWindow::TYPE_TABBED
?
578 int app_index
= tabbed_index
== 0 ? 1 : 0;
579 ASSERT_EQ(0, windows
[tabbed_index
]->selected_tab_index
);
580 ASSERT_EQ(window_id
.id(), windows
[tabbed_index
]->window_id
.id());
581 ASSERT_EQ(1U, windows
[tabbed_index
]->tabs
.size());
583 sessions::SessionTab
* tab
= windows
[tabbed_index
]->tabs
[0];
584 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
585 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
587 ASSERT_EQ(0, windows
[app_index
]->selected_tab_index
);
588 ASSERT_EQ(window2_id
.id(), windows
[app_index
]->window_id
.id());
589 ASSERT_EQ(1U, windows
[app_index
]->tabs
.size());
590 ASSERT_TRUE(windows
[app_index
]->type
== sessions::SessionWindow::TYPE_POPUP
);
591 ASSERT_EQ("TestApp", windows
[app_index
]->app_name
);
593 tab
= windows
[app_index
]->tabs
[0];
594 helper_
.AssertTabEquals(window2_id
, tab2_id
, 0, 0, 1, *tab
);
595 helper_
.AssertNavigationEquals(nav2
, tab
->navigations
[0]);
597 #endif // defined (OS_CHROMEOS)
599 // Tests pruning from the front.
600 TEST_F(SessionServiceTest
, PruneFromFront
) {
601 const std::string
base_url("http://google.com/");
604 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
606 // Add 5 navigations, with the 4th selected.
607 for (int i
= 0; i
< 5; ++i
) {
608 SerializedNavigationEntry nav
=
609 SerializedNavigationEntryTestHelper::CreateNavigation(
610 base_url
+ base::IntToString(i
), "a");
612 UpdateNavigation(window_id
, tab_id
, nav
, (i
== 3));
615 // Prune the first two navigations from the front.
616 helper_
.service()->TabNavigationPathPrunedFromFront(window_id
, tab_id
, 2);
619 ScopedVector
<sessions::SessionWindow
> windows
;
620 ReadWindows(&(windows
.get()), NULL
);
622 ASSERT_EQ(1U, windows
.size());
623 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
624 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
625 ASSERT_EQ(1U, windows
[0]->tabs
.size());
627 // There shouldn't be an app id.
628 EXPECT_TRUE(windows
[0]->tabs
[0]->extension_app_id
.empty());
630 // We should be left with three navigations, the 2nd selected.
631 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
632 ASSERT_EQ(1, tab
->current_navigation_index
);
633 EXPECT_EQ(3U, tab
->navigations
.size());
634 EXPECT_TRUE(GURL(base_url
+ base::IntToString(2)) ==
635 tab
->navigations
[0].virtual_url());
636 EXPECT_TRUE(GURL(base_url
+ base::IntToString(3)) ==
637 tab
->navigations
[1].virtual_url());
638 EXPECT_TRUE(GURL(base_url
+ base::IntToString(4)) ==
639 tab
->navigations
[2].virtual_url());
642 // Prunes from front so that we have no entries.
643 TEST_F(SessionServiceTest
, PruneToEmpty
) {
644 const std::string
base_url("http://google.com/");
647 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
649 // Add 5 navigations, with the 4th selected.
650 for (int i
= 0; i
< 5; ++i
) {
651 SerializedNavigationEntry nav
=
652 SerializedNavigationEntryTestHelper::CreateNavigation(
653 base_url
+ base::IntToString(i
), "a");
655 UpdateNavigation(window_id
, tab_id
, nav
, (i
== 3));
658 // Prune the first two navigations from the front.
659 helper_
.service()->TabNavigationPathPrunedFromFront(window_id
, tab_id
, 5);
662 ScopedVector
<sessions::SessionWindow
> windows
;
663 ReadWindows(&(windows
.get()), NULL
);
665 ASSERT_EQ(0U, windows
.size());
668 // Don't set the pinned state and make sure the pinned value is false.
669 TEST_F(SessionServiceTest
, PinnedDefaultsToFalse
) {
670 EXPECT_FALSE(CreateAndWriteSessionWithOneTab(false, false));
673 // Explicitly set the pinned state to false and make sure we get back false.
674 TEST_F(SessionServiceTest
, PinnedFalseWhenSetToFalse
) {
675 EXPECT_FALSE(CreateAndWriteSessionWithOneTab(false, true));
678 // Explicitly set the pinned state to true and make sure we get back true.
679 TEST_F(SessionServiceTest
, PinnedTrue
) {
680 EXPECT_TRUE(CreateAndWriteSessionWithOneTab(true, true));
683 // Make sure application extension ids are persisted.
684 TEST_F(SessionServiceTest
, PersistApplicationExtensionID
) {
686 ASSERT_NE(window_id
.id(), tab_id
.id());
687 std::string
app_id("foo");
689 SerializedNavigationEntry nav1
=
690 SerializedNavigationEntryTestHelper::CreateNavigation(
691 "http://google.com", "abc");
693 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
694 UpdateNavigation(window_id
, tab_id
, nav1
, true);
695 helper_
.SetTabExtensionAppID(window_id
, tab_id
, app_id
);
697 ScopedVector
<sessions::SessionWindow
> windows
;
698 ReadWindows(&(windows
.get()), NULL
);
700 helper_
.AssertSingleWindowWithSingleTab(windows
.get(), 1);
701 EXPECT_TRUE(app_id
== windows
[0]->tabs
[0]->extension_app_id
);
704 // Check that user agent overrides are persisted.
705 TEST_F(SessionServiceTest
, PersistUserAgentOverrides
) {
707 ASSERT_NE(window_id
.id(), tab_id
.id());
708 std::string user_agent_override
= "Mozilla/5.0 (X11; Linux x86_64) "
709 "AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.45 "
712 SerializedNavigationEntry nav1
=
713 SerializedNavigationEntryTestHelper::CreateNavigation(
714 "http://google.com", "abc");
715 SerializedNavigationEntryTestHelper::SetIsOverridingUserAgent(true, &nav1
);
717 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
718 UpdateNavigation(window_id
, tab_id
, nav1
, true);
719 helper_
.SetTabUserAgentOverride(window_id
, tab_id
, user_agent_override
);
721 ScopedVector
<sessions::SessionWindow
> windows
;
722 ReadWindows(&(windows
.get()), NULL
);
723 helper_
.AssertSingleWindowWithSingleTab(windows
.get(), 1);
725 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
726 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
727 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
728 EXPECT_TRUE(user_agent_override
== tab
->user_agent_override
);
731 // Test that the notification for SESSION_SERVICE_SAVED is working properly.
732 TEST_F(SessionServiceTest
, SavedSessionNotification
) {
733 content::NotificationRegistrar registrar_
;
734 registrar_
.Add(this, chrome::NOTIFICATION_SESSION_SERVICE_SAVED
,
735 content::NotificationService::AllSources());
736 service()->GetBaseSessionServiceForTest()->Save();
737 EXPECT_EQ(sync_save_count_
, 1);
740 // Makes sure a tab closed by a user gesture is not restored.
741 TEST_F(SessionServiceTest
, CloseTabUserGesture
) {
743 ASSERT_NE(window_id
.id(), tab_id
.id());
745 SerializedNavigationEntry nav1
=
746 SerializedNavigationEntryTestHelper::CreateNavigation(
747 "http://google.com", "abc");
749 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
750 UpdateNavigation(window_id
, tab_id
, nav1
, true);
751 service()->TabClosed(window_id
, tab_id
, true);
753 ScopedVector
<sessions::SessionWindow
> windows
;
754 ReadWindows(&(windows
.get()), NULL
);
756 ASSERT_TRUE(windows
.empty());
759 // Verifies SetWindowBounds maps SHOW_STATE_DEFAULT to SHOW_STATE_NORMAL.
760 TEST_F(SessionServiceTest
, DontPersistDefault
) {
762 ASSERT_NE(window_id
.id(), tab_id
.id());
763 SerializedNavigationEntry nav1
=
764 SerializedNavigationEntryTestHelper::CreateNavigation(
765 "http://google.com", "abc");
766 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
767 UpdateNavigation(window_id
, tab_id
, nav1
, true);
768 service()->SetWindowBounds(window_id
,
770 ui::SHOW_STATE_DEFAULT
);
772 ScopedVector
<sessions::SessionWindow
> windows
;
773 ReadWindows(&(windows
.get()), NULL
);
774 ASSERT_EQ(1U, windows
.size());
775 EXPECT_EQ(ui::SHOW_STATE_NORMAL
, windows
[0]->show_state
);
778 TEST_F(SessionServiceTest
, KeepPostDataWithoutPasswords
) {
780 ASSERT_NE(window_id
.id(), tab_id
.id());
782 // Create a page state representing a HTTP body without posted passwords.
783 content::PageState page_state
=
784 content::PageState::CreateForTesting(GURL(), false, "data", NULL
);
786 // Create a TabNavigation containing page_state and representing a POST
788 SerializedNavigationEntry nav1
=
789 SerializedNavigationEntryTestHelper::CreateNavigation(
790 "http://google.com", "title");
791 SerializedNavigationEntryTestHelper::SetEncodedPageState(
792 page_state
.ToEncodedData(), &nav1
);
793 SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1
);
795 // Create a TabNavigation containing page_state and representing a normal
797 SerializedNavigationEntry nav2
=
798 SerializedNavigationEntryTestHelper::CreateNavigation(
799 "http://google.com/nopost", "title");
800 SerializedNavigationEntryTestHelper::SetEncodedPageState(
801 page_state
.ToEncodedData(), &nav2
);
804 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
805 UpdateNavigation(window_id
, tab_id
, nav1
, true);
806 UpdateNavigation(window_id
, tab_id
, nav2
, true);
808 ScopedVector
<sessions::SessionWindow
> windows
;
809 ReadWindows(&(windows
.get()), NULL
);
811 helper_
.AssertSingleWindowWithSingleTab(windows
.get(), 2);
813 // Expected: the page state of both navigations was saved and restored.
814 ASSERT_EQ(2u, windows
[0]->tabs
[0]->navigations
.size());
815 helper_
.AssertNavigationEquals(nav1
, windows
[0]->tabs
[0]->navigations
[0]);
816 helper_
.AssertNavigationEquals(nav2
, windows
[0]->tabs
[0]->navigations
[1]);
819 TEST_F(SessionServiceTest
, RemovePostDataWithPasswords
) {
821 ASSERT_NE(window_id
.id(), tab_id
.id());
823 // Create a page state representing a HTTP body with posted passwords.
824 content::PageState page_state
=
825 content::PageState::CreateForTesting(GURL(), true, "data", NULL
);
827 // Create a TabNavigation containing page_state and representing a POST
828 // request with passwords.
829 SerializedNavigationEntry nav1
=
830 SerializedNavigationEntryTestHelper::CreateNavigation(
831 "http://google.com", "title");
832 SerializedNavigationEntryTestHelper::SetEncodedPageState(
833 page_state
.ToEncodedData(), &nav1
);
834 SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1
);
835 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
836 UpdateNavigation(window_id
, tab_id
, nav1
, true);
838 ScopedVector
<sessions::SessionWindow
> windows
;
839 ReadWindows(&(windows
.get()), NULL
);
841 helper_
.AssertSingleWindowWithSingleTab(windows
.get(), 1);
843 // Expected: the HTTP body was removed from the page state of the POST
844 // navigation with passwords.
845 EXPECT_NE(page_state
.ToEncodedData(),
846 windows
[0]->tabs
[0]->navigations
[0].encoded_page_state());
849 TEST_F(SessionServiceTest
, ReplacePendingNavigation
) {
850 const std::string
base_url("http://google.com/");
853 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
855 // Add 5 navigations, some with the same index
856 for (int i
= 0; i
< 5; ++i
) {
857 SerializedNavigationEntry nav
=
858 SerializedNavigationEntryTestHelper::CreateNavigation(
859 base_url
+ base::IntToString(i
), "a");
860 nav
.set_index(i
/ 2);
861 UpdateNavigation(window_id
, tab_id
, nav
, true);
865 ScopedVector
<sessions::SessionWindow
> windows
;
866 ReadWindows(&(windows
.get()), NULL
);
868 // The ones with index 0, and 2 should have been replaced by 1 and 3.
869 ASSERT_EQ(1U, windows
.size());
870 ASSERT_EQ(1U, windows
[0]->tabs
.size());
871 EXPECT_EQ(3U, windows
[0]->tabs
[0]->navigations
.size());
872 EXPECT_EQ(GURL(base_url
+ base::IntToString(1)),
873 windows
[0]->tabs
[0]->navigations
[0].virtual_url());
874 EXPECT_EQ(GURL(base_url
+ base::IntToString(3)),
875 windows
[0]->tabs
[0]->navigations
[1].virtual_url());
876 EXPECT_EQ(GURL(base_url
+ base::IntToString(4)),
877 windows
[0]->tabs
[0]->navigations
[2].virtual_url());
880 TEST_F(SessionServiceTest
, ReplacePendingNavigationAndPrune
) {
881 const std::string
base_url("http://google.com/");
884 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
886 for (int i
= 0; i
< 5; ++i
) {
887 SerializedNavigationEntry nav
=
888 SerializedNavigationEntryTestHelper::CreateNavigation(
889 base_url
+ base::IntToString(i
), "a");
891 UpdateNavigation(window_id
, tab_id
, nav
, true);
894 // Prune all those navigations.
895 helper_
.service()->TabNavigationPathPrunedFromFront(window_id
, tab_id
, 5);
897 // Add another navigation to replace the last one.
898 SerializedNavigationEntry nav
=
899 SerializedNavigationEntryTestHelper::CreateNavigation(
900 base_url
+ base::IntToString(5), "a");
902 UpdateNavigation(window_id
, tab_id
, nav
, true);
905 ScopedVector
<sessions::SessionWindow
> windows
;
906 ReadWindows(&(windows
.get()), NULL
);
908 // We should still have that last navigation at the end,
909 // even though it replaced one that was set before the prune.
910 ASSERT_EQ(1U, windows
.size());
911 ASSERT_EQ(1U, windows
[0]->tabs
.size());
912 ASSERT_EQ(1U, windows
[0]->tabs
[0]->navigations
.size());
913 EXPECT_EQ(GURL(base_url
+ base::IntToString(5)),
914 windows
[0]->tabs
[0]->navigations
[0].virtual_url());
917 TEST_F(SessionServiceTest
, RestoreActivation1
) {
918 SessionID window2_id
;
921 SerializedNavigationEntry nav1
;
922 SerializedNavigationEntry nav2
;
924 CreateAndWriteSessionWithTwoWindows(
925 window2_id
, tab1_id
, tab2_id
, &nav1
, &nav2
);
927 service()->ScheduleCommand(
928 sessions::CreateSetActiveWindowCommand(window2_id
).Pass());
929 service()->ScheduleCommand(
930 sessions::CreateSetActiveWindowCommand(window_id
).Pass());
932 ScopedVector
<sessions::SessionWindow
> windows
;
933 SessionID::id_type active_window_id
= 0;
934 ReadWindows(&(windows
.get()), &active_window_id
);
935 EXPECT_EQ(window_id
.id(), active_window_id
);
938 // It's easier to have two separate tests with setup/teardown than to manualy
939 // reset the state for the different flavors of the test.
940 TEST_F(SessionServiceTest
, RestoreActivation2
) {
941 SessionID window2_id
;
944 SerializedNavigationEntry nav1
;
945 SerializedNavigationEntry nav2
;
947 CreateAndWriteSessionWithTwoWindows(
948 window2_id
, tab1_id
, tab2_id
, &nav1
, &nav2
);
950 service()->ScheduleCommand(
951 sessions::CreateSetActiveWindowCommand(window2_id
).Pass());
952 service()->ScheduleCommand(
953 sessions::CreateSetActiveWindowCommand(window_id
).Pass());
954 service()->ScheduleCommand(
955 sessions::CreateSetActiveWindowCommand(window2_id
).Pass());
957 ScopedVector
<sessions::SessionWindow
> windows
;
958 SessionID::id_type active_window_id
= 0;
959 ReadWindows(&(windows
.get()), &active_window_id
);
960 EXPECT_EQ(window2_id
.id(), active_window_id
);
963 // Makes sure we don't track blacklisted URLs.
964 TEST_F(SessionServiceTest
, IgnoreBlacklistedUrls
) {
967 SerializedNavigationEntry nav1
=
968 SerializedNavigationEntryTestHelper::CreateNavigation(
969 "http://google.com", "abc");
970 SerializedNavigationEntry nav2
=
971 SerializedNavigationEntryTestHelper::CreateNavigation(
972 chrome::kChromeUIQuitURL
, "quit");
973 SerializedNavigationEntry nav3
=
974 SerializedNavigationEntryTestHelper::CreateNavigation(
975 chrome::kChromeUIRestartURL
, "restart");
977 helper_
.PrepareTabInWindow(window_id
, tab_id
, 0, true);
978 UpdateNavigation(window_id
, tab_id
, nav1
, true);
979 UpdateNavigation(window_id
, tab_id
, nav2
, true);
980 UpdateNavigation(window_id
, tab_id
, nav3
, true);
982 ScopedVector
<sessions::SessionWindow
> windows
;
983 ReadWindows(&(windows
.get()), NULL
);
985 ASSERT_EQ(1U, windows
.size());
986 ASSERT_EQ(0, windows
[0]->selected_tab_index
);
987 ASSERT_EQ(window_id
.id(), windows
[0]->window_id
.id());
988 ASSERT_EQ(1U, windows
[0]->tabs
.size());
990 sessions::SessionTab
* tab
= windows
[0]->tabs
[0];
991 helper_
.AssertTabEquals(window_id
, tab_id
, 0, 0, 1, *tab
);
992 helper_
.AssertNavigationEquals(nav1
, tab
->navigations
[0]);
995 // Functions used by GetSessionsAndDestroy.
998 void OnGotPreviousSession(ScopedVector
<sessions::SessionWindow
> windows
,
999 SessionID::id_type ignored_active_window
) {
1000 FAIL() << "SessionService was destroyed, this shouldn't be reached.";
1003 void PostBackToThread(base::MessageLoop
* message_loop
,
1004 base::RunLoop
* run_loop
) {
1005 message_loop
->PostTask(FROM_HERE
,
1006 base::Bind(&base::RunLoop::Quit
,
1007 base::Unretained(run_loop
)));
1012 // Verifies that SessionService::GetLastSession() works correctly if the
1013 // SessionService is deleted during processing. To verify the problematic case
1014 // does the following:
1015 // 1. Sends a task to the background thread that blocks.
1016 // 2. Asks SessionService for the last session commands. This is blocked by 1.
1017 // 3. Posts another task to the background thread, this too is blocked by 1.
1018 // 4. Deletes SessionService.
1019 // 5. Signals the semaphore that 2 and 3 are waiting on, allowing
1020 // GetLastSession() to continue.
1021 // 6. runs the message loop, this is quit when the task scheduled in 3 posts
1022 // back to the ui thread to quit the run loop.
1023 // The call to get the previous session should never be invoked because the
1024 // SessionService was destroyed before SessionService could process the results.
1025 TEST_F(SessionServiceTest
, GetSessionsAndDestroy
) {
1026 base::CancelableTaskTracker cancelable_task_tracker
;
1027 base::RunLoop run_loop
;
1028 base::WaitableEvent
event(true, false);
1029 helper_
.RunTaskOnBackendThread(FROM_HERE
,
1030 base::Bind(&base::WaitableEvent::Wait
,
1031 base::Unretained(&event
)));
1032 service()->GetLastSession(base::Bind(&OnGotPreviousSession
),
1033 &cancelable_task_tracker
);
1034 helper_
.RunTaskOnBackendThread(
1036 base::Bind(&PostBackToThread
,
1037 base::Unretained(base::MessageLoop::current()),
1038 base::Unretained(&run_loop
)));
1039 delete helper_
.ReleaseService();