persistent_tab_restore_service_browsertest.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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 "chrome/browser/sessions/persistent_tab_restore_service.h" 6 7#include "base/compiler_specific.h" 8#include "base/run_loop.h" 9#include "base/strings/stringprintf.h" 10#include "base/strings/utf_string_conversions.h" 11#include "chrome/browser/chrome_notification_types.h" 12#include "chrome/browser/profiles/profile.h" 13#include "chrome/browser/sessions/session_service.h" 14#include "chrome/browser/sessions/session_service_factory.h" 15#include "chrome/browser/sessions/session_types.h" 16#include "chrome/browser/sessions/tab_restore_service_factory.h" 17#include "chrome/browser/sessions/tab_restore_service_observer.h" 18#include "chrome/browser/ui/browser_window.h" 19#include "chrome/common/url_constants.h" 20#include "chrome/test/base/chrome_render_view_host_test_harness.h" 21#include "chrome/test/base/chrome_render_view_test.h" 22#include "chrome/test/base/in_process_browser_test.h" 23#include "chrome/test/base/testing_profile.h" 24#include "components/sessions/serialized_navigation_entry_test_helper.h" 25#include "content/public/browser/browser_thread.h" 26#include "content/public/browser/navigation_controller.h" 27#include "content/public/browser/navigation_entry.h" 28#include "content/public/browser/notification_service.h" 29#include "content/public/browser/notification_types.h" 30#include "content/public/browser/web_contents.h" 31#include "content/public/test/render_view_test.h" 32#include "content/public/test/test_utils.h" 33#include "content/public/test/web_contents_tester.h" 34#include "testing/gtest/include/gtest/gtest.h" 35#include "third_party/WebKit/public/web/WebKit.h" 36 37typedef TabRestoreService::Tab Tab; 38typedef TabRestoreService::Window Window; 39 40using content::NavigationEntry; 41using content::WebContentsTester; 42using sessions::SerializedNavigationEntry; 43using sessions::SerializedNavigationEntryTestHelper; 44 45// Create subclass that overrides TimeNow so that we can control the time used 46// for closed tabs and windows. 47class PersistentTabRestoreTimeFactory : public TabRestoreService::TimeFactory { 48 public: 49 PersistentTabRestoreTimeFactory() : time_(base::Time::Now()) {} 50 51 virtual ~PersistentTabRestoreTimeFactory() {} 52 53 virtual base::Time TimeNow() OVERRIDE { 54 return time_; 55 } 56 57 private: 58 base::Time time_; 59}; 60 61class PersistentTabRestoreServiceTest : public ChromeRenderViewHostTestHarness { 62 public: 63 PersistentTabRestoreServiceTest() 64 : url1_("http://1"), 65 url2_("http://2"), 66 url3_("http://3"), 67 user_agent_override_( 68 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19" 69 " (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19") { 70 } 71 72 virtual ~PersistentTabRestoreServiceTest() { 73 } 74 75 protected: 76 enum { 77 kMaxEntries = TabRestoreServiceHelper::kMaxEntries, 78 }; 79 80 // testing::Test: 81 virtual void SetUp() OVERRIDE { 82 WebKit::initialize(webkit_platform_support_.Get()); 83 ChromeRenderViewHostTestHarness::SetUp(); 84 time_factory_ = new PersistentTabRestoreTimeFactory(); 85 service_.reset(new PersistentTabRestoreService(profile(), time_factory_)); 86 } 87 88 virtual void TearDown() OVERRIDE { 89 service_->Shutdown(); 90 service_.reset(); 91 delete time_factory_; 92 ChromeRenderViewHostTestHarness::TearDown(); 93 WebKit::shutdown(); 94 } 95 96 TabRestoreService::Entries* mutable_entries() { 97 return service_->mutable_entries(); 98 } 99 100 void PruneEntries() { 101 service_->PruneEntries(); 102 } 103 104 void AddThreeNavigations() { 105 // Navigate to three URLs. 106 NavigateAndCommit(url1_); 107 NavigateAndCommit(url2_); 108 NavigateAndCommit(url3_); 109 } 110 111 void NavigateToIndex(int index) { 112 // Navigate back. We have to do this song and dance as NavigationController 113 // isn't happy if you navigate immediately while going back. 114 controller().GoToIndex(index); 115 WebContentsTester::For(web_contents())->CommitPendingNavigation(); 116 } 117 118 void RecreateService() { 119 // Must set service to null first so that it is destroyed before the new 120 // one is created. 121 service_->Shutdown(); 122 service_.reset(); 123 service_.reset(new PersistentTabRestoreService(profile(), time_factory_)); 124 SynchronousLoadTabsFromLastSession(); 125 } 126 127 // Adds a window with one tab and url to the profile's session service. 128 // If |pinned| is true, the tab is marked as pinned in the session service. 129 void AddWindowWithOneTabToSessionService(bool pinned) { 130 SessionService* session_service = 131 SessionServiceFactory::GetForProfile(profile()); 132 SessionID tab_id; 133 SessionID window_id; 134 session_service->SetWindowType( 135 window_id, Browser::TYPE_TABBED, SessionService::TYPE_NORMAL); 136 session_service->SetTabWindow(window_id, tab_id); 137 session_service->SetTabIndexInWindow(window_id, tab_id, 0); 138 session_service->SetSelectedTabInWindow(window_id, 0); 139 if (pinned) 140 session_service->SetPinnedState(window_id, tab_id, true); 141 session_service->UpdateTabNavigation( 142 window_id, tab_id, 143 SerializedNavigationEntryTestHelper::CreateNavigation( 144 url1_.spec(), "title")); 145 } 146 147 // Creates a SessionService and assigns it to the Profile. The SessionService 148 // is configured with a single window with a single tab pointing at url1_ by 149 // way of AddWindowWithOneTabToSessionService. If |pinned| is true, the 150 // tab is marked as pinned in the session service. 151 void CreateSessionServiceWithOneWindow(bool pinned) { 152 // The profile takes ownership of this. 153 SessionService* session_service = new SessionService(profile()); 154 SessionServiceFactory::SetForTestProfile(profile(), session_service); 155 156 AddWindowWithOneTabToSessionService(pinned); 157 158 // Set this, otherwise previous session won't be loaded. 159 profile()->set_last_session_exited_cleanly(false); 160 } 161 162 void SynchronousLoadTabsFromLastSession() { 163 // Ensures that the load is complete before continuing. 164 service_->LoadTabsFromLastSession(); 165 base::RunLoop().RunUntilIdle(); 166 } 167 168 GURL url1_; 169 GURL url2_; 170 GURL url3_; 171 std::string user_agent_override_; 172 scoped_ptr<PersistentTabRestoreService> service_; 173 PersistentTabRestoreTimeFactory* time_factory_; 174 content::RenderViewTest::RendererWebKitPlatformSupportImplNoSandbox 175 webkit_platform_support_; 176}; 177 178namespace { 179 180class TestTabRestoreServiceObserver : public TabRestoreServiceObserver { 181 public: 182 TestTabRestoreServiceObserver() : got_loaded_(false) {} 183 184 void clear_got_loaded() { got_loaded_ = false; } 185 bool got_loaded() const { return got_loaded_; } 186 187 // TabRestoreServiceObserver: 188 virtual void TabRestoreServiceChanged(TabRestoreService* service) OVERRIDE { 189 } 190 virtual void TabRestoreServiceDestroyed(TabRestoreService* service) OVERRIDE { 191 } 192 virtual void TabRestoreServiceLoaded(TabRestoreService* service) OVERRIDE { 193 got_loaded_ = true; 194 } 195 196 private: 197 // Was TabRestoreServiceLoaded() invoked? 198 bool got_loaded_; 199 200 DISALLOW_COPY_AND_ASSIGN(TestTabRestoreServiceObserver); 201}; 202 203} // namespace 204 205TEST_F(PersistentTabRestoreServiceTest, Basic) { 206 AddThreeNavigations(); 207 208 // Have the service record the tab. 209 service_->CreateHistoricalTab(web_contents(), -1); 210 211 // Make sure an entry was created. 212 ASSERT_EQ(1U, service_->entries().size()); 213 214 // Make sure the entry matches. 215 TabRestoreService::Entry* entry = service_->entries().front(); 216 ASSERT_EQ(TabRestoreService::TAB, entry->type); 217 Tab* tab = static_cast<Tab*>(entry); 218 EXPECT_FALSE(tab->pinned); 219 EXPECT_TRUE(tab->extension_app_id.empty()); 220 ASSERT_EQ(3U, tab->navigations.size()); 221 EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url()); 222 EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url()); 223 EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url()); 224 EXPECT_EQ("", tab->user_agent_override); 225 EXPECT_EQ(2, tab->current_navigation_index); 226 EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(), 227 tab->timestamp.ToInternalValue()); 228 229 NavigateToIndex(1); 230 231 // And check again, but set the user agent override this time. 232 web_contents()->SetUserAgentOverride(user_agent_override_); 233 service_->CreateHistoricalTab(web_contents(), -1); 234 235 // There should be two entries now. 236 ASSERT_EQ(2U, service_->entries().size()); 237 238 // Make sure the entry matches. 239 entry = service_->entries().front(); 240 ASSERT_EQ(TabRestoreService::TAB, entry->type); 241 tab = static_cast<Tab*>(entry); 242 EXPECT_FALSE(tab->pinned); 243 ASSERT_EQ(3U, tab->navigations.size()); 244 EXPECT_EQ(url1_, tab->navigations[0].virtual_url()); 245 EXPECT_EQ(url2_, tab->navigations[1].virtual_url()); 246 EXPECT_EQ(url3_, tab->navigations[2].virtual_url()); 247 EXPECT_EQ(user_agent_override_, tab->user_agent_override); 248 EXPECT_EQ(1, tab->current_navigation_index); 249 EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(), 250 tab->timestamp.ToInternalValue()); 251} 252 253// Make sure TabRestoreService doesn't create an entry for a tab with no 254// navigations. 255TEST_F(PersistentTabRestoreServiceTest, DontCreateEmptyTab) { 256 service_->CreateHistoricalTab(web_contents(), -1); 257 EXPECT_TRUE(service_->entries().empty()); 258} 259 260// Tests restoring a single tab. 261TEST_F(PersistentTabRestoreServiceTest, Restore) { 262 AddThreeNavigations(); 263 264 // Have the service record the tab. 265 service_->CreateHistoricalTab(web_contents(), -1); 266 267 // Recreate the service and have it load the tabs. 268 RecreateService(); 269 270 // One entry should be created. 271 ASSERT_EQ(1U, service_->entries().size()); 272 273 // And verify the entry. 274 PersistentTabRestoreService::Entry* entry = service_->entries().front(); 275 ASSERT_EQ(TabRestoreService::TAB, entry->type); 276 Tab* tab = static_cast<Tab*>(entry); 277 EXPECT_FALSE(tab->pinned); 278 ASSERT_EQ(3U, tab->navigations.size()); 279 EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url()); 280 EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url()); 281 EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url()); 282 EXPECT_EQ(2, tab->current_navigation_index); 283 EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(), 284 tab->timestamp.ToInternalValue()); 285} 286 287// Tests restoring a single pinned tab. 288TEST_F(PersistentTabRestoreServiceTest, RestorePinnedAndApp) { 289 AddThreeNavigations(); 290 291 // Have the service record the tab. 292 service_->CreateHistoricalTab(web_contents(), -1); 293 294 // One entry should be created. 295 ASSERT_EQ(1U, service_->entries().size()); 296 297 // We have to explicitly mark the tab as pinned as there is no browser for 298 // these tests. 299 TabRestoreService::Entry* entry = service_->entries().front(); 300 ASSERT_EQ(TabRestoreService::TAB, entry->type); 301 Tab* tab = static_cast<Tab*>(entry); 302 tab->pinned = true; 303 const std::string extension_app_id("test"); 304 tab->extension_app_id = extension_app_id; 305 306 // Recreate the service and have it load the tabs. 307 RecreateService(); 308 309 // One entry should be created. 310 ASSERT_EQ(1U, service_->entries().size()); 311 312 // And verify the entry. 313 entry = service_->entries().front(); 314 ASSERT_EQ(TabRestoreService::TAB, entry->type); 315 tab = static_cast<Tab*>(entry); 316 EXPECT_TRUE(tab->pinned); 317 ASSERT_EQ(3U, tab->navigations.size()); 318 EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url()); 319 EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url()); 320 EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url()); 321 EXPECT_EQ(2, tab->current_navigation_index); 322 EXPECT_TRUE(extension_app_id == tab->extension_app_id); 323} 324 325// We only restore apps on chromeos. 326#if defined(USE_AURA) 327 328typedef InProcessBrowserTest PersistentTabRestoreServiceBrowserTest; 329 330IN_PROC_BROWSER_TEST_F(PersistentTabRestoreServiceBrowserTest, RestoreApp) { 331 Profile* profile = browser()->profile(); 332 TabRestoreService* trs = TabRestoreServiceFactory::GetForProfile(profile); 333 const char* app_name = "TestApp"; 334 335 Browser* app_browser = CreateBrowserForApp(app_name, profile); 336 app_browser->window()->Close(); 337 content::WindowedNotificationObserver observer( 338 chrome::NOTIFICATION_BROWSER_CLOSED, 339 content::Source<Browser>(app_browser)); 340 observer.Wait(); 341 342 // One entry should be created. 343 ASSERT_EQ(1U, trs->entries().size()); 344 const TabRestoreService::Entry* restored_entry = trs->entries().front(); 345 346 // It should be a window with an app. 347 ASSERT_EQ(TabRestoreService::WINDOW, restored_entry->type); 348 const Window* restored_window = 349 static_cast<const Window*>(restored_entry); 350 EXPECT_EQ(app_name, restored_window->app_name); 351} 352#endif // defined(USE_AURA) 353 354// Make sure we persist entries to disk that have post data. 355TEST_F(PersistentTabRestoreServiceTest, DontPersistPostData) { 356 AddThreeNavigations(); 357 controller().GetEntryAtIndex(0)->SetHasPostData(true); 358 controller().GetEntryAtIndex(1)->SetHasPostData(true); 359 controller().GetEntryAtIndex(2)->SetHasPostData(true); 360 361 // Have the service record the tab. 362 service_->CreateHistoricalTab(web_contents(), -1); 363 ASSERT_EQ(1U, service_->entries().size()); 364 365 // Recreate the service and have it load the tabs. 366 RecreateService(); 367 368 // One entry should be created. 369 ASSERT_EQ(1U, service_->entries().size()); 370 371 const TabRestoreService::Entry* restored_entry = service_->entries().front(); 372 ASSERT_EQ(TabRestoreService::TAB, restored_entry->type); 373 374 const Tab* restored_tab = 375 static_cast<const Tab*>(restored_entry); 376 // There should be 3 navs. 377 ASSERT_EQ(3U, restored_tab->navigations.size()); 378 EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(), 379 restored_tab->timestamp.ToInternalValue()); 380} 381 382// Make sure we don't persist entries to disk that have post data. This 383// differs from DontPersistPostData1 in that all the navigations have post 384// data, so that nothing should be persisted. 385TEST_F(PersistentTabRestoreServiceTest, DontLoadTwice) { 386 AddThreeNavigations(); 387 388 // Have the service record the tab. 389 service_->CreateHistoricalTab(web_contents(), -1); 390 ASSERT_EQ(1U, service_->entries().size()); 391 392 // Recreate the service and have it load the tabs. 393 RecreateService(); 394 395 SynchronousLoadTabsFromLastSession(); 396 397 // There should only be one entry. 398 ASSERT_EQ(1U, service_->entries().size()); 399} 400 401// Makes sure we load the previous session as necessary. 402TEST_F(PersistentTabRestoreServiceTest, LoadPreviousSession) { 403 CreateSessionServiceWithOneWindow(false); 404 405 SessionServiceFactory::GetForProfile(profile())-> 406 MoveCurrentSessionToLastSession(); 407 408 EXPECT_FALSE(service_->IsLoaded()); 409 410 TestTabRestoreServiceObserver observer; 411 service_->AddObserver(&observer); 412 SynchronousLoadTabsFromLastSession(); 413 EXPECT_TRUE(observer.got_loaded()); 414 service_->RemoveObserver(&observer); 415 416 // Make sure we get back one entry with one tab whose url is url1. 417 ASSERT_EQ(1U, service_->entries().size()); 418 TabRestoreService::Entry* entry2 = service_->entries().front(); 419 ASSERT_EQ(TabRestoreService::WINDOW, entry2->type); 420 TabRestoreService::Window* window = 421 static_cast<TabRestoreService::Window*>(entry2); 422 ASSERT_EQ(1U, window->tabs.size()); 423 EXPECT_EQ(0, window->timestamp.ToInternalValue()); 424 EXPECT_EQ(0, window->selected_tab_index); 425 ASSERT_EQ(1U, window->tabs[0].navigations.size()); 426 EXPECT_EQ(0, window->tabs[0].current_navigation_index); 427 EXPECT_EQ(0, window->tabs[0].timestamp.ToInternalValue()); 428 EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url()); 429} 430 431// Makes sure we don't attempt to load previous sessions after a restore. 432TEST_F(PersistentTabRestoreServiceTest, DontLoadAfterRestore) { 433 CreateSessionServiceWithOneWindow(false); 434 435 SessionServiceFactory::GetForProfile(profile())-> 436 MoveCurrentSessionToLastSession(); 437 438 profile()->set_restored_last_session(true); 439 440 SynchronousLoadTabsFromLastSession(); 441 442 // Because we restored a session PersistentTabRestoreService shouldn't load 443 // the tabs. 444 ASSERT_EQ(0U, service_->entries().size()); 445} 446 447// Makes sure we don't attempt to load previous sessions after a clean exit. 448TEST_F(PersistentTabRestoreServiceTest, DontLoadAfterCleanExit) { 449 CreateSessionServiceWithOneWindow(false); 450 451 SessionServiceFactory::GetForProfile(profile())-> 452 MoveCurrentSessionToLastSession(); 453 454 profile()->set_last_session_exited_cleanly(true); 455 456 SynchronousLoadTabsFromLastSession(); 457 458 ASSERT_EQ(0U, service_->entries().size()); 459} 460 461TEST_F(PersistentTabRestoreServiceTest, LoadPreviousSessionAndTabs) { 462 CreateSessionServiceWithOneWindow(false); 463 464 SessionServiceFactory::GetForProfile(profile())-> 465 MoveCurrentSessionToLastSession(); 466 467 AddThreeNavigations(); 468 469 service_->CreateHistoricalTab(web_contents(), -1); 470 471 RecreateService(); 472 473 // We should get back two entries, one from the previous session and one from 474 // the tab restore service. The previous session entry should be first. 475 ASSERT_EQ(2U, service_->entries().size()); 476 // The first entry should come from the session service. 477 TabRestoreService::Entry* entry = service_->entries().front(); 478 ASSERT_EQ(TabRestoreService::WINDOW, entry->type); 479 TabRestoreService::Window* window = 480 static_cast<TabRestoreService::Window*>(entry); 481 ASSERT_EQ(1U, window->tabs.size()); 482 EXPECT_EQ(0, window->selected_tab_index); 483 EXPECT_EQ(0, window->timestamp.ToInternalValue()); 484 ASSERT_EQ(1U, window->tabs[0].navigations.size()); 485 EXPECT_EQ(0, window->tabs[0].current_navigation_index); 486 EXPECT_EQ(0, window->tabs[0].timestamp.ToInternalValue()); 487 EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url()); 488 489 // Then the closed tab. 490 entry = *(++service_->entries().begin()); 491 ASSERT_EQ(TabRestoreService::TAB, entry->type); 492 Tab* tab = static_cast<Tab*>(entry); 493 ASSERT_FALSE(tab->pinned); 494 ASSERT_EQ(3U, tab->navigations.size()); 495 EXPECT_EQ(2, tab->current_navigation_index); 496 EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(), 497 tab->timestamp.ToInternalValue()); 498 EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url()); 499 EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url()); 500 EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url()); 501} 502 503// Make sure pinned state is correctly loaded from session service. 504TEST_F(PersistentTabRestoreServiceTest, LoadPreviousSessionAndTabsPinned) { 505 CreateSessionServiceWithOneWindow(true); 506 507 SessionServiceFactory::GetForProfile(profile())-> 508 MoveCurrentSessionToLastSession(); 509 510 AddThreeNavigations(); 511 512 service_->CreateHistoricalTab(web_contents(), -1); 513 514 RecreateService(); 515 516 // We should get back two entries, one from the previous session and one from 517 // the tab restore service. The previous session entry should be first. 518 ASSERT_EQ(2U, service_->entries().size()); 519 // The first entry should come from the session service. 520 TabRestoreService::Entry* entry = service_->entries().front(); 521 ASSERT_EQ(TabRestoreService::WINDOW, entry->type); 522 TabRestoreService::Window* window = 523 static_cast<TabRestoreService::Window*>(entry); 524 ASSERT_EQ(1U, window->tabs.size()); 525 EXPECT_EQ(0, window->selected_tab_index); 526 EXPECT_TRUE(window->tabs[0].pinned); 527 ASSERT_EQ(1U, window->tabs[0].navigations.size()); 528 EXPECT_EQ(0, window->tabs[0].current_navigation_index); 529 EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url()); 530 531 // Then the closed tab. 532 entry = *(++service_->entries().begin()); 533 ASSERT_EQ(TabRestoreService::TAB, entry->type); 534 Tab* tab = static_cast<Tab*>(entry); 535 ASSERT_FALSE(tab->pinned); 536 ASSERT_EQ(3U, tab->navigations.size()); 537 EXPECT_EQ(2, tab->current_navigation_index); 538 EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url()); 539 EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url()); 540 EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url()); 541} 542 543// Creates kMaxEntries + 1 windows in the session service and makes sure we only 544// get back kMaxEntries on restore. 545TEST_F(PersistentTabRestoreServiceTest, ManyWindowsInSessionService) { 546 CreateSessionServiceWithOneWindow(false); 547 548 for (size_t i = 0; i < kMaxEntries; ++i) 549 AddWindowWithOneTabToSessionService(false); 550 551 SessionServiceFactory::GetForProfile(profile())-> 552 MoveCurrentSessionToLastSession(); 553 554 AddThreeNavigations(); 555 556 service_->CreateHistoricalTab(web_contents(), -1); 557 558 RecreateService(); 559 560 // We should get back kMaxEntries entries. We added more, but 561 // TabRestoreService only allows up to kMaxEntries. 562 ASSERT_EQ(kMaxEntries, service_->entries().size()); 563 564 // The first entry should come from the session service. 565 TabRestoreService::Entry* entry = service_->entries().front(); 566 ASSERT_EQ(TabRestoreService::WINDOW, entry->type); 567 TabRestoreService::Window* window = 568 static_cast<TabRestoreService::Window*>(entry); 569 ASSERT_EQ(1U, window->tabs.size()); 570 EXPECT_EQ(0, window->selected_tab_index); 571 EXPECT_EQ(0, window->timestamp.ToInternalValue()); 572 ASSERT_EQ(1U, window->tabs[0].navigations.size()); 573 EXPECT_EQ(0, window->tabs[0].current_navigation_index); 574 EXPECT_EQ(0, window->tabs[0].timestamp.ToInternalValue()); 575 EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url()); 576} 577 578// Makes sure we restore timestamps correctly. 579TEST_F(PersistentTabRestoreServiceTest, TimestampSurvivesRestore) { 580 base::Time tab_timestamp(base::Time::FromInternalValue(123456789)); 581 582 AddThreeNavigations(); 583 584 // Have the service record the tab. 585 service_->CreateHistoricalTab(web_contents(), -1); 586 587 // Make sure an entry was created. 588 ASSERT_EQ(1U, service_->entries().size()); 589 590 // Make sure the entry matches. 591 std::vector<SerializedNavigationEntry> old_navigations; 592 { 593 // |entry|/|tab| doesn't survive after RecreateService(). 594 TabRestoreService::Entry* entry = service_->entries().front(); 595 ASSERT_EQ(TabRestoreService::TAB, entry->type); 596 Tab* tab = static_cast<Tab*>(entry); 597 tab->timestamp = tab_timestamp; 598 old_navigations = tab->navigations; 599 } 600 601 EXPECT_EQ(3U, old_navigations.size()); 602 for (size_t i = 0; i < old_navigations.size(); ++i) { 603 EXPECT_FALSE(old_navigations[i].timestamp().is_null()); 604 } 605 606 // Set this, otherwise previous session won't be loaded. 607 profile()->set_last_session_exited_cleanly(false); 608 609 RecreateService(); 610 611 // One entry should be created. 612 ASSERT_EQ(1U, service_->entries().size()); 613 614 // And verify the entry. 615 TabRestoreService::Entry* restored_entry = service_->entries().front(); 616 ASSERT_EQ(TabRestoreService::TAB, restored_entry->type); 617 Tab* restored_tab = 618 static_cast<Tab*>(restored_entry); 619 EXPECT_EQ(tab_timestamp.ToInternalValue(), 620 restored_tab->timestamp.ToInternalValue()); 621 ASSERT_EQ(old_navigations.size(), restored_tab->navigations.size()); 622 for (size_t i = 0; i < restored_tab->navigations.size(); ++i) { 623 EXPECT_EQ(old_navigations[i].timestamp(), 624 restored_tab->navigations[i].timestamp()); 625 } 626} 627 628TEST_F(PersistentTabRestoreServiceTest, PruneEntries) { 629 service_->ClearEntries(); 630 ASSERT_TRUE(service_->entries().empty()); 631 632 const size_t max_entries = kMaxEntries; 633 for (size_t i = 0; i < max_entries + 5; i++) { 634 SerializedNavigationEntry navigation = 635 SerializedNavigationEntryTestHelper::CreateNavigation( 636 base::StringPrintf("http://%d", static_cast<int>(i)), 637 base::StringPrintf("%d", static_cast<int>(i))); 638 639 Tab* tab = new Tab(); 640 tab->navigations.push_back(navigation); 641 tab->current_navigation_index = 0; 642 643 mutable_entries()->push_back(tab); 644 } 645 646 // Only keep kMaxEntries around. 647 EXPECT_EQ(max_entries + 5, service_->entries().size()); 648 PruneEntries(); 649 EXPECT_EQ(max_entries, service_->entries().size()); 650 // Pruning again does nothing. 651 PruneEntries(); 652 EXPECT_EQ(max_entries, service_->entries().size()); 653 654 // Prune older first. 655 const char kRecentUrl[] = "http://recent"; 656 SerializedNavigationEntry navigation = 657 SerializedNavigationEntryTestHelper::CreateNavigation(kRecentUrl, 658 "Most recent"); 659 Tab* tab = new Tab(); 660 tab->navigations.push_back(navigation); 661 tab->current_navigation_index = 0; 662 mutable_entries()->push_front(tab); 663 EXPECT_EQ(max_entries + 1, service_->entries().size()); 664 PruneEntries(); 665 EXPECT_EQ(max_entries, service_->entries().size()); 666 EXPECT_EQ(GURL(kRecentUrl), 667 static_cast<Tab*>(service_->entries().front())-> 668 navigations[0].virtual_url()); 669 670 // Ignore NTPs. 671 navigation = SerializedNavigationEntryTestHelper::CreateNavigation( 672 chrome::kChromeUINewTabURL, "New tab"); 673 674 tab = new Tab(); 675 tab->navigations.push_back(navigation); 676 tab->current_navigation_index = 0; 677 mutable_entries()->push_front(tab); 678 679 EXPECT_EQ(max_entries + 1, service_->entries().size()); 680 PruneEntries(); 681 EXPECT_EQ(max_entries, service_->entries().size()); 682 EXPECT_EQ(GURL(kRecentUrl), 683 static_cast<Tab*>(service_->entries().front())-> 684 navigations[0].virtual_url()); 685 686 // Don't prune pinned NTPs. 687 tab = new Tab(); 688 tab->pinned = true; 689 tab->current_navigation_index = 0; 690 tab->navigations.push_back(navigation); 691 mutable_entries()->push_front(tab); 692 EXPECT_EQ(max_entries + 1, service_->entries().size()); 693 PruneEntries(); 694 EXPECT_EQ(max_entries, service_->entries().size()); 695 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL), 696 static_cast<Tab*>(service_->entries().front())-> 697 navigations[0].virtual_url()); 698 699 // Don't prune NTPs that have multiple navigations. 700 // (Erase the last NTP first.) 701 delete service_->entries().front(); 702 mutable_entries()->erase(mutable_entries()->begin()); 703 tab = new Tab(); 704 tab->current_navigation_index = 1; 705 tab->navigations.push_back(navigation); 706 tab->navigations.push_back(navigation); 707 mutable_entries()->push_front(tab); 708 EXPECT_EQ(max_entries, service_->entries().size()); 709 PruneEntries(); 710 EXPECT_EQ(max_entries, service_->entries().size()); 711 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL), 712 static_cast<Tab*>(service_->entries().front())-> 713 navigations[1].virtual_url()); 714} 715 716// Regression test for crbug.com/106082 717TEST_F(PersistentTabRestoreServiceTest, PruneIsCalled) { 718 CreateSessionServiceWithOneWindow(false); 719 720 SessionServiceFactory::GetForProfile(profile())-> 721 MoveCurrentSessionToLastSession(); 722 723 profile()->set_restored_last_session(true); 724 725 const size_t max_entries = kMaxEntries; 726 for (size_t i = 0; i < max_entries + 5; i++) { 727 NavigateAndCommit( 728 GURL(base::StringPrintf("http://%d", static_cast<int>(i)))); 729 service_->CreateHistoricalTab(web_contents(), -1); 730 } 731 732 EXPECT_EQ(max_entries, service_->entries().size()); 733 // This should not crash. 734 SynchronousLoadTabsFromLastSession(); 735 EXPECT_EQ(max_entries, service_->entries().size()); 736} 737 738// Makes sure invoking LoadTabsFromLastSession() when the max number of entries 739// have been added results in IsLoaded() returning true and notifies observers. 740TEST_F(PersistentTabRestoreServiceTest, GoToLoadedWhenHaveMaxEntries) { 741 const size_t max_entries = kMaxEntries; 742 for (size_t i = 0; i < max_entries + 5; i++) { 743 NavigateAndCommit( 744 GURL(base::StringPrintf("http://%d", static_cast<int>(i)))); 745 service_->CreateHistoricalTab(web_contents(), -1); 746 } 747 748 EXPECT_FALSE(service_->IsLoaded()); 749 TestTabRestoreServiceObserver observer; 750 service_->AddObserver(&observer); 751 EXPECT_EQ(max_entries, service_->entries().size()); 752 SynchronousLoadTabsFromLastSession(); 753 EXPECT_TRUE(observer.got_loaded()); 754 EXPECT_TRUE(service_->IsLoaded()); 755 service_->RemoveObserver(&observer); 756} 757