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 sessions::TabRestoreService::Tab Tab
;
40 typedef sessions::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
50 : public sessions::TabRestoreService::TimeFactory
{
52 PersistentTabRestoreTimeFactory() : time_(base::Time::Now()) {}
54 ~PersistentTabRestoreTimeFactory() override
{}
56 base::Time
TimeNow() override
{ return time_
; }
62 class PersistentTabRestoreServiceTest
: public ChromeRenderViewHostTestHarness
{
64 PersistentTabRestoreServiceTest()
69 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19"
70 " (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19"),
74 ~PersistentTabRestoreServiceTest() override
{}
78 kMaxEntries
= sessions::TabRestoreServiceHelper::kMaxEntries
,
82 void SetUp() override
{
83 ChromeRenderViewHostTestHarness::SetUp();
84 live_tab_
= make_scoped_ptr(new sessions::ContentLiveTab(web_contents()));
85 time_factory_
= new PersistentTabRestoreTimeFactory();
86 service_
.reset(new sessions::PersistentTabRestoreService(
87 make_scoped_ptr(new ChromeTabRestoreServiceClient(profile())),
91 void TearDown() override
{
95 ChromeRenderViewHostTestHarness::TearDown();
98 sessions::TabRestoreService::Entries
* mutable_entries() {
99 return service_
->mutable_entries();
102 void PruneEntries() {
103 service_
->PruneEntries();
106 void AddThreeNavigations() {
107 // Navigate to three URLs.
108 NavigateAndCommit(url1_
);
109 NavigateAndCommit(url2_
);
110 NavigateAndCommit(url3_
);
113 void NavigateToIndex(int index
) {
114 // Navigate back. We have to do this song and dance as NavigationController
115 // isn't happy if you navigate immediately while going back.
116 controller().GoToIndex(index
);
117 WebContentsTester::For(web_contents())->CommitPendingNavigation();
120 void RecreateService() {
121 // Must set service to null first so that it is destroyed before the new
123 service_
->Shutdown();
124 content::RunAllBlockingPoolTasksUntilIdle();
126 service_
.reset(new sessions::PersistentTabRestoreService(
127 make_scoped_ptr(new ChromeTabRestoreServiceClient(profile())),
129 SynchronousLoadTabsFromLastSession();
132 // Adds a window with one tab and url to the profile's session service.
133 // If |pinned| is true, the tab is marked as pinned in the session service.
134 void AddWindowWithOneTabToSessionService(bool pinned
) {
135 SessionService
* session_service
=
136 SessionServiceFactory::GetForProfile(profile());
139 session_service
->SetWindowType(window_id
,
140 Browser::TYPE_TABBED
,
141 SessionService::TYPE_NORMAL
);
142 session_service
->SetTabWindow(window_id
, tab_id
);
143 session_service
->SetTabIndexInWindow(window_id
, tab_id
, 0);
144 session_service
->SetSelectedTabInWindow(window_id
, 0);
146 session_service
->SetPinnedState(window_id
, tab_id
, true);
147 session_service
->UpdateTabNavigation(
149 SerializedNavigationEntryTestHelper::CreateNavigation(
150 url1_
.spec(), "title"));
153 // Creates a SessionService and assigns it to the Profile. The SessionService
154 // is configured with a single window with a single tab pointing at url1_ by
155 // way of AddWindowWithOneTabToSessionService. If |pinned| is true, the
156 // tab is marked as pinned in the session service.
157 void CreateSessionServiceWithOneWindow(bool pinned
) {
158 scoped_ptr
<SessionService
> session_service(new SessionService(profile()));
159 SessionServiceFactory::SetForTestProfile(profile(), session_service
.Pass());
161 AddWindowWithOneTabToSessionService(pinned
);
163 // Set this, otherwise previous session won't be loaded.
164 profile()->set_last_session_exited_cleanly(false);
167 void SynchronousLoadTabsFromLastSession() {
168 // Ensures that the load is complete before continuing.
169 service_
->LoadTabsFromLastSession();
170 content::RunAllBlockingPoolTasksUntilIdle();
173 sessions::LiveTab
* live_tab() { return live_tab_
.get(); }
178 std::string user_agent_override_
;
179 scoped_ptr
<sessions::LiveTab
> live_tab_
;
180 scoped_ptr
<sessions::PersistentTabRestoreService
> service_
;
181 PersistentTabRestoreTimeFactory
* time_factory_
;
186 class TestTabRestoreServiceObserver
187 : public sessions::TabRestoreServiceObserver
{
189 TestTabRestoreServiceObserver() : got_loaded_(false) {}
191 void clear_got_loaded() { got_loaded_
= false; }
192 bool got_loaded() const { return got_loaded_
; }
194 // TabRestoreServiceObserver:
195 void TabRestoreServiceChanged(sessions::TabRestoreService
* service
) override
{
197 void TabRestoreServiceDestroyed(
198 sessions::TabRestoreService
* service
) override
{}
199 void TabRestoreServiceLoaded(sessions::TabRestoreService
* service
) override
{
204 // Was TabRestoreServiceLoaded() invoked?
207 DISALLOW_COPY_AND_ASSIGN(TestTabRestoreServiceObserver
);
212 TEST_F(PersistentTabRestoreServiceTest
, Basic
) {
213 AddThreeNavigations();
215 // Have the service record the tab.
216 service_
->CreateHistoricalTab(live_tab(), -1);
218 // Make sure an entry was created.
219 ASSERT_EQ(1U, service_
->entries().size());
221 // Make sure the entry matches.
222 sessions::TabRestoreService::Entry
* entry
= service_
->entries().front();
223 ASSERT_EQ(sessions::TabRestoreService::TAB
, entry
->type
);
224 Tab
* tab
= static_cast<Tab
*>(entry
);
225 EXPECT_FALSE(tab
->pinned
);
226 EXPECT_TRUE(tab
->extension_app_id
.empty());
227 ASSERT_EQ(3U, tab
->navigations
.size());
228 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
229 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
230 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
231 EXPECT_EQ("", tab
->user_agent_override
);
232 EXPECT_EQ(2, tab
->current_navigation_index
);
233 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
234 tab
->timestamp
.ToInternalValue());
238 // And check again, but set the user agent override this time.
239 web_contents()->SetUserAgentOverride(user_agent_override_
);
240 service_
->CreateHistoricalTab(live_tab(), -1);
242 // There should be two entries now.
243 ASSERT_EQ(2U, service_
->entries().size());
245 // Make sure the entry matches.
246 entry
= service_
->entries().front();
247 ASSERT_EQ(sessions::TabRestoreService::TAB
, entry
->type
);
248 tab
= static_cast<Tab
*>(entry
);
249 EXPECT_FALSE(tab
->pinned
);
250 ASSERT_EQ(3U, tab
->navigations
.size());
251 EXPECT_EQ(url1_
, tab
->navigations
[0].virtual_url());
252 EXPECT_EQ(url2_
, tab
->navigations
[1].virtual_url());
253 EXPECT_EQ(url3_
, tab
->navigations
[2].virtual_url());
254 EXPECT_EQ(user_agent_override_
, tab
->user_agent_override
);
255 EXPECT_EQ(1, tab
->current_navigation_index
);
256 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
257 tab
->timestamp
.ToInternalValue());
260 // Make sure TabRestoreService doesn't create an entry for a tab with no
262 TEST_F(PersistentTabRestoreServiceTest
, DontCreateEmptyTab
) {
263 service_
->CreateHistoricalTab(live_tab(), -1);
264 EXPECT_TRUE(service_
->entries().empty());
267 // Tests restoring a single tab.
268 TEST_F(PersistentTabRestoreServiceTest
, Restore
) {
269 AddThreeNavigations();
271 // Have the service record the tab.
272 service_
->CreateHistoricalTab(live_tab(), -1);
274 // Recreate the service and have it load the tabs.
277 // One entry should be created.
278 ASSERT_EQ(1U, service_
->entries().size());
280 // And verify the entry.
281 sessions::PersistentTabRestoreService::Entry
* entry
=
282 service_
->entries().front();
283 ASSERT_EQ(sessions::TabRestoreService::TAB
, entry
->type
);
284 Tab
* tab
= static_cast<Tab
*>(entry
);
285 EXPECT_FALSE(tab
->pinned
);
286 ASSERT_EQ(3U, tab
->navigations
.size());
287 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
288 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
289 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
290 EXPECT_EQ(2, tab
->current_navigation_index
);
291 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
292 tab
->timestamp
.ToInternalValue());
295 // Tests restoring a single pinned tab.
296 TEST_F(PersistentTabRestoreServiceTest
, RestorePinnedAndApp
) {
297 AddThreeNavigations();
299 // Have the service record the tab.
300 service_
->CreateHistoricalTab(live_tab(), -1);
302 // One entry should be created.
303 ASSERT_EQ(1U, service_
->entries().size());
305 // We have to explicitly mark the tab as pinned as there is no browser for
307 sessions::TabRestoreService::Entry
* entry
= service_
->entries().front();
308 ASSERT_EQ(sessions::TabRestoreService::TAB
, entry
->type
);
309 Tab
* tab
= static_cast<Tab
*>(entry
);
311 const std::string
extension_app_id("test");
312 tab
->extension_app_id
= extension_app_id
;
314 // Recreate the service and have it load the tabs.
317 // One entry should be created.
318 ASSERT_EQ(1U, service_
->entries().size());
320 // And verify the entry.
321 entry
= service_
->entries().front();
322 ASSERT_EQ(sessions::TabRestoreService::TAB
, entry
->type
);
323 tab
= static_cast<Tab
*>(entry
);
324 EXPECT_TRUE(tab
->pinned
);
325 ASSERT_EQ(3U, tab
->navigations
.size());
326 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
327 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
328 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
329 EXPECT_EQ(2, tab
->current_navigation_index
);
330 EXPECT_TRUE(extension_app_id
== tab
->extension_app_id
);
333 // Make sure we persist entries to disk that have post data.
334 TEST_F(PersistentTabRestoreServiceTest
, DontPersistPostData
) {
335 AddThreeNavigations();
336 controller().GetEntryAtIndex(0)->SetHasPostData(true);
337 controller().GetEntryAtIndex(1)->SetHasPostData(true);
338 controller().GetEntryAtIndex(2)->SetHasPostData(true);
340 // Have the service record the tab.
341 service_
->CreateHistoricalTab(live_tab(), -1);
342 ASSERT_EQ(1U, service_
->entries().size());
344 // Recreate the service and have it load the tabs.
347 // One entry should be created.
348 ASSERT_EQ(1U, service_
->entries().size());
350 const sessions::TabRestoreService::Entry
* restored_entry
=
351 service_
->entries().front();
352 ASSERT_EQ(sessions::TabRestoreService::TAB
, restored_entry
->type
);
354 const Tab
* restored_tab
=
355 static_cast<const Tab
*>(restored_entry
);
356 // There should be 3 navs.
357 ASSERT_EQ(3U, restored_tab
->navigations
.size());
358 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
359 restored_tab
->timestamp
.ToInternalValue());
362 // Make sure we don't persist entries to disk that have post data. This
363 // differs from DontPersistPostData1 in that all the navigations have post
364 // data, so that nothing should be persisted.
365 TEST_F(PersistentTabRestoreServiceTest
, DontLoadTwice
) {
366 AddThreeNavigations();
368 // Have the service record the tab.
369 service_
->CreateHistoricalTab(live_tab(), -1);
370 ASSERT_EQ(1U, service_
->entries().size());
372 // Recreate the service and have it load the tabs.
375 SynchronousLoadTabsFromLastSession();
377 // There should only be one entry.
378 ASSERT_EQ(1U, service_
->entries().size());
381 // Makes sure we load the previous session as necessary.
382 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSession
) {
383 CreateSessionServiceWithOneWindow(false);
385 SessionServiceFactory::GetForProfile(profile())->
386 MoveCurrentSessionToLastSession();
388 EXPECT_FALSE(service_
->IsLoaded());
390 TestTabRestoreServiceObserver observer
;
391 service_
->AddObserver(&observer
);
392 SynchronousLoadTabsFromLastSession();
393 EXPECT_TRUE(observer
.got_loaded());
394 service_
->RemoveObserver(&observer
);
396 // Make sure we get back one entry with one tab whose url is url1.
397 ASSERT_EQ(1U, service_
->entries().size());
398 sessions::TabRestoreService::Entry
* entry2
= service_
->entries().front();
399 ASSERT_EQ(sessions::TabRestoreService::WINDOW
, entry2
->type
);
400 sessions::TabRestoreService::Window
* window
=
401 static_cast<sessions::TabRestoreService::Window
*>(entry2
);
402 ASSERT_EQ(1U, window
->tabs
.size());
403 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
404 EXPECT_EQ(0, window
->selected_tab_index
);
405 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
406 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
407 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
408 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
411 // Makes sure we don't attempt to load previous sessions after a restore.
412 TEST_F(PersistentTabRestoreServiceTest
, DontLoadAfterRestore
) {
413 CreateSessionServiceWithOneWindow(false);
415 SessionServiceFactory::GetForProfile(profile())->
416 MoveCurrentSessionToLastSession();
418 profile()->set_restored_last_session(true);
420 SynchronousLoadTabsFromLastSession();
422 // Because we restored a session PersistentTabRestoreService shouldn't load
424 ASSERT_EQ(0U, service_
->entries().size());
427 // Makes sure we don't attempt to load previous sessions after a clean exit.
428 TEST_F(PersistentTabRestoreServiceTest
, DontLoadAfterCleanExit
) {
429 CreateSessionServiceWithOneWindow(false);
431 SessionServiceFactory::GetForProfile(profile())->
432 MoveCurrentSessionToLastSession();
434 profile()->set_last_session_exited_cleanly(true);
436 SynchronousLoadTabsFromLastSession();
438 ASSERT_EQ(0U, service_
->entries().size());
441 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSessionAndTabs
) {
442 CreateSessionServiceWithOneWindow(false);
444 SessionServiceFactory::GetForProfile(profile())->
445 MoveCurrentSessionToLastSession();
447 AddThreeNavigations();
449 service_
->CreateHistoricalTab(live_tab(), -1);
453 // We should get back two entries, one from the previous session and one from
454 // the tab restore service. The previous session entry should be first.
455 ASSERT_EQ(2U, service_
->entries().size());
456 // The first entry should come from the session service.
457 sessions::TabRestoreService::Entry
* entry
= service_
->entries().front();
458 ASSERT_EQ(sessions::TabRestoreService::WINDOW
, entry
->type
);
459 sessions::TabRestoreService::Window
* window
=
460 static_cast<sessions::TabRestoreService::Window
*>(entry
);
461 ASSERT_EQ(1U, window
->tabs
.size());
462 EXPECT_EQ(0, window
->selected_tab_index
);
463 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
464 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
465 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
466 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
467 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
469 // Then the closed tab.
470 entry
= *(++service_
->entries().begin());
471 ASSERT_EQ(sessions::TabRestoreService::TAB
, entry
->type
);
472 Tab
* tab
= static_cast<Tab
*>(entry
);
473 ASSERT_FALSE(tab
->pinned
);
474 ASSERT_EQ(3U, tab
->navigations
.size());
475 EXPECT_EQ(2, tab
->current_navigation_index
);
476 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
477 tab
->timestamp
.ToInternalValue());
478 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
479 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
480 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
483 // Make sure pinned state is correctly loaded from session service.
484 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSessionAndTabsPinned
) {
485 CreateSessionServiceWithOneWindow(true);
487 SessionServiceFactory::GetForProfile(profile())->
488 MoveCurrentSessionToLastSession();
490 AddThreeNavigations();
492 service_
->CreateHistoricalTab(live_tab(), -1);
496 // We should get back two entries, one from the previous session and one from
497 // the tab restore service. The previous session entry should be first.
498 ASSERT_EQ(2U, service_
->entries().size());
499 // The first entry should come from the session service.
500 sessions::TabRestoreService::Entry
* entry
= service_
->entries().front();
501 ASSERT_EQ(sessions::TabRestoreService::WINDOW
, entry
->type
);
502 sessions::TabRestoreService::Window
* window
=
503 static_cast<sessions::TabRestoreService::Window
*>(entry
);
504 ASSERT_EQ(1U, window
->tabs
.size());
505 EXPECT_EQ(0, window
->selected_tab_index
);
506 EXPECT_TRUE(window
->tabs
[0].pinned
);
507 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
508 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
509 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
511 // Then the closed tab.
512 entry
= *(++service_
->entries().begin());
513 ASSERT_EQ(sessions::TabRestoreService::TAB
, entry
->type
);
514 Tab
* tab
= static_cast<Tab
*>(entry
);
515 ASSERT_FALSE(tab
->pinned
);
516 ASSERT_EQ(3U, tab
->navigations
.size());
517 EXPECT_EQ(2, tab
->current_navigation_index
);
518 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
519 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
520 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
523 // Creates kMaxEntries + 1 windows in the session service and makes sure we only
524 // get back kMaxEntries on restore.
525 TEST_F(PersistentTabRestoreServiceTest
, ManyWindowsInSessionService
) {
526 CreateSessionServiceWithOneWindow(false);
528 for (size_t i
= 0; i
< kMaxEntries
; ++i
)
529 AddWindowWithOneTabToSessionService(false);
531 SessionServiceFactory::GetForProfile(profile())->
532 MoveCurrentSessionToLastSession();
534 AddThreeNavigations();
536 service_
->CreateHistoricalTab(live_tab(), -1);
540 // We should get back kMaxEntries entries. We added more, but
541 // TabRestoreService only allows up to kMaxEntries.
542 ASSERT_EQ(kMaxEntries
, service_
->entries().size());
544 // The first entry should come from the session service.
545 sessions::TabRestoreService::Entry
* entry
= service_
->entries().front();
546 ASSERT_EQ(sessions::TabRestoreService::WINDOW
, entry
->type
);
547 sessions::TabRestoreService::Window
* window
=
548 static_cast<sessions::TabRestoreService::Window
*>(entry
);
549 ASSERT_EQ(1U, window
->tabs
.size());
550 EXPECT_EQ(0, window
->selected_tab_index
);
551 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
552 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
553 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
554 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
555 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
558 // Makes sure we restore timestamps correctly.
559 TEST_F(PersistentTabRestoreServiceTest
, TimestampSurvivesRestore
) {
560 base::Time
tab_timestamp(base::Time::FromInternalValue(123456789));
562 AddThreeNavigations();
564 // Have the service record the tab.
565 service_
->CreateHistoricalTab(live_tab(), -1);
567 // Make sure an entry was created.
568 ASSERT_EQ(1U, service_
->entries().size());
570 // Make sure the entry matches.
571 std::vector
<SerializedNavigationEntry
> old_navigations
;
573 // |entry|/|tab| doesn't survive after RecreateService().
574 sessions::TabRestoreService::Entry
* entry
= service_
->entries().front();
575 ASSERT_EQ(sessions::TabRestoreService::TAB
, entry
->type
);
576 Tab
* tab
= static_cast<Tab
*>(entry
);
577 tab
->timestamp
= tab_timestamp
;
578 old_navigations
= tab
->navigations
;
581 EXPECT_EQ(3U, old_navigations
.size());
582 for (size_t i
= 0; i
< old_navigations
.size(); ++i
) {
583 EXPECT_FALSE(old_navigations
[i
].timestamp().is_null());
586 // Set this, otherwise previous session won't be loaded.
587 profile()->set_last_session_exited_cleanly(false);
591 // One entry should be created.
592 ASSERT_EQ(1U, service_
->entries().size());
594 // And verify the entry.
595 sessions::TabRestoreService::Entry
* restored_entry
=
596 service_
->entries().front();
597 ASSERT_EQ(sessions::TabRestoreService::TAB
, restored_entry
->type
);
599 static_cast<Tab
*>(restored_entry
);
600 EXPECT_EQ(tab_timestamp
.ToInternalValue(),
601 restored_tab
->timestamp
.ToInternalValue());
602 ASSERT_EQ(old_navigations
.size(), restored_tab
->navigations
.size());
603 for (size_t i
= 0; i
< restored_tab
->navigations
.size(); ++i
) {
604 EXPECT_EQ(old_navigations
[i
].timestamp(),
605 restored_tab
->navigations
[i
].timestamp());
609 // Makes sure we restore status codes correctly.
610 TEST_F(PersistentTabRestoreServiceTest
, StatusCodesSurviveRestore
) {
611 AddThreeNavigations();
613 // Have the service record the tab.
614 service_
->CreateHistoricalTab(live_tab(), -1);
616 // Make sure an entry was created.
617 ASSERT_EQ(1U, service_
->entries().size());
619 // Make sure the entry matches.
620 std::vector
<sessions::SerializedNavigationEntry
> old_navigations
;
622 // |entry|/|tab| doesn't survive after RecreateService().
623 sessions::TabRestoreService::Entry
* entry
= service_
->entries().front();
624 ASSERT_EQ(sessions::TabRestoreService::TAB
, entry
->type
);
625 Tab
* tab
= static_cast<Tab
*>(entry
);
626 old_navigations
= tab
->navigations
;
629 EXPECT_EQ(3U, old_navigations
.size());
630 for (size_t i
= 0; i
< old_navigations
.size(); ++i
) {
631 EXPECT_EQ(200, old_navigations
[i
].http_status_code());
634 // Set this, otherwise previous session won't be loaded.
635 profile()->set_last_session_exited_cleanly(false);
639 // One entry should be created.
640 ASSERT_EQ(1U, service_
->entries().size());
642 // And verify the entry.
643 sessions::TabRestoreService::Entry
* restored_entry
=
644 service_
->entries().front();
645 ASSERT_EQ(sessions::TabRestoreService::TAB
, restored_entry
->type
);
647 static_cast<Tab
*>(restored_entry
);
648 ASSERT_EQ(old_navigations
.size(), restored_tab
->navigations
.size());
649 for (size_t i
= 0; i
< restored_tab
->navigations
.size(); ++i
) {
650 EXPECT_EQ(200, restored_tab
->navigations
[i
].http_status_code());
654 TEST_F(PersistentTabRestoreServiceTest
, PruneEntries
) {
655 service_
->ClearEntries();
656 ASSERT_TRUE(service_
->entries().empty());
658 const size_t max_entries
= kMaxEntries
;
659 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
660 SerializedNavigationEntry navigation
=
661 SerializedNavigationEntryTestHelper::CreateNavigation(
662 base::StringPrintf("http://%d", static_cast<int>(i
)),
663 base::SizeTToString(i
));
665 Tab
* tab
= new Tab();
666 tab
->navigations
.push_back(navigation
);
667 tab
->current_navigation_index
= 0;
669 mutable_entries()->push_back(tab
);
672 // Only keep kMaxEntries around.
673 EXPECT_EQ(max_entries
+ 5, service_
->entries().size());
675 EXPECT_EQ(max_entries
, service_
->entries().size());
676 // Pruning again does nothing.
678 EXPECT_EQ(max_entries
, service_
->entries().size());
680 // Prune older first.
681 const char kRecentUrl
[] = "http://recent";
682 SerializedNavigationEntry navigation
=
683 SerializedNavigationEntryTestHelper::CreateNavigation(kRecentUrl
,
685 Tab
* tab
= new Tab();
686 tab
->navigations
.push_back(navigation
);
687 tab
->current_navigation_index
= 0;
688 mutable_entries()->push_front(tab
);
689 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
691 EXPECT_EQ(max_entries
, service_
->entries().size());
692 EXPECT_EQ(GURL(kRecentUrl
),
693 static_cast<Tab
*>(service_
->entries().front())->
694 navigations
[0].virtual_url());
697 navigation
= SerializedNavigationEntryTestHelper::CreateNavigation(
698 chrome::kChromeUINewTabURL
, "New tab");
701 tab
->navigations
.push_back(navigation
);
702 tab
->current_navigation_index
= 0;
703 mutable_entries()->push_front(tab
);
705 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
707 EXPECT_EQ(max_entries
, service_
->entries().size());
708 EXPECT_EQ(GURL(kRecentUrl
),
709 static_cast<Tab
*>(service_
->entries().front())->
710 navigations
[0].virtual_url());
712 // Don't prune pinned NTPs.
715 tab
->current_navigation_index
= 0;
716 tab
->navigations
.push_back(navigation
);
717 mutable_entries()->push_front(tab
);
718 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
720 EXPECT_EQ(max_entries
, service_
->entries().size());
721 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL
),
722 static_cast<Tab
*>(service_
->entries().front())->
723 navigations
[0].virtual_url());
725 // Don't prune NTPs that have multiple navigations.
726 // (Erase the last NTP first.)
727 delete service_
->entries().front();
728 mutable_entries()->erase(mutable_entries()->begin());
730 tab
->current_navigation_index
= 1;
731 tab
->navigations
.push_back(navigation
);
732 tab
->navigations
.push_back(navigation
);
733 mutable_entries()->push_front(tab
);
734 EXPECT_EQ(max_entries
, service_
->entries().size());
736 EXPECT_EQ(max_entries
, service_
->entries().size());
737 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL
),
738 static_cast<Tab
*>(service_
->entries().front())->
739 navigations
[1].virtual_url());
742 // Regression test for crbug.com/106082
743 TEST_F(PersistentTabRestoreServiceTest
, PruneIsCalled
) {
744 CreateSessionServiceWithOneWindow(false);
746 SessionServiceFactory::GetForProfile(profile())->
747 MoveCurrentSessionToLastSession();
749 profile()->set_restored_last_session(true);
751 const size_t max_entries
= kMaxEntries
;
752 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
754 GURL(base::StringPrintf("http://%d", static_cast<int>(i
))));
755 service_
->CreateHistoricalTab(live_tab(), -1);
758 EXPECT_EQ(max_entries
, service_
->entries().size());
759 // This should not crash.
760 SynchronousLoadTabsFromLastSession();
761 EXPECT_EQ(max_entries
, service_
->entries().size());
764 // Makes sure invoking LoadTabsFromLastSession() when the max number of entries
765 // have been added results in IsLoaded() returning true and notifies observers.
766 TEST_F(PersistentTabRestoreServiceTest
, GoToLoadedWhenHaveMaxEntries
) {
767 const size_t max_entries
= kMaxEntries
;
768 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
770 GURL(base::StringPrintf("http://%d", static_cast<int>(i
))));
771 service_
->CreateHistoricalTab(live_tab(), -1);
774 EXPECT_FALSE(service_
->IsLoaded());
775 TestTabRestoreServiceObserver observer
;
776 service_
->AddObserver(&observer
);
777 EXPECT_EQ(max_entries
, service_
->entries().size());
778 SynchronousLoadTabsFromLastSession();
779 EXPECT_TRUE(observer
.got_loaded());
780 EXPECT_TRUE(service_
->IsLoaded());
781 service_
->RemoveObserver(&observer
);