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