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