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"
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
{
51 PersistentTabRestoreTimeFactory() : time_(base::Time::Now()) {}
53 ~PersistentTabRestoreTimeFactory() override
{}
55 base::Time
TimeNow() override
{ return time_
; }
61 class PersistentTabRestoreServiceTest
: public ChromeRenderViewHostTestHarness
{
63 PersistentTabRestoreServiceTest()
68 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19"
69 " (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19"),
73 ~PersistentTabRestoreServiceTest() override
{}
77 kMaxEntries
= TabRestoreServiceHelper::kMaxEntries
,
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())),
90 void TearDown() override
{
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
122 service_
->Shutdown();
123 content::RunAllBlockingPoolTasksUntilIdle();
125 service_
.reset(new PersistentTabRestoreService(
126 make_scoped_ptr(new ChromeTabRestoreServiceClient(profile())),
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());
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);
145 session_service
->SetPinnedState(window_id
, tab_id
, true);
146 session_service
->UpdateTabNavigation(
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(); }
177 std::string user_agent_override_
;
178 scoped_ptr
<sessions::LiveTab
> live_tab_
;
179 scoped_ptr
<PersistentTabRestoreService
> service_
;
180 PersistentTabRestoreTimeFactory
* time_factory_
;
185 class TestTabRestoreServiceObserver
: public TabRestoreServiceObserver
{
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
{
200 // Was TabRestoreServiceLoaded() invoked?
203 DISALLOW_COPY_AND_ASSIGN(TestTabRestoreServiceObserver
);
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());
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
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.
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
302 TabRestoreService::Entry
* entry
= service_
->entries().front();
303 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
304 Tab
* tab
= static_cast<Tab
*>(entry
);
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.
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.
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.
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
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);
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);
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);
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);
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
);
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);
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
);
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());
667 EXPECT_EQ(max_entries
, service_
->entries().size());
668 // Pruning again does nothing.
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
,
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());
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());
689 navigation
= SerializedNavigationEntryTestHelper::CreateNavigation(
690 chrome::kChromeUINewTabURL
, "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());
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.
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());
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());
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());
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
++) {
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
++) {
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
);