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 "chrome/browser/sessions/persistent_tab_restore_service.h"
9 #include "base/compiler_specific.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/threading/sequenced_worker_pool.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/sessions/session_service.h"
15 #include "chrome/browser/sessions/session_service_factory.h"
16 #include "chrome/browser/sessions/session_service_utils.h"
17 #include "chrome/browser/sessions/tab_restore_service_factory.h"
18 #include "chrome/browser/sessions/tab_restore_service_observer.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/testing_profile.h"
23 #include "components/sessions/serialized_navigation_entry_test_helper.h"
24 #include "components/sessions/session_types.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"
36 typedef TabRestoreService::Tab Tab
;
37 typedef TabRestoreService::Window Window
;
39 using content::NavigationEntry
;
40 using content::WebContentsTester
;
41 using sessions::SerializedNavigationEntry
;
42 using sessions::SerializedNavigationEntryTestHelper
;
44 // Create subclass that overrides TimeNow so that we can control the time used
45 // for closed tabs and windows.
46 class PersistentTabRestoreTimeFactory
: public TabRestoreService::TimeFactory
{
48 PersistentTabRestoreTimeFactory() : time_(base::Time::Now()) {}
50 ~PersistentTabRestoreTimeFactory() override
{}
52 base::Time
TimeNow() override
{ return time_
; }
58 class PersistentTabRestoreServiceTest
: public ChromeRenderViewHostTestHarness
{
60 PersistentTabRestoreServiceTest()
65 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19"
66 " (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19"),
70 ~PersistentTabRestoreServiceTest() override
{}
74 kMaxEntries
= TabRestoreServiceHelper::kMaxEntries
,
78 void SetUp() override
{
79 ChromeRenderViewHostTestHarness::SetUp();
80 time_factory_
= new PersistentTabRestoreTimeFactory();
81 service_
.reset(new PersistentTabRestoreService(profile(), time_factory_
));
84 void TearDown() override
{
88 ChromeRenderViewHostTestHarness::TearDown();
91 TabRestoreService::Entries
* mutable_entries() {
92 return service_
->mutable_entries();
96 service_
->PruneEntries();
99 void AddThreeNavigations() {
100 // Navigate to three URLs.
101 NavigateAndCommit(url1_
);
102 NavigateAndCommit(url2_
);
103 NavigateAndCommit(url3_
);
106 void NavigateToIndex(int index
) {
107 // Navigate back. We have to do this song and dance as NavigationController
108 // isn't happy if you navigate immediately while going back.
109 controller().GoToIndex(index
);
110 WebContentsTester::For(web_contents())->CommitPendingNavigation();
113 void RecreateService() {
114 // Must set service to null first so that it is destroyed before the new
116 service_
->Shutdown();
117 content::RunAllBlockingPoolTasksUntilIdle();
119 service_
.reset(new PersistentTabRestoreService(profile(), time_factory_
));
120 SynchronousLoadTabsFromLastSession();
123 // Adds a window with one tab and url to the profile's session service.
124 // If |pinned| is true, the tab is marked as pinned in the session service.
125 void AddWindowWithOneTabToSessionService(bool pinned
) {
126 SessionService
* session_service
=
127 SessionServiceFactory::GetForProfile(profile());
130 session_service
->SetWindowType(window_id
,
131 Browser::TYPE_TABBED
,
132 SessionService::TYPE_NORMAL
);
133 session_service
->SetTabWindow(window_id
, tab_id
);
134 session_service
->SetTabIndexInWindow(window_id
, tab_id
, 0);
135 session_service
->SetSelectedTabInWindow(window_id
, 0);
137 session_service
->SetPinnedState(window_id
, tab_id
, true);
138 session_service
->UpdateTabNavigation(
140 SerializedNavigationEntryTestHelper::CreateNavigation(
141 url1_
.spec(), "title"));
144 // Creates a SessionService and assigns it to the Profile. The SessionService
145 // is configured with a single window with a single tab pointing at url1_ by
146 // way of AddWindowWithOneTabToSessionService. If |pinned| is true, the
147 // tab is marked as pinned in the session service.
148 void CreateSessionServiceWithOneWindow(bool pinned
) {
149 scoped_ptr
<SessionService
> session_service(new SessionService(profile()));
150 SessionServiceFactory::SetForTestProfile(profile(), session_service
.Pass());
152 AddWindowWithOneTabToSessionService(pinned
);
154 // Set this, otherwise previous session won't be loaded.
155 profile()->set_last_session_exited_cleanly(false);
158 void SynchronousLoadTabsFromLastSession() {
159 // Ensures that the load is complete before continuing.
160 service_
->LoadTabsFromLastSession();
161 content::RunAllBlockingPoolTasksUntilIdle();
167 std::string user_agent_override_
;
168 scoped_ptr
<PersistentTabRestoreService
> service_
;
169 PersistentTabRestoreTimeFactory
* time_factory_
;
174 class TestTabRestoreServiceObserver
: public TabRestoreServiceObserver
{
176 TestTabRestoreServiceObserver() : got_loaded_(false) {}
178 void clear_got_loaded() { got_loaded_
= false; }
179 bool got_loaded() const { return got_loaded_
; }
181 // TabRestoreServiceObserver:
182 void TabRestoreServiceChanged(TabRestoreService
* service
) override
{}
183 void TabRestoreServiceDestroyed(TabRestoreService
* service
) override
{}
184 void TabRestoreServiceLoaded(TabRestoreService
* service
) override
{
189 // Was TabRestoreServiceLoaded() invoked?
192 DISALLOW_COPY_AND_ASSIGN(TestTabRestoreServiceObserver
);
197 TEST_F(PersistentTabRestoreServiceTest
, Basic
) {
198 AddThreeNavigations();
200 // Have the service record the tab.
201 service_
->CreateHistoricalTab(web_contents(), -1);
203 // Make sure an entry was created.
204 ASSERT_EQ(1U, service_
->entries().size());
206 // Make sure the entry matches.
207 TabRestoreService::Entry
* entry
= service_
->entries().front();
208 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
209 Tab
* tab
= static_cast<Tab
*>(entry
);
210 EXPECT_FALSE(tab
->pinned
);
211 EXPECT_TRUE(tab
->extension_app_id
.empty());
212 ASSERT_EQ(3U, tab
->navigations
.size());
213 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
214 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
215 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
216 EXPECT_EQ("", tab
->user_agent_override
);
217 EXPECT_EQ(2, tab
->current_navigation_index
);
218 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
219 tab
->timestamp
.ToInternalValue());
223 // And check again, but set the user agent override this time.
224 web_contents()->SetUserAgentOverride(user_agent_override_
);
225 service_
->CreateHistoricalTab(web_contents(), -1);
227 // There should be two entries now.
228 ASSERT_EQ(2U, service_
->entries().size());
230 // Make sure the entry matches.
231 entry
= service_
->entries().front();
232 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
233 tab
= static_cast<Tab
*>(entry
);
234 EXPECT_FALSE(tab
->pinned
);
235 ASSERT_EQ(3U, tab
->navigations
.size());
236 EXPECT_EQ(url1_
, tab
->navigations
[0].virtual_url());
237 EXPECT_EQ(url2_
, tab
->navigations
[1].virtual_url());
238 EXPECT_EQ(url3_
, tab
->navigations
[2].virtual_url());
239 EXPECT_EQ(user_agent_override_
, tab
->user_agent_override
);
240 EXPECT_EQ(1, tab
->current_navigation_index
);
241 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
242 tab
->timestamp
.ToInternalValue());
245 // Make sure TabRestoreService doesn't create an entry for a tab with no
247 TEST_F(PersistentTabRestoreServiceTest
, DontCreateEmptyTab
) {
248 service_
->CreateHistoricalTab(web_contents(), -1);
249 EXPECT_TRUE(service_
->entries().empty());
252 // Tests restoring a single tab.
253 TEST_F(PersistentTabRestoreServiceTest
, Restore
) {
254 AddThreeNavigations();
256 // Have the service record the tab.
257 service_
->CreateHistoricalTab(web_contents(), -1);
259 // Recreate the service and have it load the tabs.
262 // One entry should be created.
263 ASSERT_EQ(1U, service_
->entries().size());
265 // And verify the entry.
266 PersistentTabRestoreService::Entry
* entry
= service_
->entries().front();
267 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
268 Tab
* tab
= static_cast<Tab
*>(entry
);
269 EXPECT_FALSE(tab
->pinned
);
270 ASSERT_EQ(3U, tab
->navigations
.size());
271 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
272 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
273 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
274 EXPECT_EQ(2, tab
->current_navigation_index
);
275 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
276 tab
->timestamp
.ToInternalValue());
279 // Tests restoring a single pinned tab.
280 TEST_F(PersistentTabRestoreServiceTest
, RestorePinnedAndApp
) {
281 AddThreeNavigations();
283 // Have the service record the tab.
284 service_
->CreateHistoricalTab(web_contents(), -1);
286 // One entry should be created.
287 ASSERT_EQ(1U, service_
->entries().size());
289 // We have to explicitly mark the tab as pinned as there is no browser for
291 TabRestoreService::Entry
* entry
= service_
->entries().front();
292 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
293 Tab
* tab
= static_cast<Tab
*>(entry
);
295 const std::string
extension_app_id("test");
296 tab
->extension_app_id
= extension_app_id
;
298 // Recreate the service and have it load the tabs.
301 // One entry should be created.
302 ASSERT_EQ(1U, service_
->entries().size());
304 // And verify the entry.
305 entry
= service_
->entries().front();
306 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
307 tab
= static_cast<Tab
*>(entry
);
308 EXPECT_TRUE(tab
->pinned
);
309 ASSERT_EQ(3U, tab
->navigations
.size());
310 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
311 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
312 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
313 EXPECT_EQ(2, tab
->current_navigation_index
);
314 EXPECT_TRUE(extension_app_id
== tab
->extension_app_id
);
317 // Make sure we persist entries to disk that have post data.
318 TEST_F(PersistentTabRestoreServiceTest
, DontPersistPostData
) {
319 AddThreeNavigations();
320 controller().GetEntryAtIndex(0)->SetHasPostData(true);
321 controller().GetEntryAtIndex(1)->SetHasPostData(true);
322 controller().GetEntryAtIndex(2)->SetHasPostData(true);
324 // Have the service record the tab.
325 service_
->CreateHistoricalTab(web_contents(), -1);
326 ASSERT_EQ(1U, service_
->entries().size());
328 // Recreate the service and have it load the tabs.
331 // One entry should be created.
332 ASSERT_EQ(1U, service_
->entries().size());
334 const TabRestoreService::Entry
* restored_entry
= service_
->entries().front();
335 ASSERT_EQ(TabRestoreService::TAB
, restored_entry
->type
);
337 const Tab
* restored_tab
=
338 static_cast<const Tab
*>(restored_entry
);
339 // There should be 3 navs.
340 ASSERT_EQ(3U, restored_tab
->navigations
.size());
341 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
342 restored_tab
->timestamp
.ToInternalValue());
345 // Make sure we don't persist entries to disk that have post data. This
346 // differs from DontPersistPostData1 in that all the navigations have post
347 // data, so that nothing should be persisted.
348 TEST_F(PersistentTabRestoreServiceTest
, DontLoadTwice
) {
349 AddThreeNavigations();
351 // Have the service record the tab.
352 service_
->CreateHistoricalTab(web_contents(), -1);
353 ASSERT_EQ(1U, service_
->entries().size());
355 // Recreate the service and have it load the tabs.
358 SynchronousLoadTabsFromLastSession();
360 // There should only be one entry.
361 ASSERT_EQ(1U, service_
->entries().size());
364 // Makes sure we load the previous session as necessary.
365 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSession
) {
366 CreateSessionServiceWithOneWindow(false);
368 SessionServiceFactory::GetForProfile(profile())->
369 MoveCurrentSessionToLastSession();
371 EXPECT_FALSE(service_
->IsLoaded());
373 TestTabRestoreServiceObserver observer
;
374 service_
->AddObserver(&observer
);
375 SynchronousLoadTabsFromLastSession();
376 EXPECT_TRUE(observer
.got_loaded());
377 service_
->RemoveObserver(&observer
);
379 // Make sure we get back one entry with one tab whose url is url1.
380 ASSERT_EQ(1U, service_
->entries().size());
381 TabRestoreService::Entry
* entry2
= service_
->entries().front();
382 ASSERT_EQ(TabRestoreService::WINDOW
, entry2
->type
);
383 TabRestoreService::Window
* window
=
384 static_cast<TabRestoreService::Window
*>(entry2
);
385 ASSERT_EQ(1U, window
->tabs
.size());
386 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
387 EXPECT_EQ(0, window
->selected_tab_index
);
388 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
389 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
390 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
391 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
394 // Makes sure we don't attempt to load previous sessions after a restore.
395 TEST_F(PersistentTabRestoreServiceTest
, DontLoadAfterRestore
) {
396 CreateSessionServiceWithOneWindow(false);
398 SessionServiceFactory::GetForProfile(profile())->
399 MoveCurrentSessionToLastSession();
401 profile()->set_restored_last_session(true);
403 SynchronousLoadTabsFromLastSession();
405 // Because we restored a session PersistentTabRestoreService shouldn't load
407 ASSERT_EQ(0U, service_
->entries().size());
410 // Makes sure we don't attempt to load previous sessions after a clean exit.
411 TEST_F(PersistentTabRestoreServiceTest
, DontLoadAfterCleanExit
) {
412 CreateSessionServiceWithOneWindow(false);
414 SessionServiceFactory::GetForProfile(profile())->
415 MoveCurrentSessionToLastSession();
417 profile()->set_last_session_exited_cleanly(true);
419 SynchronousLoadTabsFromLastSession();
421 ASSERT_EQ(0U, service_
->entries().size());
424 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSessionAndTabs
) {
425 CreateSessionServiceWithOneWindow(false);
427 SessionServiceFactory::GetForProfile(profile())->
428 MoveCurrentSessionToLastSession();
430 AddThreeNavigations();
432 service_
->CreateHistoricalTab(web_contents(), -1);
436 // We should get back two entries, one from the previous session and one from
437 // the tab restore service. The previous session entry should be first.
438 ASSERT_EQ(2U, service_
->entries().size());
439 // The first entry should come from the session service.
440 TabRestoreService::Entry
* entry
= service_
->entries().front();
441 ASSERT_EQ(TabRestoreService::WINDOW
, entry
->type
);
442 TabRestoreService::Window
* window
=
443 static_cast<TabRestoreService::Window
*>(entry
);
444 ASSERT_EQ(1U, window
->tabs
.size());
445 EXPECT_EQ(0, window
->selected_tab_index
);
446 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
447 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
448 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
449 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
450 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
452 // Then the closed tab.
453 entry
= *(++service_
->entries().begin());
454 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
455 Tab
* tab
= static_cast<Tab
*>(entry
);
456 ASSERT_FALSE(tab
->pinned
);
457 ASSERT_EQ(3U, tab
->navigations
.size());
458 EXPECT_EQ(2, tab
->current_navigation_index
);
459 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
460 tab
->timestamp
.ToInternalValue());
461 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
462 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
463 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
466 // Make sure pinned state is correctly loaded from session service.
467 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSessionAndTabsPinned
) {
468 CreateSessionServiceWithOneWindow(true);
470 SessionServiceFactory::GetForProfile(profile())->
471 MoveCurrentSessionToLastSession();
473 AddThreeNavigations();
475 service_
->CreateHistoricalTab(web_contents(), -1);
479 // We should get back two entries, one from the previous session and one from
480 // the tab restore service. The previous session entry should be first.
481 ASSERT_EQ(2U, service_
->entries().size());
482 // The first entry should come from the session service.
483 TabRestoreService::Entry
* entry
= service_
->entries().front();
484 ASSERT_EQ(TabRestoreService::WINDOW
, entry
->type
);
485 TabRestoreService::Window
* window
=
486 static_cast<TabRestoreService::Window
*>(entry
);
487 ASSERT_EQ(1U, window
->tabs
.size());
488 EXPECT_EQ(0, window
->selected_tab_index
);
489 EXPECT_TRUE(window
->tabs
[0].pinned
);
490 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
491 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
492 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
494 // Then the closed tab.
495 entry
= *(++service_
->entries().begin());
496 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
497 Tab
* tab
= static_cast<Tab
*>(entry
);
498 ASSERT_FALSE(tab
->pinned
);
499 ASSERT_EQ(3U, tab
->navigations
.size());
500 EXPECT_EQ(2, tab
->current_navigation_index
);
501 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
502 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
503 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
506 // Creates kMaxEntries + 1 windows in the session service and makes sure we only
507 // get back kMaxEntries on restore.
508 TEST_F(PersistentTabRestoreServiceTest
, ManyWindowsInSessionService
) {
509 CreateSessionServiceWithOneWindow(false);
511 for (size_t i
= 0; i
< kMaxEntries
; ++i
)
512 AddWindowWithOneTabToSessionService(false);
514 SessionServiceFactory::GetForProfile(profile())->
515 MoveCurrentSessionToLastSession();
517 AddThreeNavigations();
519 service_
->CreateHistoricalTab(web_contents(), -1);
523 // We should get back kMaxEntries entries. We added more, but
524 // TabRestoreService only allows up to kMaxEntries.
525 ASSERT_EQ(kMaxEntries
, service_
->entries().size());
527 // The first entry should come from the session service.
528 TabRestoreService::Entry
* entry
= service_
->entries().front();
529 ASSERT_EQ(TabRestoreService::WINDOW
, entry
->type
);
530 TabRestoreService::Window
* window
=
531 static_cast<TabRestoreService::Window
*>(entry
);
532 ASSERT_EQ(1U, window
->tabs
.size());
533 EXPECT_EQ(0, window
->selected_tab_index
);
534 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
535 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
536 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
537 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
538 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
541 // Makes sure we restore timestamps correctly.
542 TEST_F(PersistentTabRestoreServiceTest
, TimestampSurvivesRestore
) {
543 base::Time
tab_timestamp(base::Time::FromInternalValue(123456789));
545 AddThreeNavigations();
547 // Have the service record the tab.
548 service_
->CreateHistoricalTab(web_contents(), -1);
550 // Make sure an entry was created.
551 ASSERT_EQ(1U, service_
->entries().size());
553 // Make sure the entry matches.
554 std::vector
<SerializedNavigationEntry
> old_navigations
;
556 // |entry|/|tab| doesn't survive after RecreateService().
557 TabRestoreService::Entry
* entry
= service_
->entries().front();
558 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
559 Tab
* tab
= static_cast<Tab
*>(entry
);
560 tab
->timestamp
= tab_timestamp
;
561 old_navigations
= tab
->navigations
;
564 EXPECT_EQ(3U, old_navigations
.size());
565 for (size_t i
= 0; i
< old_navigations
.size(); ++i
) {
566 EXPECT_FALSE(old_navigations
[i
].timestamp().is_null());
569 // Set this, otherwise previous session won't be loaded.
570 profile()->set_last_session_exited_cleanly(false);
574 // One entry should be created.
575 ASSERT_EQ(1U, service_
->entries().size());
577 // And verify the entry.
578 TabRestoreService::Entry
* restored_entry
= service_
->entries().front();
579 ASSERT_EQ(TabRestoreService::TAB
, restored_entry
->type
);
581 static_cast<Tab
*>(restored_entry
);
582 EXPECT_EQ(tab_timestamp
.ToInternalValue(),
583 restored_tab
->timestamp
.ToInternalValue());
584 ASSERT_EQ(old_navigations
.size(), restored_tab
->navigations
.size());
585 for (size_t i
= 0; i
< restored_tab
->navigations
.size(); ++i
) {
586 EXPECT_EQ(old_navigations
[i
].timestamp(),
587 restored_tab
->navigations
[i
].timestamp());
591 // Makes sure we restore status codes correctly.
592 TEST_F(PersistentTabRestoreServiceTest
, StatusCodesSurviveRestore
) {
593 AddThreeNavigations();
595 // Have the service record the tab.
596 service_
->CreateHistoricalTab(web_contents(), -1);
598 // Make sure an entry was created.
599 ASSERT_EQ(1U, service_
->entries().size());
601 // Make sure the entry matches.
602 std::vector
<sessions::SerializedNavigationEntry
> old_navigations
;
604 // |entry|/|tab| doesn't survive after RecreateService().
605 TabRestoreService::Entry
* entry
= service_
->entries().front();
606 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
607 Tab
* tab
= static_cast<Tab
*>(entry
);
608 old_navigations
= tab
->navigations
;
611 EXPECT_EQ(3U, old_navigations
.size());
612 for (size_t i
= 0; i
< old_navigations
.size(); ++i
) {
613 EXPECT_EQ(200, old_navigations
[i
].http_status_code());
616 // Set this, otherwise previous session won't be loaded.
617 profile()->set_last_session_exited_cleanly(false);
621 // One entry should be created.
622 ASSERT_EQ(1U, service_
->entries().size());
624 // And verify the entry.
625 TabRestoreService::Entry
* restored_entry
= service_
->entries().front();
626 ASSERT_EQ(TabRestoreService::TAB
, restored_entry
->type
);
628 static_cast<Tab
*>(restored_entry
);
629 ASSERT_EQ(old_navigations
.size(), restored_tab
->navigations
.size());
630 for (size_t i
= 0; i
< restored_tab
->navigations
.size(); ++i
) {
631 EXPECT_EQ(200, restored_tab
->navigations
[i
].http_status_code());
635 TEST_F(PersistentTabRestoreServiceTest
, PruneEntries
) {
636 service_
->ClearEntries();
637 ASSERT_TRUE(service_
->entries().empty());
639 const size_t max_entries
= kMaxEntries
;
640 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
641 SerializedNavigationEntry navigation
=
642 SerializedNavigationEntryTestHelper::CreateNavigation(
643 base::StringPrintf("http://%d", static_cast<int>(i
)),
644 base::StringPrintf("%d", static_cast<int>(i
)));
646 Tab
* tab
= new Tab();
647 tab
->navigations
.push_back(navigation
);
648 tab
->current_navigation_index
= 0;
650 mutable_entries()->push_back(tab
);
653 // Only keep kMaxEntries around.
654 EXPECT_EQ(max_entries
+ 5, service_
->entries().size());
656 EXPECT_EQ(max_entries
, service_
->entries().size());
657 // Pruning again does nothing.
659 EXPECT_EQ(max_entries
, service_
->entries().size());
661 // Prune older first.
662 const char kRecentUrl
[] = "http://recent";
663 SerializedNavigationEntry navigation
=
664 SerializedNavigationEntryTestHelper::CreateNavigation(kRecentUrl
,
666 Tab
* tab
= new Tab();
667 tab
->navigations
.push_back(navigation
);
668 tab
->current_navigation_index
= 0;
669 mutable_entries()->push_front(tab
);
670 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
672 EXPECT_EQ(max_entries
, service_
->entries().size());
673 EXPECT_EQ(GURL(kRecentUrl
),
674 static_cast<Tab
*>(service_
->entries().front())->
675 navigations
[0].virtual_url());
678 navigation
= SerializedNavigationEntryTestHelper::CreateNavigation(
679 chrome::kChromeUINewTabURL
, "New tab");
682 tab
->navigations
.push_back(navigation
);
683 tab
->current_navigation_index
= 0;
684 mutable_entries()->push_front(tab
);
686 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
688 EXPECT_EQ(max_entries
, service_
->entries().size());
689 EXPECT_EQ(GURL(kRecentUrl
),
690 static_cast<Tab
*>(service_
->entries().front())->
691 navigations
[0].virtual_url());
693 // Don't prune pinned NTPs.
696 tab
->current_navigation_index
= 0;
697 tab
->navigations
.push_back(navigation
);
698 mutable_entries()->push_front(tab
);
699 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
701 EXPECT_EQ(max_entries
, service_
->entries().size());
702 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL
),
703 static_cast<Tab
*>(service_
->entries().front())->
704 navigations
[0].virtual_url());
706 // Don't prune NTPs that have multiple navigations.
707 // (Erase the last NTP first.)
708 delete service_
->entries().front();
709 mutable_entries()->erase(mutable_entries()->begin());
711 tab
->current_navigation_index
= 1;
712 tab
->navigations
.push_back(navigation
);
713 tab
->navigations
.push_back(navigation
);
714 mutable_entries()->push_front(tab
);
715 EXPECT_EQ(max_entries
, service_
->entries().size());
717 EXPECT_EQ(max_entries
, service_
->entries().size());
718 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL
),
719 static_cast<Tab
*>(service_
->entries().front())->
720 navigations
[1].virtual_url());
723 // Regression test for crbug.com/106082
724 TEST_F(PersistentTabRestoreServiceTest
, PruneIsCalled
) {
725 CreateSessionServiceWithOneWindow(false);
727 SessionServiceFactory::GetForProfile(profile())->
728 MoveCurrentSessionToLastSession();
730 profile()->set_restored_last_session(true);
732 const size_t max_entries
= kMaxEntries
;
733 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
735 GURL(base::StringPrintf("http://%d", static_cast<int>(i
))));
736 service_
->CreateHistoricalTab(web_contents(), -1);
739 EXPECT_EQ(max_entries
, service_
->entries().size());
740 // This should not crash.
741 SynchronousLoadTabsFromLastSession();
742 EXPECT_EQ(max_entries
, service_
->entries().size());
745 // Makes sure invoking LoadTabsFromLastSession() when the max number of entries
746 // have been added results in IsLoaded() returning true and notifies observers.
747 TEST_F(PersistentTabRestoreServiceTest
, GoToLoadedWhenHaveMaxEntries
) {
748 const size_t max_entries
= kMaxEntries
;
749 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
751 GURL(base::StringPrintf("http://%d", static_cast<int>(i
))));
752 service_
->CreateHistoricalTab(web_contents(), -1);
755 EXPECT_FALSE(service_
->IsLoaded());
756 TestTabRestoreServiceObserver observer
;
757 service_
->AddObserver(&observer
);
758 EXPECT_EQ(max_entries
, service_
->entries().size());
759 SynchronousLoadTabsFromLastSession();
760 EXPECT_TRUE(observer
.got_loaded());
761 EXPECT_TRUE(service_
->IsLoaded());
762 service_
->RemoveObserver(&observer
);