[sessions]: Componentize TabRestore code
[chromium-blink-merge.git] / chrome / browser / sessions / persistent_tab_restore_service_unittest.cc
blobf706477f45a48fa3d22adc59f68b1f9e6ec94a31
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/sessions/core/persistent_tab_restore_service.h"
7 #include <string>
9 #include "base/compiler_specific.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/threading/sequenced_worker_pool.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/sessions/chrome_tab_restore_service_client.h"
16 #include "chrome/browser/sessions/session_service.h"
17 #include "chrome/browser/sessions/session_service_factory.h"
18 #include "chrome/browser/sessions/session_service_utils.h"
19 #include "chrome/browser/sessions/tab_restore_service_factory.h"
20 #include "chrome/common/url_constants.h"
21 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
22 #include "chrome/test/base/chrome_render_view_test.h"
23 #include "chrome/test/base/testing_profile.h"
24 #include "components/sessions/content/content_live_tab.h"
25 #include "components/sessions/core/tab_restore_service_observer.h"
26 #include "components/sessions/serialized_navigation_entry_test_helper.h"
27 #include "components/sessions/session_types.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/navigation_controller.h"
30 #include "content/public/browser/navigation_entry.h"
31 #include "content/public/browser/notification_service.h"
32 #include "content/public/browser/notification_types.h"
33 #include "content/public/browser/web_contents.h"
34 #include "content/public/test/render_view_test.h"
35 #include "content/public/test/test_utils.h"
36 #include "content/public/test/web_contents_tester.h"
37 #include "testing/gtest/include/gtest/gtest.h"
39 typedef TabRestoreService::Tab Tab;
40 typedef TabRestoreService::Window Window;
42 using content::NavigationEntry;
43 using content::WebContentsTester;
44 using sessions::SerializedNavigationEntry;
45 using sessions::SerializedNavigationEntryTestHelper;
47 // Create subclass that overrides TimeNow so that we can control the time used
48 // for closed tabs and windows.
49 class PersistentTabRestoreTimeFactory : public TabRestoreService::TimeFactory {
50 public:
51 PersistentTabRestoreTimeFactory() : time_(base::Time::Now()) {}
53 ~PersistentTabRestoreTimeFactory() override {}
55 base::Time TimeNow() override { return time_; }
57 private:
58 base::Time time_;
61 class 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 time_factory_(NULL) {
73 ~PersistentTabRestoreServiceTest() override {}
75 protected:
76 enum {
77 kMaxEntries = TabRestoreServiceHelper::kMaxEntries,
80 // testing::Test:
81 void SetUp() override {
82 ChromeRenderViewHostTestHarness::SetUp();
83 live_tab_ = make_scoped_ptr(new sessions::ContentLiveTab(web_contents()));
84 time_factory_ = new PersistentTabRestoreTimeFactory();
85 service_.reset(new PersistentTabRestoreService(
86 make_scoped_ptr(new ChromeTabRestoreServiceClient(profile())),
87 time_factory_));
90 void TearDown() override {
91 service_->Shutdown();
92 service_.reset();
93 delete time_factory_;
94 ChromeRenderViewHostTestHarness::TearDown();
97 TabRestoreService::Entries* mutable_entries() {
98 return service_->mutable_entries();
101 void PruneEntries() {
102 service_->PruneEntries();
105 void AddThreeNavigations() {
106 // Navigate to three URLs.
107 NavigateAndCommit(url1_);
108 NavigateAndCommit(url2_);
109 NavigateAndCommit(url3_);
112 void NavigateToIndex(int index) {
113 // Navigate back. We have to do this song and dance as NavigationController
114 // isn't happy if you navigate immediately while going back.
115 controller().GoToIndex(index);
116 WebContentsTester::For(web_contents())->CommitPendingNavigation();
119 void RecreateService() {
120 // Must set service to null first so that it is destroyed before the new
121 // one is created.
122 service_->Shutdown();
123 content::RunAllBlockingPoolTasksUntilIdle();
124 service_.reset();
125 service_.reset(new PersistentTabRestoreService(
126 make_scoped_ptr(new ChromeTabRestoreServiceClient(profile())),
127 time_factory_));
128 SynchronousLoadTabsFromLastSession();
131 // Adds a window with one tab and url to the profile's session service.
132 // If |pinned| is true, the tab is marked as pinned in the session service.
133 void AddWindowWithOneTabToSessionService(bool pinned) {
134 SessionService* session_service =
135 SessionServiceFactory::GetForProfile(profile());
136 SessionID tab_id;
137 SessionID window_id;
138 session_service->SetWindowType(window_id,
139 Browser::TYPE_TABBED,
140 SessionService::TYPE_NORMAL);
141 session_service->SetTabWindow(window_id, tab_id);
142 session_service->SetTabIndexInWindow(window_id, tab_id, 0);
143 session_service->SetSelectedTabInWindow(window_id, 0);
144 if (pinned)
145 session_service->SetPinnedState(window_id, tab_id, true);
146 session_service->UpdateTabNavigation(
147 window_id, tab_id,
148 SerializedNavigationEntryTestHelper::CreateNavigation(
149 url1_.spec(), "title"));
152 // Creates a SessionService and assigns it to the Profile. The SessionService
153 // is configured with a single window with a single tab pointing at url1_ by
154 // way of AddWindowWithOneTabToSessionService. If |pinned| is true, the
155 // tab is marked as pinned in the session service.
156 void CreateSessionServiceWithOneWindow(bool pinned) {
157 scoped_ptr<SessionService> session_service(new SessionService(profile()));
158 SessionServiceFactory::SetForTestProfile(profile(), session_service.Pass());
160 AddWindowWithOneTabToSessionService(pinned);
162 // Set this, otherwise previous session won't be loaded.
163 profile()->set_last_session_exited_cleanly(false);
166 void SynchronousLoadTabsFromLastSession() {
167 // Ensures that the load is complete before continuing.
168 service_->LoadTabsFromLastSession();
169 content::RunAllBlockingPoolTasksUntilIdle();
172 sessions::LiveTab* live_tab() { return live_tab_.get(); }
174 GURL url1_;
175 GURL url2_;
176 GURL url3_;
177 std::string user_agent_override_;
178 scoped_ptr<sessions::LiveTab> live_tab_;
179 scoped_ptr<PersistentTabRestoreService> service_;
180 PersistentTabRestoreTimeFactory* time_factory_;
183 namespace {
185 class TestTabRestoreServiceObserver : public TabRestoreServiceObserver {
186 public:
187 TestTabRestoreServiceObserver() : got_loaded_(false) {}
189 void clear_got_loaded() { got_loaded_ = false; }
190 bool got_loaded() const { return got_loaded_; }
192 // TabRestoreServiceObserver:
193 void TabRestoreServiceChanged(TabRestoreService* service) override {}
194 void TabRestoreServiceDestroyed(TabRestoreService* service) override {}
195 void TabRestoreServiceLoaded(TabRestoreService* service) override {
196 got_loaded_ = true;
199 private:
200 // Was TabRestoreServiceLoaded() invoked?
201 bool got_loaded_;
203 DISALLOW_COPY_AND_ASSIGN(TestTabRestoreServiceObserver);
206 } // namespace
208 TEST_F(PersistentTabRestoreServiceTest, Basic) {
209 AddThreeNavigations();
211 // Have the service record the tab.
212 service_->CreateHistoricalTab(live_tab(), -1);
214 // Make sure an entry was created.
215 ASSERT_EQ(1U, service_->entries().size());
217 // Make sure the entry matches.
218 TabRestoreService::Entry* entry = service_->entries().front();
219 ASSERT_EQ(TabRestoreService::TAB, entry->type);
220 Tab* tab = static_cast<Tab*>(entry);
221 EXPECT_FALSE(tab->pinned);
222 EXPECT_TRUE(tab->extension_app_id.empty());
223 ASSERT_EQ(3U, tab->navigations.size());
224 EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url());
225 EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url());
226 EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url());
227 EXPECT_EQ("", tab->user_agent_override);
228 EXPECT_EQ(2, tab->current_navigation_index);
229 EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(),
230 tab->timestamp.ToInternalValue());
232 NavigateToIndex(1);
234 // And check again, but set the user agent override this time.
235 web_contents()->SetUserAgentOverride(user_agent_override_);
236 service_->CreateHistoricalTab(live_tab(), -1);
238 // There should be two entries now.
239 ASSERT_EQ(2U, service_->entries().size());
241 // Make sure the entry matches.
242 entry = service_->entries().front();
243 ASSERT_EQ(TabRestoreService::TAB, entry->type);
244 tab = static_cast<Tab*>(entry);
245 EXPECT_FALSE(tab->pinned);
246 ASSERT_EQ(3U, tab->navigations.size());
247 EXPECT_EQ(url1_, tab->navigations[0].virtual_url());
248 EXPECT_EQ(url2_, tab->navigations[1].virtual_url());
249 EXPECT_EQ(url3_, tab->navigations[2].virtual_url());
250 EXPECT_EQ(user_agent_override_, tab->user_agent_override);
251 EXPECT_EQ(1, tab->current_navigation_index);
252 EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(),
253 tab->timestamp.ToInternalValue());
256 // Make sure TabRestoreService doesn't create an entry for a tab with no
257 // navigations.
258 TEST_F(PersistentTabRestoreServiceTest, DontCreateEmptyTab) {
259 service_->CreateHistoricalTab(live_tab(), -1);
260 EXPECT_TRUE(service_->entries().empty());
263 // Tests restoring a single tab.
264 TEST_F(PersistentTabRestoreServiceTest, Restore) {
265 AddThreeNavigations();
267 // Have the service record the tab.
268 service_->CreateHistoricalTab(live_tab(), -1);
270 // Recreate the service and have it load the tabs.
271 RecreateService();
273 // One entry should be created.
274 ASSERT_EQ(1U, service_->entries().size());
276 // And verify the entry.
277 PersistentTabRestoreService::Entry* entry = service_->entries().front();
278 ASSERT_EQ(TabRestoreService::TAB, entry->type);
279 Tab* tab = static_cast<Tab*>(entry);
280 EXPECT_FALSE(tab->pinned);
281 ASSERT_EQ(3U, tab->navigations.size());
282 EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url());
283 EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url());
284 EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url());
285 EXPECT_EQ(2, tab->current_navigation_index);
286 EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(),
287 tab->timestamp.ToInternalValue());
290 // Tests restoring a single pinned tab.
291 TEST_F(PersistentTabRestoreServiceTest, RestorePinnedAndApp) {
292 AddThreeNavigations();
294 // Have the service record the tab.
295 service_->CreateHistoricalTab(live_tab(), -1);
297 // One entry should be created.
298 ASSERT_EQ(1U, service_->entries().size());
300 // We have to explicitly mark the tab as pinned as there is no browser for
301 // these tests.
302 TabRestoreService::Entry* entry = service_->entries().front();
303 ASSERT_EQ(TabRestoreService::TAB, entry->type);
304 Tab* tab = static_cast<Tab*>(entry);
305 tab->pinned = true;
306 const std::string extension_app_id("test");
307 tab->extension_app_id = extension_app_id;
309 // Recreate the service and have it load the tabs.
310 RecreateService();
312 // One entry should be created.
313 ASSERT_EQ(1U, service_->entries().size());
315 // And verify the entry.
316 entry = service_->entries().front();
317 ASSERT_EQ(TabRestoreService::TAB, entry->type);
318 tab = static_cast<Tab*>(entry);
319 EXPECT_TRUE(tab->pinned);
320 ASSERT_EQ(3U, tab->navigations.size());
321 EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url());
322 EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url());
323 EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url());
324 EXPECT_EQ(2, tab->current_navigation_index);
325 EXPECT_TRUE(extension_app_id == tab->extension_app_id);
328 // Make sure we persist entries to disk that have post data.
329 TEST_F(PersistentTabRestoreServiceTest, DontPersistPostData) {
330 AddThreeNavigations();
331 controller().GetEntryAtIndex(0)->SetHasPostData(true);
332 controller().GetEntryAtIndex(1)->SetHasPostData(true);
333 controller().GetEntryAtIndex(2)->SetHasPostData(true);
335 // Have the service record the tab.
336 service_->CreateHistoricalTab(live_tab(), -1);
337 ASSERT_EQ(1U, service_->entries().size());
339 // Recreate the service and have it load the tabs.
340 RecreateService();
342 // One entry should be created.
343 ASSERT_EQ(1U, service_->entries().size());
345 const TabRestoreService::Entry* restored_entry = service_->entries().front();
346 ASSERT_EQ(TabRestoreService::TAB, restored_entry->type);
348 const Tab* restored_tab =
349 static_cast<const Tab*>(restored_entry);
350 // There should be 3 navs.
351 ASSERT_EQ(3U, restored_tab->navigations.size());
352 EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(),
353 restored_tab->timestamp.ToInternalValue());
356 // Make sure we don't persist entries to disk that have post data. This
357 // differs from DontPersistPostData1 in that all the navigations have post
358 // data, so that nothing should be persisted.
359 TEST_F(PersistentTabRestoreServiceTest, DontLoadTwice) {
360 AddThreeNavigations();
362 // Have the service record the tab.
363 service_->CreateHistoricalTab(live_tab(), -1);
364 ASSERT_EQ(1U, service_->entries().size());
366 // Recreate the service and have it load the tabs.
367 RecreateService();
369 SynchronousLoadTabsFromLastSession();
371 // There should only be one entry.
372 ASSERT_EQ(1U, service_->entries().size());
375 // Makes sure we load the previous session as necessary.
376 TEST_F(PersistentTabRestoreServiceTest, LoadPreviousSession) {
377 CreateSessionServiceWithOneWindow(false);
379 SessionServiceFactory::GetForProfile(profile())->
380 MoveCurrentSessionToLastSession();
382 EXPECT_FALSE(service_->IsLoaded());
384 TestTabRestoreServiceObserver observer;
385 service_->AddObserver(&observer);
386 SynchronousLoadTabsFromLastSession();
387 EXPECT_TRUE(observer.got_loaded());
388 service_->RemoveObserver(&observer);
390 // Make sure we get back one entry with one tab whose url is url1.
391 ASSERT_EQ(1U, service_->entries().size());
392 TabRestoreService::Entry* entry2 = service_->entries().front();
393 ASSERT_EQ(TabRestoreService::WINDOW, entry2->type);
394 TabRestoreService::Window* window =
395 static_cast<TabRestoreService::Window*>(entry2);
396 ASSERT_EQ(1U, window->tabs.size());
397 EXPECT_EQ(0, window->timestamp.ToInternalValue());
398 EXPECT_EQ(0, window->selected_tab_index);
399 ASSERT_EQ(1U, window->tabs[0].navigations.size());
400 EXPECT_EQ(0, window->tabs[0].current_navigation_index);
401 EXPECT_EQ(0, window->tabs[0].timestamp.ToInternalValue());
402 EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url());
405 // Makes sure we don't attempt to load previous sessions after a restore.
406 TEST_F(PersistentTabRestoreServiceTest, DontLoadAfterRestore) {
407 CreateSessionServiceWithOneWindow(false);
409 SessionServiceFactory::GetForProfile(profile())->
410 MoveCurrentSessionToLastSession();
412 profile()->set_restored_last_session(true);
414 SynchronousLoadTabsFromLastSession();
416 // Because we restored a session PersistentTabRestoreService shouldn't load
417 // the tabs.
418 ASSERT_EQ(0U, service_->entries().size());
421 // Makes sure we don't attempt to load previous sessions after a clean exit.
422 TEST_F(PersistentTabRestoreServiceTest, DontLoadAfterCleanExit) {
423 CreateSessionServiceWithOneWindow(false);
425 SessionServiceFactory::GetForProfile(profile())->
426 MoveCurrentSessionToLastSession();
428 profile()->set_last_session_exited_cleanly(true);
430 SynchronousLoadTabsFromLastSession();
432 ASSERT_EQ(0U, service_->entries().size());
435 TEST_F(PersistentTabRestoreServiceTest, LoadPreviousSessionAndTabs) {
436 CreateSessionServiceWithOneWindow(false);
438 SessionServiceFactory::GetForProfile(profile())->
439 MoveCurrentSessionToLastSession();
441 AddThreeNavigations();
443 service_->CreateHistoricalTab(live_tab(), -1);
445 RecreateService();
447 // We should get back two entries, one from the previous session and one from
448 // the tab restore service. The previous session entry should be first.
449 ASSERT_EQ(2U, service_->entries().size());
450 // The first entry should come from the session service.
451 TabRestoreService::Entry* entry = service_->entries().front();
452 ASSERT_EQ(TabRestoreService::WINDOW, entry->type);
453 TabRestoreService::Window* window =
454 static_cast<TabRestoreService::Window*>(entry);
455 ASSERT_EQ(1U, window->tabs.size());
456 EXPECT_EQ(0, window->selected_tab_index);
457 EXPECT_EQ(0, window->timestamp.ToInternalValue());
458 ASSERT_EQ(1U, window->tabs[0].navigations.size());
459 EXPECT_EQ(0, window->tabs[0].current_navigation_index);
460 EXPECT_EQ(0, window->tabs[0].timestamp.ToInternalValue());
461 EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url());
463 // Then the closed tab.
464 entry = *(++service_->entries().begin());
465 ASSERT_EQ(TabRestoreService::TAB, entry->type);
466 Tab* tab = static_cast<Tab*>(entry);
467 ASSERT_FALSE(tab->pinned);
468 ASSERT_EQ(3U, tab->navigations.size());
469 EXPECT_EQ(2, tab->current_navigation_index);
470 EXPECT_EQ(time_factory_->TimeNow().ToInternalValue(),
471 tab->timestamp.ToInternalValue());
472 EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url());
473 EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url());
474 EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url());
477 // Make sure pinned state is correctly loaded from session service.
478 TEST_F(PersistentTabRestoreServiceTest, LoadPreviousSessionAndTabsPinned) {
479 CreateSessionServiceWithOneWindow(true);
481 SessionServiceFactory::GetForProfile(profile())->
482 MoveCurrentSessionToLastSession();
484 AddThreeNavigations();
486 service_->CreateHistoricalTab(live_tab(), -1);
488 RecreateService();
490 // We should get back two entries, one from the previous session and one from
491 // the tab restore service. The previous session entry should be first.
492 ASSERT_EQ(2U, service_->entries().size());
493 // The first entry should come from the session service.
494 TabRestoreService::Entry* entry = service_->entries().front();
495 ASSERT_EQ(TabRestoreService::WINDOW, entry->type);
496 TabRestoreService::Window* window =
497 static_cast<TabRestoreService::Window*>(entry);
498 ASSERT_EQ(1U, window->tabs.size());
499 EXPECT_EQ(0, window->selected_tab_index);
500 EXPECT_TRUE(window->tabs[0].pinned);
501 ASSERT_EQ(1U, window->tabs[0].navigations.size());
502 EXPECT_EQ(0, window->tabs[0].current_navigation_index);
503 EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url());
505 // Then the closed tab.
506 entry = *(++service_->entries().begin());
507 ASSERT_EQ(TabRestoreService::TAB, entry->type);
508 Tab* tab = static_cast<Tab*>(entry);
509 ASSERT_FALSE(tab->pinned);
510 ASSERT_EQ(3U, tab->navigations.size());
511 EXPECT_EQ(2, tab->current_navigation_index);
512 EXPECT_TRUE(url1_ == tab->navigations[0].virtual_url());
513 EXPECT_TRUE(url2_ == tab->navigations[1].virtual_url());
514 EXPECT_TRUE(url3_ == tab->navigations[2].virtual_url());
517 // Creates kMaxEntries + 1 windows in the session service and makes sure we only
518 // get back kMaxEntries on restore.
519 TEST_F(PersistentTabRestoreServiceTest, ManyWindowsInSessionService) {
520 CreateSessionServiceWithOneWindow(false);
522 for (size_t i = 0; i < kMaxEntries; ++i)
523 AddWindowWithOneTabToSessionService(false);
525 SessionServiceFactory::GetForProfile(profile())->
526 MoveCurrentSessionToLastSession();
528 AddThreeNavigations();
530 service_->CreateHistoricalTab(live_tab(), -1);
532 RecreateService();
534 // We should get back kMaxEntries entries. We added more, but
535 // TabRestoreService only allows up to kMaxEntries.
536 ASSERT_EQ(kMaxEntries, service_->entries().size());
538 // The first entry should come from the session service.
539 TabRestoreService::Entry* entry = service_->entries().front();
540 ASSERT_EQ(TabRestoreService::WINDOW, entry->type);
541 TabRestoreService::Window* window =
542 static_cast<TabRestoreService::Window*>(entry);
543 ASSERT_EQ(1U, window->tabs.size());
544 EXPECT_EQ(0, window->selected_tab_index);
545 EXPECT_EQ(0, window->timestamp.ToInternalValue());
546 ASSERT_EQ(1U, window->tabs[0].navigations.size());
547 EXPECT_EQ(0, window->tabs[0].current_navigation_index);
548 EXPECT_EQ(0, window->tabs[0].timestamp.ToInternalValue());
549 EXPECT_TRUE(url1_ == window->tabs[0].navigations[0].virtual_url());
552 // Makes sure we restore timestamps correctly.
553 TEST_F(PersistentTabRestoreServiceTest, TimestampSurvivesRestore) {
554 base::Time tab_timestamp(base::Time::FromInternalValue(123456789));
556 AddThreeNavigations();
558 // Have the service record the tab.
559 service_->CreateHistoricalTab(live_tab(), -1);
561 // Make sure an entry was created.
562 ASSERT_EQ(1U, service_->entries().size());
564 // Make sure the entry matches.
565 std::vector<SerializedNavigationEntry> old_navigations;
567 // |entry|/|tab| doesn't survive after RecreateService().
568 TabRestoreService::Entry* entry = service_->entries().front();
569 ASSERT_EQ(TabRestoreService::TAB, entry->type);
570 Tab* tab = static_cast<Tab*>(entry);
571 tab->timestamp = tab_timestamp;
572 old_navigations = tab->navigations;
575 EXPECT_EQ(3U, old_navigations.size());
576 for (size_t i = 0; i < old_navigations.size(); ++i) {
577 EXPECT_FALSE(old_navigations[i].timestamp().is_null());
580 // Set this, otherwise previous session won't be loaded.
581 profile()->set_last_session_exited_cleanly(false);
583 RecreateService();
585 // One entry should be created.
586 ASSERT_EQ(1U, service_->entries().size());
588 // And verify the entry.
589 TabRestoreService::Entry* restored_entry = service_->entries().front();
590 ASSERT_EQ(TabRestoreService::TAB, restored_entry->type);
591 Tab* restored_tab =
592 static_cast<Tab*>(restored_entry);
593 EXPECT_EQ(tab_timestamp.ToInternalValue(),
594 restored_tab->timestamp.ToInternalValue());
595 ASSERT_EQ(old_navigations.size(), restored_tab->navigations.size());
596 for (size_t i = 0; i < restored_tab->navigations.size(); ++i) {
597 EXPECT_EQ(old_navigations[i].timestamp(),
598 restored_tab->navigations[i].timestamp());
602 // Makes sure we restore status codes correctly.
603 TEST_F(PersistentTabRestoreServiceTest, StatusCodesSurviveRestore) {
604 AddThreeNavigations();
606 // Have the service record the tab.
607 service_->CreateHistoricalTab(live_tab(), -1);
609 // Make sure an entry was created.
610 ASSERT_EQ(1U, service_->entries().size());
612 // Make sure the entry matches.
613 std::vector<sessions::SerializedNavigationEntry> old_navigations;
615 // |entry|/|tab| doesn't survive after RecreateService().
616 TabRestoreService::Entry* entry = service_->entries().front();
617 ASSERT_EQ(TabRestoreService::TAB, entry->type);
618 Tab* tab = static_cast<Tab*>(entry);
619 old_navigations = tab->navigations;
622 EXPECT_EQ(3U, old_navigations.size());
623 for (size_t i = 0; i < old_navigations.size(); ++i) {
624 EXPECT_EQ(200, old_navigations[i].http_status_code());
627 // Set this, otherwise previous session won't be loaded.
628 profile()->set_last_session_exited_cleanly(false);
630 RecreateService();
632 // One entry should be created.
633 ASSERT_EQ(1U, service_->entries().size());
635 // And verify the entry.
636 TabRestoreService::Entry* restored_entry = service_->entries().front();
637 ASSERT_EQ(TabRestoreService::TAB, restored_entry->type);
638 Tab* restored_tab =
639 static_cast<Tab*>(restored_entry);
640 ASSERT_EQ(old_navigations.size(), restored_tab->navigations.size());
641 for (size_t i = 0; i < restored_tab->navigations.size(); ++i) {
642 EXPECT_EQ(200, restored_tab->navigations[i].http_status_code());
646 TEST_F(PersistentTabRestoreServiceTest, PruneEntries) {
647 service_->ClearEntries();
648 ASSERT_TRUE(service_->entries().empty());
650 const size_t max_entries = kMaxEntries;
651 for (size_t i = 0; i < max_entries + 5; i++) {
652 SerializedNavigationEntry navigation =
653 SerializedNavigationEntryTestHelper::CreateNavigation(
654 base::StringPrintf("http://%d", static_cast<int>(i)),
655 base::SizeTToString(i));
657 Tab* tab = new Tab();
658 tab->navigations.push_back(navigation);
659 tab->current_navigation_index = 0;
661 mutable_entries()->push_back(tab);
664 // Only keep kMaxEntries around.
665 EXPECT_EQ(max_entries + 5, service_->entries().size());
666 PruneEntries();
667 EXPECT_EQ(max_entries, service_->entries().size());
668 // Pruning again does nothing.
669 PruneEntries();
670 EXPECT_EQ(max_entries, service_->entries().size());
672 // Prune older first.
673 const char kRecentUrl[] = "http://recent";
674 SerializedNavigationEntry navigation =
675 SerializedNavigationEntryTestHelper::CreateNavigation(kRecentUrl,
676 "Most recent");
677 Tab* tab = new Tab();
678 tab->navigations.push_back(navigation);
679 tab->current_navigation_index = 0;
680 mutable_entries()->push_front(tab);
681 EXPECT_EQ(max_entries + 1, service_->entries().size());
682 PruneEntries();
683 EXPECT_EQ(max_entries, service_->entries().size());
684 EXPECT_EQ(GURL(kRecentUrl),
685 static_cast<Tab*>(service_->entries().front())->
686 navigations[0].virtual_url());
688 // Ignore NTPs.
689 navigation = SerializedNavigationEntryTestHelper::CreateNavigation(
690 chrome::kChromeUINewTabURL, "New tab");
692 tab = new Tab();
693 tab->navigations.push_back(navigation);
694 tab->current_navigation_index = 0;
695 mutable_entries()->push_front(tab);
697 EXPECT_EQ(max_entries + 1, service_->entries().size());
698 PruneEntries();
699 EXPECT_EQ(max_entries, service_->entries().size());
700 EXPECT_EQ(GURL(kRecentUrl),
701 static_cast<Tab*>(service_->entries().front())->
702 navigations[0].virtual_url());
704 // Don't prune pinned NTPs.
705 tab = new Tab();
706 tab->pinned = true;
707 tab->current_navigation_index = 0;
708 tab->navigations.push_back(navigation);
709 mutable_entries()->push_front(tab);
710 EXPECT_EQ(max_entries + 1, service_->entries().size());
711 PruneEntries();
712 EXPECT_EQ(max_entries, service_->entries().size());
713 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL),
714 static_cast<Tab*>(service_->entries().front())->
715 navigations[0].virtual_url());
717 // Don't prune NTPs that have multiple navigations.
718 // (Erase the last NTP first.)
719 delete service_->entries().front();
720 mutable_entries()->erase(mutable_entries()->begin());
721 tab = new Tab();
722 tab->current_navigation_index = 1;
723 tab->navigations.push_back(navigation);
724 tab->navigations.push_back(navigation);
725 mutable_entries()->push_front(tab);
726 EXPECT_EQ(max_entries, service_->entries().size());
727 PruneEntries();
728 EXPECT_EQ(max_entries, service_->entries().size());
729 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL),
730 static_cast<Tab*>(service_->entries().front())->
731 navigations[1].virtual_url());
734 // Regression test for crbug.com/106082
735 TEST_F(PersistentTabRestoreServiceTest, PruneIsCalled) {
736 CreateSessionServiceWithOneWindow(false);
738 SessionServiceFactory::GetForProfile(profile())->
739 MoveCurrentSessionToLastSession();
741 profile()->set_restored_last_session(true);
743 const size_t max_entries = kMaxEntries;
744 for (size_t i = 0; i < max_entries + 5; i++) {
745 NavigateAndCommit(
746 GURL(base::StringPrintf("http://%d", static_cast<int>(i))));
747 service_->CreateHistoricalTab(live_tab(), -1);
750 EXPECT_EQ(max_entries, service_->entries().size());
751 // This should not crash.
752 SynchronousLoadTabsFromLastSession();
753 EXPECT_EQ(max_entries, service_->entries().size());
756 // Makes sure invoking LoadTabsFromLastSession() when the max number of entries
757 // have been added results in IsLoaded() returning true and notifies observers.
758 TEST_F(PersistentTabRestoreServiceTest, GoToLoadedWhenHaveMaxEntries) {
759 const size_t max_entries = kMaxEntries;
760 for (size_t i = 0; i < max_entries + 5; i++) {
761 NavigateAndCommit(
762 GURL(base::StringPrintf("http://%d", static_cast<int>(i))));
763 service_->CreateHistoricalTab(live_tab(), -1);
766 EXPECT_FALSE(service_->IsLoaded());
767 TestTabRestoreServiceObserver observer;
768 service_->AddObserver(&observer);
769 EXPECT_EQ(max_entries, service_->entries().size());
770 SynchronousLoadTabsFromLastSession();
771 EXPECT_TRUE(observer.got_loaded());
772 EXPECT_TRUE(service_->IsLoaded());
773 service_->RemoveObserver(&observer);