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/session_service.h"
16 #include "chrome/browser/sessions/session_service_factory.h"
17 #include "chrome/browser/sessions/session_service_utils.h"
18 #include "chrome/browser/sessions/tab_restore_service_factory.h"
19 #include "chrome/browser/sessions/tab_restore_service_observer.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/serialized_navigation_entry_test_helper.h"
25 #include "components/sessions/session_types.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/navigation_controller.h"
28 #include "content/public/browser/navigation_entry.h"
29 #include "content/public/browser/notification_service.h"
30 #include "content/public/browser/notification_types.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/test/render_view_test.h"
33 #include "content/public/test/test_utils.h"
34 #include "content/public/test/web_contents_tester.h"
35 #include "testing/gtest/include/gtest/gtest.h"
37 typedef TabRestoreService::Tab Tab
;
38 typedef TabRestoreService::Window Window
;
40 using content::NavigationEntry
;
41 using content::WebContentsTester
;
42 using sessions::SerializedNavigationEntry
;
43 using sessions::SerializedNavigationEntryTestHelper
;
45 // Create subclass that overrides TimeNow so that we can control the time used
46 // for closed tabs and windows.
47 class PersistentTabRestoreTimeFactory
: public TabRestoreService::TimeFactory
{
49 PersistentTabRestoreTimeFactory() : time_(base::Time::Now()) {}
51 ~PersistentTabRestoreTimeFactory() override
{}
53 base::Time
TimeNow() override
{ return time_
; }
59 class PersistentTabRestoreServiceTest
: public ChromeRenderViewHostTestHarness
{
61 PersistentTabRestoreServiceTest()
66 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19"
67 " (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19"),
71 ~PersistentTabRestoreServiceTest() override
{}
75 kMaxEntries
= TabRestoreServiceHelper::kMaxEntries
,
79 void SetUp() override
{
80 ChromeRenderViewHostTestHarness::SetUp();
81 time_factory_
= new PersistentTabRestoreTimeFactory();
82 service_
.reset(new PersistentTabRestoreService(profile(), time_factory_
));
85 void TearDown() override
{
89 ChromeRenderViewHostTestHarness::TearDown();
92 TabRestoreService::Entries
* mutable_entries() {
93 return service_
->mutable_entries();
97 service_
->PruneEntries();
100 void AddThreeNavigations() {
101 // Navigate to three URLs.
102 NavigateAndCommit(url1_
);
103 NavigateAndCommit(url2_
);
104 NavigateAndCommit(url3_
);
107 void NavigateToIndex(int index
) {
108 // Navigate back. We have to do this song and dance as NavigationController
109 // isn't happy if you navigate immediately while going back.
110 controller().GoToIndex(index
);
111 WebContentsTester::For(web_contents())->CommitPendingNavigation();
114 void RecreateService() {
115 // Must set service to null first so that it is destroyed before the new
117 service_
->Shutdown();
118 content::RunAllBlockingPoolTasksUntilIdle();
120 service_
.reset(new PersistentTabRestoreService(profile(), time_factory_
));
121 SynchronousLoadTabsFromLastSession();
124 // Adds a window with one tab and url to the profile's session service.
125 // If |pinned| is true, the tab is marked as pinned in the session service.
126 void AddWindowWithOneTabToSessionService(bool pinned
) {
127 SessionService
* session_service
=
128 SessionServiceFactory::GetForProfile(profile());
131 session_service
->SetWindowType(window_id
,
132 Browser::TYPE_TABBED
,
133 SessionService::TYPE_NORMAL
);
134 session_service
->SetTabWindow(window_id
, tab_id
);
135 session_service
->SetTabIndexInWindow(window_id
, tab_id
, 0);
136 session_service
->SetSelectedTabInWindow(window_id
, 0);
138 session_service
->SetPinnedState(window_id
, tab_id
, true);
139 session_service
->UpdateTabNavigation(
141 SerializedNavigationEntryTestHelper::CreateNavigation(
142 url1_
.spec(), "title"));
145 // Creates a SessionService and assigns it to the Profile. The SessionService
146 // is configured with a single window with a single tab pointing at url1_ by
147 // way of AddWindowWithOneTabToSessionService. If |pinned| is true, the
148 // tab is marked as pinned in the session service.
149 void CreateSessionServiceWithOneWindow(bool pinned
) {
150 scoped_ptr
<SessionService
> session_service(new SessionService(profile()));
151 SessionServiceFactory::SetForTestProfile(profile(), session_service
.Pass());
153 AddWindowWithOneTabToSessionService(pinned
);
155 // Set this, otherwise previous session won't be loaded.
156 profile()->set_last_session_exited_cleanly(false);
159 void SynchronousLoadTabsFromLastSession() {
160 // Ensures that the load is complete before continuing.
161 service_
->LoadTabsFromLastSession();
162 content::RunAllBlockingPoolTasksUntilIdle();
168 std::string user_agent_override_
;
169 scoped_ptr
<PersistentTabRestoreService
> service_
;
170 PersistentTabRestoreTimeFactory
* time_factory_
;
175 class TestTabRestoreServiceObserver
: public TabRestoreServiceObserver
{
177 TestTabRestoreServiceObserver() : got_loaded_(false) {}
179 void clear_got_loaded() { got_loaded_
= false; }
180 bool got_loaded() const { return got_loaded_
; }
182 // TabRestoreServiceObserver:
183 void TabRestoreServiceChanged(TabRestoreService
* service
) override
{}
184 void TabRestoreServiceDestroyed(TabRestoreService
* service
) override
{}
185 void TabRestoreServiceLoaded(TabRestoreService
* service
) override
{
190 // Was TabRestoreServiceLoaded() invoked?
193 DISALLOW_COPY_AND_ASSIGN(TestTabRestoreServiceObserver
);
198 TEST_F(PersistentTabRestoreServiceTest
, Basic
) {
199 AddThreeNavigations();
201 // Have the service record the tab.
202 service_
->CreateHistoricalTab(web_contents(), -1);
204 // Make sure an entry was created.
205 ASSERT_EQ(1U, service_
->entries().size());
207 // Make sure the entry matches.
208 TabRestoreService::Entry
* entry
= service_
->entries().front();
209 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
210 Tab
* tab
= static_cast<Tab
*>(entry
);
211 EXPECT_FALSE(tab
->pinned
);
212 EXPECT_TRUE(tab
->extension_app_id
.empty());
213 ASSERT_EQ(3U, tab
->navigations
.size());
214 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
215 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
216 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
217 EXPECT_EQ("", tab
->user_agent_override
);
218 EXPECT_EQ(2, tab
->current_navigation_index
);
219 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
220 tab
->timestamp
.ToInternalValue());
224 // And check again, but set the user agent override this time.
225 web_contents()->SetUserAgentOverride(user_agent_override_
);
226 service_
->CreateHistoricalTab(web_contents(), -1);
228 // There should be two entries now.
229 ASSERT_EQ(2U, service_
->entries().size());
231 // Make sure the entry matches.
232 entry
= service_
->entries().front();
233 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
234 tab
= static_cast<Tab
*>(entry
);
235 EXPECT_FALSE(tab
->pinned
);
236 ASSERT_EQ(3U, tab
->navigations
.size());
237 EXPECT_EQ(url1_
, tab
->navigations
[0].virtual_url());
238 EXPECT_EQ(url2_
, tab
->navigations
[1].virtual_url());
239 EXPECT_EQ(url3_
, tab
->navigations
[2].virtual_url());
240 EXPECT_EQ(user_agent_override_
, tab
->user_agent_override
);
241 EXPECT_EQ(1, tab
->current_navigation_index
);
242 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
243 tab
->timestamp
.ToInternalValue());
246 // Make sure TabRestoreService doesn't create an entry for a tab with no
248 TEST_F(PersistentTabRestoreServiceTest
, DontCreateEmptyTab
) {
249 service_
->CreateHistoricalTab(web_contents(), -1);
250 EXPECT_TRUE(service_
->entries().empty());
253 // Tests restoring a single tab.
254 TEST_F(PersistentTabRestoreServiceTest
, Restore
) {
255 AddThreeNavigations();
257 // Have the service record the tab.
258 service_
->CreateHistoricalTab(web_contents(), -1);
260 // Recreate the service and have it load the tabs.
263 // One entry should be created.
264 ASSERT_EQ(1U, service_
->entries().size());
266 // And verify the entry.
267 PersistentTabRestoreService::Entry
* entry
= service_
->entries().front();
268 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
269 Tab
* tab
= static_cast<Tab
*>(entry
);
270 EXPECT_FALSE(tab
->pinned
);
271 ASSERT_EQ(3U, tab
->navigations
.size());
272 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
273 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
274 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
275 EXPECT_EQ(2, tab
->current_navigation_index
);
276 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
277 tab
->timestamp
.ToInternalValue());
280 // Tests restoring a single pinned tab.
281 TEST_F(PersistentTabRestoreServiceTest
, RestorePinnedAndApp
) {
282 AddThreeNavigations();
284 // Have the service record the tab.
285 service_
->CreateHistoricalTab(web_contents(), -1);
287 // One entry should be created.
288 ASSERT_EQ(1U, service_
->entries().size());
290 // We have to explicitly mark the tab as pinned as there is no browser for
292 TabRestoreService::Entry
* entry
= service_
->entries().front();
293 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
294 Tab
* tab
= static_cast<Tab
*>(entry
);
296 const std::string
extension_app_id("test");
297 tab
->extension_app_id
= extension_app_id
;
299 // Recreate the service and have it load the tabs.
302 // One entry should be created.
303 ASSERT_EQ(1U, service_
->entries().size());
305 // And verify the entry.
306 entry
= service_
->entries().front();
307 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
308 tab
= static_cast<Tab
*>(entry
);
309 EXPECT_TRUE(tab
->pinned
);
310 ASSERT_EQ(3U, tab
->navigations
.size());
311 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
312 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
313 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
314 EXPECT_EQ(2, tab
->current_navigation_index
);
315 EXPECT_TRUE(extension_app_id
== tab
->extension_app_id
);
318 // Make sure we persist entries to disk that have post data.
319 TEST_F(PersistentTabRestoreServiceTest
, DontPersistPostData
) {
320 AddThreeNavigations();
321 controller().GetEntryAtIndex(0)->SetHasPostData(true);
322 controller().GetEntryAtIndex(1)->SetHasPostData(true);
323 controller().GetEntryAtIndex(2)->SetHasPostData(true);
325 // Have the service record the tab.
326 service_
->CreateHistoricalTab(web_contents(), -1);
327 ASSERT_EQ(1U, service_
->entries().size());
329 // Recreate the service and have it load the tabs.
332 // One entry should be created.
333 ASSERT_EQ(1U, service_
->entries().size());
335 const TabRestoreService::Entry
* restored_entry
= service_
->entries().front();
336 ASSERT_EQ(TabRestoreService::TAB
, restored_entry
->type
);
338 const Tab
* restored_tab
=
339 static_cast<const Tab
*>(restored_entry
);
340 // There should be 3 navs.
341 ASSERT_EQ(3U, restored_tab
->navigations
.size());
342 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
343 restored_tab
->timestamp
.ToInternalValue());
346 // Make sure we don't persist entries to disk that have post data. This
347 // differs from DontPersistPostData1 in that all the navigations have post
348 // data, so that nothing should be persisted.
349 TEST_F(PersistentTabRestoreServiceTest
, DontLoadTwice
) {
350 AddThreeNavigations();
352 // Have the service record the tab.
353 service_
->CreateHistoricalTab(web_contents(), -1);
354 ASSERT_EQ(1U, service_
->entries().size());
356 // Recreate the service and have it load the tabs.
359 SynchronousLoadTabsFromLastSession();
361 // There should only be one entry.
362 ASSERT_EQ(1U, service_
->entries().size());
365 // Makes sure we load the previous session as necessary.
366 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSession
) {
367 CreateSessionServiceWithOneWindow(false);
369 SessionServiceFactory::GetForProfile(profile())->
370 MoveCurrentSessionToLastSession();
372 EXPECT_FALSE(service_
->IsLoaded());
374 TestTabRestoreServiceObserver observer
;
375 service_
->AddObserver(&observer
);
376 SynchronousLoadTabsFromLastSession();
377 EXPECT_TRUE(observer
.got_loaded());
378 service_
->RemoveObserver(&observer
);
380 // Make sure we get back one entry with one tab whose url is url1.
381 ASSERT_EQ(1U, service_
->entries().size());
382 TabRestoreService::Entry
* entry2
= service_
->entries().front();
383 ASSERT_EQ(TabRestoreService::WINDOW
, entry2
->type
);
384 TabRestoreService::Window
* window
=
385 static_cast<TabRestoreService::Window
*>(entry2
);
386 ASSERT_EQ(1U, window
->tabs
.size());
387 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
388 EXPECT_EQ(0, window
->selected_tab_index
);
389 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
390 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
391 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
392 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
395 // Makes sure we don't attempt to load previous sessions after a restore.
396 TEST_F(PersistentTabRestoreServiceTest
, DontLoadAfterRestore
) {
397 CreateSessionServiceWithOneWindow(false);
399 SessionServiceFactory::GetForProfile(profile())->
400 MoveCurrentSessionToLastSession();
402 profile()->set_restored_last_session(true);
404 SynchronousLoadTabsFromLastSession();
406 // Because we restored a session PersistentTabRestoreService shouldn't load
408 ASSERT_EQ(0U, service_
->entries().size());
411 // Makes sure we don't attempt to load previous sessions after a clean exit.
412 TEST_F(PersistentTabRestoreServiceTest
, DontLoadAfterCleanExit
) {
413 CreateSessionServiceWithOneWindow(false);
415 SessionServiceFactory::GetForProfile(profile())->
416 MoveCurrentSessionToLastSession();
418 profile()->set_last_session_exited_cleanly(true);
420 SynchronousLoadTabsFromLastSession();
422 ASSERT_EQ(0U, service_
->entries().size());
425 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSessionAndTabs
) {
426 CreateSessionServiceWithOneWindow(false);
428 SessionServiceFactory::GetForProfile(profile())->
429 MoveCurrentSessionToLastSession();
431 AddThreeNavigations();
433 service_
->CreateHistoricalTab(web_contents(), -1);
437 // We should get back two entries, one from the previous session and one from
438 // the tab restore service. The previous session entry should be first.
439 ASSERT_EQ(2U, service_
->entries().size());
440 // The first entry should come from the session service.
441 TabRestoreService::Entry
* entry
= service_
->entries().front();
442 ASSERT_EQ(TabRestoreService::WINDOW
, entry
->type
);
443 TabRestoreService::Window
* window
=
444 static_cast<TabRestoreService::Window
*>(entry
);
445 ASSERT_EQ(1U, window
->tabs
.size());
446 EXPECT_EQ(0, window
->selected_tab_index
);
447 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
448 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
449 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
450 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
451 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
453 // Then the closed tab.
454 entry
= *(++service_
->entries().begin());
455 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
456 Tab
* tab
= static_cast<Tab
*>(entry
);
457 ASSERT_FALSE(tab
->pinned
);
458 ASSERT_EQ(3U, tab
->navigations
.size());
459 EXPECT_EQ(2, tab
->current_navigation_index
);
460 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
461 tab
->timestamp
.ToInternalValue());
462 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
463 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
464 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
467 // Make sure pinned state is correctly loaded from session service.
468 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSessionAndTabsPinned
) {
469 CreateSessionServiceWithOneWindow(true);
471 SessionServiceFactory::GetForProfile(profile())->
472 MoveCurrentSessionToLastSession();
474 AddThreeNavigations();
476 service_
->CreateHistoricalTab(web_contents(), -1);
480 // We should get back two entries, one from the previous session and one from
481 // the tab restore service. The previous session entry should be first.
482 ASSERT_EQ(2U, service_
->entries().size());
483 // The first entry should come from the session service.
484 TabRestoreService::Entry
* entry
= service_
->entries().front();
485 ASSERT_EQ(TabRestoreService::WINDOW
, entry
->type
);
486 TabRestoreService::Window
* window
=
487 static_cast<TabRestoreService::Window
*>(entry
);
488 ASSERT_EQ(1U, window
->tabs
.size());
489 EXPECT_EQ(0, window
->selected_tab_index
);
490 EXPECT_TRUE(window
->tabs
[0].pinned
);
491 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
492 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
493 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
495 // Then the closed tab.
496 entry
= *(++service_
->entries().begin());
497 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
498 Tab
* tab
= static_cast<Tab
*>(entry
);
499 ASSERT_FALSE(tab
->pinned
);
500 ASSERT_EQ(3U, tab
->navigations
.size());
501 EXPECT_EQ(2, tab
->current_navigation_index
);
502 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
503 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
504 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
507 // Creates kMaxEntries + 1 windows in the session service and makes sure we only
508 // get back kMaxEntries on restore.
509 TEST_F(PersistentTabRestoreServiceTest
, ManyWindowsInSessionService
) {
510 CreateSessionServiceWithOneWindow(false);
512 for (size_t i
= 0; i
< kMaxEntries
; ++i
)
513 AddWindowWithOneTabToSessionService(false);
515 SessionServiceFactory::GetForProfile(profile())->
516 MoveCurrentSessionToLastSession();
518 AddThreeNavigations();
520 service_
->CreateHistoricalTab(web_contents(), -1);
524 // We should get back kMaxEntries entries. We added more, but
525 // TabRestoreService only allows up to kMaxEntries.
526 ASSERT_EQ(kMaxEntries
, service_
->entries().size());
528 // The first entry should come from the session service.
529 TabRestoreService::Entry
* entry
= service_
->entries().front();
530 ASSERT_EQ(TabRestoreService::WINDOW
, entry
->type
);
531 TabRestoreService::Window
* window
=
532 static_cast<TabRestoreService::Window
*>(entry
);
533 ASSERT_EQ(1U, window
->tabs
.size());
534 EXPECT_EQ(0, window
->selected_tab_index
);
535 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
536 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
537 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
538 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
539 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
542 // Makes sure we restore timestamps correctly.
543 TEST_F(PersistentTabRestoreServiceTest
, TimestampSurvivesRestore
) {
544 base::Time
tab_timestamp(base::Time::FromInternalValue(123456789));
546 AddThreeNavigations();
548 // Have the service record the tab.
549 service_
->CreateHistoricalTab(web_contents(), -1);
551 // Make sure an entry was created.
552 ASSERT_EQ(1U, service_
->entries().size());
554 // Make sure the entry matches.
555 std::vector
<SerializedNavigationEntry
> old_navigations
;
557 // |entry|/|tab| doesn't survive after RecreateService().
558 TabRestoreService::Entry
* entry
= service_
->entries().front();
559 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
560 Tab
* tab
= static_cast<Tab
*>(entry
);
561 tab
->timestamp
= tab_timestamp
;
562 old_navigations
= tab
->navigations
;
565 EXPECT_EQ(3U, old_navigations
.size());
566 for (size_t i
= 0; i
< old_navigations
.size(); ++i
) {
567 EXPECT_FALSE(old_navigations
[i
].timestamp().is_null());
570 // Set this, otherwise previous session won't be loaded.
571 profile()->set_last_session_exited_cleanly(false);
575 // One entry should be created.
576 ASSERT_EQ(1U, service_
->entries().size());
578 // And verify the entry.
579 TabRestoreService::Entry
* restored_entry
= service_
->entries().front();
580 ASSERT_EQ(TabRestoreService::TAB
, restored_entry
->type
);
582 static_cast<Tab
*>(restored_entry
);
583 EXPECT_EQ(tab_timestamp
.ToInternalValue(),
584 restored_tab
->timestamp
.ToInternalValue());
585 ASSERT_EQ(old_navigations
.size(), restored_tab
->navigations
.size());
586 for (size_t i
= 0; i
< restored_tab
->navigations
.size(); ++i
) {
587 EXPECT_EQ(old_navigations
[i
].timestamp(),
588 restored_tab
->navigations
[i
].timestamp());
592 // Makes sure we restore status codes correctly.
593 TEST_F(PersistentTabRestoreServiceTest
, StatusCodesSurviveRestore
) {
594 AddThreeNavigations();
596 // Have the service record the tab.
597 service_
->CreateHistoricalTab(web_contents(), -1);
599 // Make sure an entry was created.
600 ASSERT_EQ(1U, service_
->entries().size());
602 // Make sure the entry matches.
603 std::vector
<sessions::SerializedNavigationEntry
> old_navigations
;
605 // |entry|/|tab| doesn't survive after RecreateService().
606 TabRestoreService::Entry
* entry
= service_
->entries().front();
607 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
608 Tab
* tab
= static_cast<Tab
*>(entry
);
609 old_navigations
= tab
->navigations
;
612 EXPECT_EQ(3U, old_navigations
.size());
613 for (size_t i
= 0; i
< old_navigations
.size(); ++i
) {
614 EXPECT_EQ(200, old_navigations
[i
].http_status_code());
617 // Set this, otherwise previous session won't be loaded.
618 profile()->set_last_session_exited_cleanly(false);
622 // One entry should be created.
623 ASSERT_EQ(1U, service_
->entries().size());
625 // And verify the entry.
626 TabRestoreService::Entry
* restored_entry
= service_
->entries().front();
627 ASSERT_EQ(TabRestoreService::TAB
, restored_entry
->type
);
629 static_cast<Tab
*>(restored_entry
);
630 ASSERT_EQ(old_navigations
.size(), restored_tab
->navigations
.size());
631 for (size_t i
= 0; i
< restored_tab
->navigations
.size(); ++i
) {
632 EXPECT_EQ(200, restored_tab
->navigations
[i
].http_status_code());
636 TEST_F(PersistentTabRestoreServiceTest
, PruneEntries
) {
637 service_
->ClearEntries();
638 ASSERT_TRUE(service_
->entries().empty());
640 const size_t max_entries
= kMaxEntries
;
641 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
642 SerializedNavigationEntry navigation
=
643 SerializedNavigationEntryTestHelper::CreateNavigation(
644 base::StringPrintf("http://%d", static_cast<int>(i
)),
645 base::SizeTToString(i
));
647 Tab
* tab
= new Tab();
648 tab
->navigations
.push_back(navigation
);
649 tab
->current_navigation_index
= 0;
651 mutable_entries()->push_back(tab
);
654 // Only keep kMaxEntries around.
655 EXPECT_EQ(max_entries
+ 5, service_
->entries().size());
657 EXPECT_EQ(max_entries
, service_
->entries().size());
658 // Pruning again does nothing.
660 EXPECT_EQ(max_entries
, service_
->entries().size());
662 // Prune older first.
663 const char kRecentUrl
[] = "http://recent";
664 SerializedNavigationEntry navigation
=
665 SerializedNavigationEntryTestHelper::CreateNavigation(kRecentUrl
,
667 Tab
* tab
= new Tab();
668 tab
->navigations
.push_back(navigation
);
669 tab
->current_navigation_index
= 0;
670 mutable_entries()->push_front(tab
);
671 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
673 EXPECT_EQ(max_entries
, service_
->entries().size());
674 EXPECT_EQ(GURL(kRecentUrl
),
675 static_cast<Tab
*>(service_
->entries().front())->
676 navigations
[0].virtual_url());
679 navigation
= SerializedNavigationEntryTestHelper::CreateNavigation(
680 chrome::kChromeUINewTabURL
, "New tab");
683 tab
->navigations
.push_back(navigation
);
684 tab
->current_navigation_index
= 0;
685 mutable_entries()->push_front(tab
);
687 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
689 EXPECT_EQ(max_entries
, service_
->entries().size());
690 EXPECT_EQ(GURL(kRecentUrl
),
691 static_cast<Tab
*>(service_
->entries().front())->
692 navigations
[0].virtual_url());
694 // Don't prune pinned NTPs.
697 tab
->current_navigation_index
= 0;
698 tab
->navigations
.push_back(navigation
);
699 mutable_entries()->push_front(tab
);
700 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
702 EXPECT_EQ(max_entries
, service_
->entries().size());
703 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL
),
704 static_cast<Tab
*>(service_
->entries().front())->
705 navigations
[0].virtual_url());
707 // Don't prune NTPs that have multiple navigations.
708 // (Erase the last NTP first.)
709 delete service_
->entries().front();
710 mutable_entries()->erase(mutable_entries()->begin());
712 tab
->current_navigation_index
= 1;
713 tab
->navigations
.push_back(navigation
);
714 tab
->navigations
.push_back(navigation
);
715 mutable_entries()->push_front(tab
);
716 EXPECT_EQ(max_entries
, service_
->entries().size());
718 EXPECT_EQ(max_entries
, service_
->entries().size());
719 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL
),
720 static_cast<Tab
*>(service_
->entries().front())->
721 navigations
[1].virtual_url());
724 // Regression test for crbug.com/106082
725 TEST_F(PersistentTabRestoreServiceTest
, PruneIsCalled
) {
726 CreateSessionServiceWithOneWindow(false);
728 SessionServiceFactory::GetForProfile(profile())->
729 MoveCurrentSessionToLastSession();
731 profile()->set_restored_last_session(true);
733 const size_t max_entries
= kMaxEntries
;
734 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
736 GURL(base::StringPrintf("http://%d", static_cast<int>(i
))));
737 service_
->CreateHistoricalTab(web_contents(), -1);
740 EXPECT_EQ(max_entries
, service_
->entries().size());
741 // This should not crash.
742 SynchronousLoadTabsFromLastSession();
743 EXPECT_EQ(max_entries
, service_
->entries().size());
746 // Makes sure invoking LoadTabsFromLastSession() when the max number of entries
747 // have been added results in IsLoaded() returning true and notifies observers.
748 TEST_F(PersistentTabRestoreServiceTest
, GoToLoadedWhenHaveMaxEntries
) {
749 const size_t max_entries
= kMaxEntries
;
750 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
752 GURL(base::StringPrintf("http://%d", static_cast<int>(i
))));
753 service_
->CreateHistoricalTab(web_contents(), -1);
756 EXPECT_FALSE(service_
->IsLoaded());
757 TestTabRestoreServiceObserver observer
;
758 service_
->AddObserver(&observer
);
759 EXPECT_EQ(max_entries
, service_
->entries().size());
760 SynchronousLoadTabsFromLastSession();
761 EXPECT_TRUE(observer
.got_loaded());
762 EXPECT_TRUE(service_
->IsLoaded());
763 service_
->RemoveObserver(&observer
);