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/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/browser/sessions/tab_restore_service_observer.h"
21 #include "chrome/common/url_constants.h"
22 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
23 #include "chrome/test/base/chrome_render_view_test.h"
24 #include "chrome/test/base/testing_profile.h"
25 #include "components/sessions/serialized_navigation_entry_test_helper.h"
26 #include "components/sessions/session_types.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/navigation_controller.h"
29 #include "content/public/browser/navigation_entry.h"
30 #include "content/public/browser/notification_service.h"
31 #include "content/public/browser/notification_types.h"
32 #include "content/public/browser/web_contents.h"
33 #include "content/public/test/render_view_test.h"
34 #include "content/public/test/test_utils.h"
35 #include "content/public/test/web_contents_tester.h"
36 #include "testing/gtest/include/gtest/gtest.h"
38 typedef TabRestoreService::Tab Tab
;
39 typedef TabRestoreService::Window Window
;
41 using content::NavigationEntry
;
42 using content::WebContentsTester
;
43 using sessions::SerializedNavigationEntry
;
44 using sessions::SerializedNavigationEntryTestHelper
;
46 // Create subclass that overrides TimeNow so that we can control the time used
47 // for closed tabs and windows.
48 class PersistentTabRestoreTimeFactory
: public TabRestoreService::TimeFactory
{
50 PersistentTabRestoreTimeFactory() : time_(base::Time::Now()) {}
52 ~PersistentTabRestoreTimeFactory() override
{}
54 base::Time
TimeNow() override
{ return time_
; }
60 class PersistentTabRestoreServiceTest
: public ChromeRenderViewHostTestHarness
{
62 PersistentTabRestoreServiceTest()
67 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19"
68 " (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19"),
72 ~PersistentTabRestoreServiceTest() override
{}
76 kMaxEntries
= TabRestoreServiceHelper::kMaxEntries
,
80 void SetUp() override
{
81 ChromeRenderViewHostTestHarness::SetUp();
82 time_factory_
= new PersistentTabRestoreTimeFactory();
83 service_
.reset(new PersistentTabRestoreService(
85 make_scoped_ptr(new ChromeTabRestoreServiceClient(profile())),
89 void TearDown() override
{
93 ChromeRenderViewHostTestHarness::TearDown();
96 TabRestoreService::Entries
* mutable_entries() {
97 return service_
->mutable_entries();
100 void PruneEntries() {
101 service_
->PruneEntries();
104 void AddThreeNavigations() {
105 // Navigate to three URLs.
106 NavigateAndCommit(url1_
);
107 NavigateAndCommit(url2_
);
108 NavigateAndCommit(url3_
);
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();
118 void RecreateService() {
119 // Must set service to null first so that it is destroyed before the new
121 service_
->Shutdown();
122 content::RunAllBlockingPoolTasksUntilIdle();
124 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();
175 std::string user_agent_override_
;
176 scoped_ptr
<PersistentTabRestoreService
> service_
;
177 PersistentTabRestoreTimeFactory
* time_factory_
;
182 class TestTabRestoreServiceObserver
: public TabRestoreServiceObserver
{
184 TestTabRestoreServiceObserver() : got_loaded_(false) {}
186 void clear_got_loaded() { got_loaded_
= false; }
187 bool got_loaded() const { return got_loaded_
; }
189 // TabRestoreServiceObserver:
190 void TabRestoreServiceChanged(TabRestoreService
* service
) override
{}
191 void TabRestoreServiceDestroyed(TabRestoreService
* service
) override
{}
192 void TabRestoreServiceLoaded(TabRestoreService
* service
) override
{
197 // Was TabRestoreServiceLoaded() invoked?
200 DISALLOW_COPY_AND_ASSIGN(TestTabRestoreServiceObserver
);
205 TEST_F(PersistentTabRestoreServiceTest
, Basic
) {
206 AddThreeNavigations();
208 // Have the service record the tab.
209 service_
->CreateHistoricalTab(web_contents(), -1);
211 // Make sure an entry was created.
212 ASSERT_EQ(1U, service_
->entries().size());
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());
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);
235 // There should be two entries now.
236 ASSERT_EQ(2U, service_
->entries().size());
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());
253 // Make sure TabRestoreService doesn't create an entry for a tab with no
255 TEST_F(PersistentTabRestoreServiceTest
, DontCreateEmptyTab
) {
256 service_
->CreateHistoricalTab(web_contents(), -1);
257 EXPECT_TRUE(service_
->entries().empty());
260 // Tests restoring a single tab.
261 TEST_F(PersistentTabRestoreServiceTest
, Restore
) {
262 AddThreeNavigations();
264 // Have the service record the tab.
265 service_
->CreateHistoricalTab(web_contents(), -1);
267 // Recreate the service and have it load the tabs.
270 // One entry should be created.
271 ASSERT_EQ(1U, service_
->entries().size());
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());
287 // Tests restoring a single pinned tab.
288 TEST_F(PersistentTabRestoreServiceTest
, RestorePinnedAndApp
) {
289 AddThreeNavigations();
291 // Have the service record the tab.
292 service_
->CreateHistoricalTab(web_contents(), -1);
294 // One entry should be created.
295 ASSERT_EQ(1U, service_
->entries().size());
297 // We have to explicitly mark the tab as pinned as there is no browser for
299 TabRestoreService::Entry
* entry
= service_
->entries().front();
300 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
301 Tab
* tab
= static_cast<Tab
*>(entry
);
303 const std::string
extension_app_id("test");
304 tab
->extension_app_id
= extension_app_id
;
306 // Recreate the service and have it load the tabs.
309 // One entry should be created.
310 ASSERT_EQ(1U, service_
->entries().size());
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
);
325 // Make sure we persist entries to disk that have post data.
326 TEST_F(PersistentTabRestoreServiceTest
, DontPersistPostData
) {
327 AddThreeNavigations();
328 controller().GetEntryAtIndex(0)->SetHasPostData(true);
329 controller().GetEntryAtIndex(1)->SetHasPostData(true);
330 controller().GetEntryAtIndex(2)->SetHasPostData(true);
332 // Have the service record the tab.
333 service_
->CreateHistoricalTab(web_contents(), -1);
334 ASSERT_EQ(1U, service_
->entries().size());
336 // Recreate the service and have it load the tabs.
339 // One entry should be created.
340 ASSERT_EQ(1U, service_
->entries().size());
342 const TabRestoreService::Entry
* restored_entry
= service_
->entries().front();
343 ASSERT_EQ(TabRestoreService::TAB
, restored_entry
->type
);
345 const Tab
* restored_tab
=
346 static_cast<const Tab
*>(restored_entry
);
347 // There should be 3 navs.
348 ASSERT_EQ(3U, restored_tab
->navigations
.size());
349 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
350 restored_tab
->timestamp
.ToInternalValue());
353 // Make sure we don't persist entries to disk that have post data. This
354 // differs from DontPersistPostData1 in that all the navigations have post
355 // data, so that nothing should be persisted.
356 TEST_F(PersistentTabRestoreServiceTest
, DontLoadTwice
) {
357 AddThreeNavigations();
359 // Have the service record the tab.
360 service_
->CreateHistoricalTab(web_contents(), -1);
361 ASSERT_EQ(1U, service_
->entries().size());
363 // Recreate the service and have it load the tabs.
366 SynchronousLoadTabsFromLastSession();
368 // There should only be one entry.
369 ASSERT_EQ(1U, service_
->entries().size());
372 // Makes sure we load the previous session as necessary.
373 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSession
) {
374 CreateSessionServiceWithOneWindow(false);
376 SessionServiceFactory::GetForProfile(profile())->
377 MoveCurrentSessionToLastSession();
379 EXPECT_FALSE(service_
->IsLoaded());
381 TestTabRestoreServiceObserver observer
;
382 service_
->AddObserver(&observer
);
383 SynchronousLoadTabsFromLastSession();
384 EXPECT_TRUE(observer
.got_loaded());
385 service_
->RemoveObserver(&observer
);
387 // Make sure we get back one entry with one tab whose url is url1.
388 ASSERT_EQ(1U, service_
->entries().size());
389 TabRestoreService::Entry
* entry2
= service_
->entries().front();
390 ASSERT_EQ(TabRestoreService::WINDOW
, entry2
->type
);
391 TabRestoreService::Window
* window
=
392 static_cast<TabRestoreService::Window
*>(entry2
);
393 ASSERT_EQ(1U, window
->tabs
.size());
394 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
395 EXPECT_EQ(0, window
->selected_tab_index
);
396 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
397 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
398 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
399 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
402 // Makes sure we don't attempt to load previous sessions after a restore.
403 TEST_F(PersistentTabRestoreServiceTest
, DontLoadAfterRestore
) {
404 CreateSessionServiceWithOneWindow(false);
406 SessionServiceFactory::GetForProfile(profile())->
407 MoveCurrentSessionToLastSession();
409 profile()->set_restored_last_session(true);
411 SynchronousLoadTabsFromLastSession();
413 // Because we restored a session PersistentTabRestoreService shouldn't load
415 ASSERT_EQ(0U, service_
->entries().size());
418 // Makes sure we don't attempt to load previous sessions after a clean exit.
419 TEST_F(PersistentTabRestoreServiceTest
, DontLoadAfterCleanExit
) {
420 CreateSessionServiceWithOneWindow(false);
422 SessionServiceFactory::GetForProfile(profile())->
423 MoveCurrentSessionToLastSession();
425 profile()->set_last_session_exited_cleanly(true);
427 SynchronousLoadTabsFromLastSession();
429 ASSERT_EQ(0U, service_
->entries().size());
432 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSessionAndTabs
) {
433 CreateSessionServiceWithOneWindow(false);
435 SessionServiceFactory::GetForProfile(profile())->
436 MoveCurrentSessionToLastSession();
438 AddThreeNavigations();
440 service_
->CreateHistoricalTab(web_contents(), -1);
444 // We should get back two entries, one from the previous session and one from
445 // the tab restore service. The previous session entry should be first.
446 ASSERT_EQ(2U, service_
->entries().size());
447 // The first entry should come from the session service.
448 TabRestoreService::Entry
* entry
= service_
->entries().front();
449 ASSERT_EQ(TabRestoreService::WINDOW
, entry
->type
);
450 TabRestoreService::Window
* window
=
451 static_cast<TabRestoreService::Window
*>(entry
);
452 ASSERT_EQ(1U, window
->tabs
.size());
453 EXPECT_EQ(0, window
->selected_tab_index
);
454 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
455 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
456 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
457 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
458 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
460 // Then the closed tab.
461 entry
= *(++service_
->entries().begin());
462 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
463 Tab
* tab
= static_cast<Tab
*>(entry
);
464 ASSERT_FALSE(tab
->pinned
);
465 ASSERT_EQ(3U, tab
->navigations
.size());
466 EXPECT_EQ(2, tab
->current_navigation_index
);
467 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
468 tab
->timestamp
.ToInternalValue());
469 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
470 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
471 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
474 // Make sure pinned state is correctly loaded from session service.
475 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSessionAndTabsPinned
) {
476 CreateSessionServiceWithOneWindow(true);
478 SessionServiceFactory::GetForProfile(profile())->
479 MoveCurrentSessionToLastSession();
481 AddThreeNavigations();
483 service_
->CreateHistoricalTab(web_contents(), -1);
487 // We should get back two entries, one from the previous session and one from
488 // the tab restore service. The previous session entry should be first.
489 ASSERT_EQ(2U, service_
->entries().size());
490 // The first entry should come from the session service.
491 TabRestoreService::Entry
* entry
= service_
->entries().front();
492 ASSERT_EQ(TabRestoreService::WINDOW
, entry
->type
);
493 TabRestoreService::Window
* window
=
494 static_cast<TabRestoreService::Window
*>(entry
);
495 ASSERT_EQ(1U, window
->tabs
.size());
496 EXPECT_EQ(0, window
->selected_tab_index
);
497 EXPECT_TRUE(window
->tabs
[0].pinned
);
498 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
499 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
500 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
502 // Then the closed tab.
503 entry
= *(++service_
->entries().begin());
504 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
505 Tab
* tab
= static_cast<Tab
*>(entry
);
506 ASSERT_FALSE(tab
->pinned
);
507 ASSERT_EQ(3U, tab
->navigations
.size());
508 EXPECT_EQ(2, tab
->current_navigation_index
);
509 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
510 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
511 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
514 // Creates kMaxEntries + 1 windows in the session service and makes sure we only
515 // get back kMaxEntries on restore.
516 TEST_F(PersistentTabRestoreServiceTest
, ManyWindowsInSessionService
) {
517 CreateSessionServiceWithOneWindow(false);
519 for (size_t i
= 0; i
< kMaxEntries
; ++i
)
520 AddWindowWithOneTabToSessionService(false);
522 SessionServiceFactory::GetForProfile(profile())->
523 MoveCurrentSessionToLastSession();
525 AddThreeNavigations();
527 service_
->CreateHistoricalTab(web_contents(), -1);
531 // We should get back kMaxEntries entries. We added more, but
532 // TabRestoreService only allows up to kMaxEntries.
533 ASSERT_EQ(kMaxEntries
, service_
->entries().size());
535 // The first entry should come from the session service.
536 TabRestoreService::Entry
* entry
= service_
->entries().front();
537 ASSERT_EQ(TabRestoreService::WINDOW
, entry
->type
);
538 TabRestoreService::Window
* window
=
539 static_cast<TabRestoreService::Window
*>(entry
);
540 ASSERT_EQ(1U, window
->tabs
.size());
541 EXPECT_EQ(0, window
->selected_tab_index
);
542 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
543 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
544 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
545 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
546 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
549 // Makes sure we restore timestamps correctly.
550 TEST_F(PersistentTabRestoreServiceTest
, TimestampSurvivesRestore
) {
551 base::Time
tab_timestamp(base::Time::FromInternalValue(123456789));
553 AddThreeNavigations();
555 // Have the service record the tab.
556 service_
->CreateHistoricalTab(web_contents(), -1);
558 // Make sure an entry was created.
559 ASSERT_EQ(1U, service_
->entries().size());
561 // Make sure the entry matches.
562 std::vector
<SerializedNavigationEntry
> old_navigations
;
564 // |entry|/|tab| doesn't survive after RecreateService().
565 TabRestoreService::Entry
* entry
= service_
->entries().front();
566 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
567 Tab
* tab
= static_cast<Tab
*>(entry
);
568 tab
->timestamp
= tab_timestamp
;
569 old_navigations
= tab
->navigations
;
572 EXPECT_EQ(3U, old_navigations
.size());
573 for (size_t i
= 0; i
< old_navigations
.size(); ++i
) {
574 EXPECT_FALSE(old_navigations
[i
].timestamp().is_null());
577 // Set this, otherwise previous session won't be loaded.
578 profile()->set_last_session_exited_cleanly(false);
582 // One entry should be created.
583 ASSERT_EQ(1U, service_
->entries().size());
585 // And verify the entry.
586 TabRestoreService::Entry
* restored_entry
= service_
->entries().front();
587 ASSERT_EQ(TabRestoreService::TAB
, restored_entry
->type
);
589 static_cast<Tab
*>(restored_entry
);
590 EXPECT_EQ(tab_timestamp
.ToInternalValue(),
591 restored_tab
->timestamp
.ToInternalValue());
592 ASSERT_EQ(old_navigations
.size(), restored_tab
->navigations
.size());
593 for (size_t i
= 0; i
< restored_tab
->navigations
.size(); ++i
) {
594 EXPECT_EQ(old_navigations
[i
].timestamp(),
595 restored_tab
->navigations
[i
].timestamp());
599 // Makes sure we restore status codes correctly.
600 TEST_F(PersistentTabRestoreServiceTest
, StatusCodesSurviveRestore
) {
601 AddThreeNavigations();
603 // Have the service record the tab.
604 service_
->CreateHistoricalTab(web_contents(), -1);
606 // Make sure an entry was created.
607 ASSERT_EQ(1U, service_
->entries().size());
609 // Make sure the entry matches.
610 std::vector
<sessions::SerializedNavigationEntry
> old_navigations
;
612 // |entry|/|tab| doesn't survive after RecreateService().
613 TabRestoreService::Entry
* entry
= service_
->entries().front();
614 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
615 Tab
* tab
= static_cast<Tab
*>(entry
);
616 old_navigations
= tab
->navigations
;
619 EXPECT_EQ(3U, old_navigations
.size());
620 for (size_t i
= 0; i
< old_navigations
.size(); ++i
) {
621 EXPECT_EQ(200, old_navigations
[i
].http_status_code());
624 // Set this, otherwise previous session won't be loaded.
625 profile()->set_last_session_exited_cleanly(false);
629 // One entry should be created.
630 ASSERT_EQ(1U, service_
->entries().size());
632 // And verify the entry.
633 TabRestoreService::Entry
* restored_entry
= service_
->entries().front();
634 ASSERT_EQ(TabRestoreService::TAB
, restored_entry
->type
);
636 static_cast<Tab
*>(restored_entry
);
637 ASSERT_EQ(old_navigations
.size(), restored_tab
->navigations
.size());
638 for (size_t i
= 0; i
< restored_tab
->navigations
.size(); ++i
) {
639 EXPECT_EQ(200, restored_tab
->navigations
[i
].http_status_code());
643 TEST_F(PersistentTabRestoreServiceTest
, PruneEntries
) {
644 service_
->ClearEntries();
645 ASSERT_TRUE(service_
->entries().empty());
647 const size_t max_entries
= kMaxEntries
;
648 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
649 SerializedNavigationEntry navigation
=
650 SerializedNavigationEntryTestHelper::CreateNavigation(
651 base::StringPrintf("http://%d", static_cast<int>(i
)),
652 base::SizeTToString(i
));
654 Tab
* tab
= new Tab();
655 tab
->navigations
.push_back(navigation
);
656 tab
->current_navigation_index
= 0;
658 mutable_entries()->push_back(tab
);
661 // Only keep kMaxEntries around.
662 EXPECT_EQ(max_entries
+ 5, service_
->entries().size());
664 EXPECT_EQ(max_entries
, service_
->entries().size());
665 // Pruning again does nothing.
667 EXPECT_EQ(max_entries
, service_
->entries().size());
669 // Prune older first.
670 const char kRecentUrl
[] = "http://recent";
671 SerializedNavigationEntry navigation
=
672 SerializedNavigationEntryTestHelper::CreateNavigation(kRecentUrl
,
674 Tab
* tab
= new Tab();
675 tab
->navigations
.push_back(navigation
);
676 tab
->current_navigation_index
= 0;
677 mutable_entries()->push_front(tab
);
678 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
680 EXPECT_EQ(max_entries
, service_
->entries().size());
681 EXPECT_EQ(GURL(kRecentUrl
),
682 static_cast<Tab
*>(service_
->entries().front())->
683 navigations
[0].virtual_url());
686 navigation
= SerializedNavigationEntryTestHelper::CreateNavigation(
687 chrome::kChromeUINewTabURL
, "New tab");
690 tab
->navigations
.push_back(navigation
);
691 tab
->current_navigation_index
= 0;
692 mutable_entries()->push_front(tab
);
694 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
696 EXPECT_EQ(max_entries
, service_
->entries().size());
697 EXPECT_EQ(GURL(kRecentUrl
),
698 static_cast<Tab
*>(service_
->entries().front())->
699 navigations
[0].virtual_url());
701 // Don't prune pinned NTPs.
704 tab
->current_navigation_index
= 0;
705 tab
->navigations
.push_back(navigation
);
706 mutable_entries()->push_front(tab
);
707 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
709 EXPECT_EQ(max_entries
, service_
->entries().size());
710 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL
),
711 static_cast<Tab
*>(service_
->entries().front())->
712 navigations
[0].virtual_url());
714 // Don't prune NTPs that have multiple navigations.
715 // (Erase the last NTP first.)
716 delete service_
->entries().front();
717 mutable_entries()->erase(mutable_entries()->begin());
719 tab
->current_navigation_index
= 1;
720 tab
->navigations
.push_back(navigation
);
721 tab
->navigations
.push_back(navigation
);
722 mutable_entries()->push_front(tab
);
723 EXPECT_EQ(max_entries
, service_
->entries().size());
725 EXPECT_EQ(max_entries
, service_
->entries().size());
726 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL
),
727 static_cast<Tab
*>(service_
->entries().front())->
728 navigations
[1].virtual_url());
731 // Regression test for crbug.com/106082
732 TEST_F(PersistentTabRestoreServiceTest
, PruneIsCalled
) {
733 CreateSessionServiceWithOneWindow(false);
735 SessionServiceFactory::GetForProfile(profile())->
736 MoveCurrentSessionToLastSession();
738 profile()->set_restored_last_session(true);
740 const size_t max_entries
= kMaxEntries
;
741 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
743 GURL(base::StringPrintf("http://%d", static_cast<int>(i
))));
744 service_
->CreateHistoricalTab(web_contents(), -1);
747 EXPECT_EQ(max_entries
, service_
->entries().size());
748 // This should not crash.
749 SynchronousLoadTabsFromLastSession();
750 EXPECT_EQ(max_entries
, service_
->entries().size());
753 // Makes sure invoking LoadTabsFromLastSession() when the max number of entries
754 // have been added results in IsLoaded() returning true and notifies observers.
755 TEST_F(PersistentTabRestoreServiceTest
, GoToLoadedWhenHaveMaxEntries
) {
756 const size_t max_entries
= kMaxEntries
;
757 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
759 GURL(base::StringPrintf("http://%d", static_cast<int>(i
))));
760 service_
->CreateHistoricalTab(web_contents(), -1);
763 EXPECT_FALSE(service_
->IsLoaded());
764 TestTabRestoreServiceObserver observer
;
765 service_
->AddObserver(&observer
);
766 EXPECT_EQ(max_entries
, service_
->entries().size());
767 SynchronousLoadTabsFromLastSession();
768 EXPECT_TRUE(observer
.got_loaded());
769 EXPECT_TRUE(service_
->IsLoaded());
770 service_
->RemoveObserver(&observer
);