Fire an error if a pref used in the UI is missing once all prefs are fetched.
[chromium-blink-merge.git] / chrome / browser / sessions / session_service_unittest.cc
bloba2ed6057be4053e101f459d4b6ce8d77d08a5b05
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.
5 #include "base/bind.h"
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 {
45 public:
46 SessionServiceTest() : window_bounds(0, 1, 2, 3), sync_save_count_(0) {}
48 protected:
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,
64 Browser::TYPE_TABBED,
65 SessionService::TYPE_NORMAL);
66 service()->SetWindowBounds(window_id,
67 window_bounds,
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);
76 sync_save_count_++;
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,
88 bool select) {
89 service()->UpdateTabNavigation(window_id, tab_id, navigation);
90 if (select) {
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) {
116 SessionID tab_id;
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())
132 return false;
133 EXPECT_EQ(1U, windows[0]->tabs.size());
134 if (HasFatalFailure())
135 return false;
137 sessions::SessionTab* tab = windows[0]->tabs[0];
138 helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
140 return tab->pinned;
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,
162 window2_bounds,
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;
172 SessionID window_id;
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) {
185 SessionID tab_id;
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) {
215 SessionID tab_id;
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) {
233 SessionID tab_id;
234 SessionID tab2_id;
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) {
266 SessionID tab_id;
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;
278 nav->set_index(i);
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;
303 SessionID tab1_id;
304 SessionID tab2_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];
328 } else {
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]);
340 tab = rt2;
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;
347 SessionID tab1_id;
348 SessionID tab2_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,
362 window2_bounds,
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) {
380 SessionID tab_id;
381 SessionID tab2_id;
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;
418 SessionID tab1_id;
419 SessionID tab2_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;
450 SessionID tab_id;
451 SessionID tab2_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,
458 window_bounds,
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;
494 SessionID tab_id;
495 SessionID tab2_id;
496 ASSERT_NE(window2_id.id(), window_id.id());
498 service()->SetWindowType(window2_id,
499 Browser::TYPE_POPUP,
500 SessionService::TYPE_NORMAL);
501 service()->SetWindowBounds(window2_id,
502 window_bounds,
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;
547 SessionID tab_id;
548 SessionID tab2_id;
549 ASSERT_NE(window2_id.id(), window_id.id());
551 service()->SetWindowType(window2_id,
552 Browser::TYPE_POPUP,
553 SessionService::TYPE_APP);
554 service()->SetWindowBounds(window2_id,
555 window_bounds,
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 ?
577 0 : 1;
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/");
602 SessionID tab_id;
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");
611 nav.set_index(i);
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);
618 // Read back in.
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/");
645 SessionID tab_id;
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");
654 nav.set_index(i);
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);
661 // Read back in.
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) {
685 SessionID tab_id;
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) {
706 SessionID tab_id;
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 "
710 "Safari/535.19";
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) {
742 SessionID tab_id;
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) {
761 SessionID tab_id;
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,
769 window_bounds,
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) {
779 SessionID tab_id;
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
787 // request.
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
796 // request.
797 SerializedNavigationEntry nav2 =
798 SerializedNavigationEntryTestHelper::CreateNavigation(
799 "http://google.com/nopost", "title");
800 SerializedNavigationEntryTestHelper::SetEncodedPageState(
801 page_state.ToEncodedData(), &nav2);
802 nav2.set_index(1);
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) {
820 SessionID tab_id;
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/");
851 SessionID tab_id;
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);
864 // Read back in.
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/");
882 SessionID tab_id;
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");
890 nav.set_index(i);
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");
901 nav.set_index(4);
902 UpdateNavigation(window_id, tab_id, nav, true);
904 // Read back in.
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;
919 SessionID tab1_id;
920 SessionID tab2_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;
942 SessionID tab1_id;
943 SessionID tab2_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) {
965 SessionID tab_id;
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.
996 namespace {
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)));
1010 } // namespace
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(
1035 FROM_HERE,
1036 base::Bind(&PostBackToThread,
1037 base::Unretained(base::MessageLoop::current()),
1038 base::Unretained(&run_loop)));
1039 delete helper_.ReleaseService();
1040 event.Signal();
1041 run_loop.Run();