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"
7 #include "base/compiler_specific.h"
8 #include "base/run_loop.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/threading/sequenced_worker_pool.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/sessions/session_service.h"
14 #include "chrome/browser/sessions/session_service_factory.h"
15 #include "chrome/browser/sessions/session_types.h"
16 #include "chrome/browser/sessions/tab_restore_service_factory.h"
17 #include "chrome/browser/sessions/tab_restore_service_observer.h"
18 #include "chrome/common/url_constants.h"
19 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
20 #include "chrome/test/base/chrome_render_view_test.h"
21 #include "chrome/test/base/testing_profile.h"
22 #include "components/sessions/serialized_navigation_entry_test_helper.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/navigation_controller.h"
25 #include "content/public/browser/navigation_entry.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/notification_types.h"
28 #include "content/public/browser/web_contents.h"
29 #include "content/public/test/render_view_test.h"
30 #include "content/public/test/web_contents_tester.h"
31 #include "testing/gtest/include/gtest/gtest.h"
33 typedef TabRestoreService::Tab Tab
;
34 typedef TabRestoreService::Window Window
;
36 using content::NavigationEntry
;
37 using content::WebContentsTester
;
38 using sessions::SerializedNavigationEntry
;
39 using sessions::SerializedNavigationEntryTestHelper
;
41 // Create subclass that overrides TimeNow so that we can control the time used
42 // for closed tabs and windows.
43 class PersistentTabRestoreTimeFactory
: public TabRestoreService::TimeFactory
{
45 PersistentTabRestoreTimeFactory() : time_(base::Time::Now()) {}
47 virtual ~PersistentTabRestoreTimeFactory() {}
49 virtual base::Time
TimeNow() OVERRIDE
{
57 class PersistentTabRestoreServiceTest
: public ChromeRenderViewHostTestHarness
{
59 PersistentTabRestoreServiceTest()
64 "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19"
65 " (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19"),
69 virtual ~PersistentTabRestoreServiceTest() {
74 kMaxEntries
= TabRestoreServiceHelper::kMaxEntries
,
78 virtual void SetUp() OVERRIDE
{
79 ChromeRenderViewHostTestHarness::SetUp();
80 time_factory_
= new PersistentTabRestoreTimeFactory();
81 service_
.reset(new PersistentTabRestoreService(profile(), time_factory_
));
84 virtual 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::BrowserThread::GetBlockingPool()->FlushForTesting();
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(
131 window_id
, Browser::TYPE_TABBED
, SessionService::TYPE_NORMAL
);
132 session_service
->SetTabWindow(window_id
, tab_id
);
133 session_service
->SetTabIndexInWindow(window_id
, tab_id
, 0);
134 session_service
->SetSelectedTabInWindow(window_id
, 0);
136 session_service
->SetPinnedState(window_id
, tab_id
, true);
137 session_service
->UpdateTabNavigation(
139 SerializedNavigationEntryTestHelper::CreateNavigation(
140 url1_
.spec(), "title"));
143 // Creates a SessionService and assigns it to the Profile. The SessionService
144 // is configured with a single window with a single tab pointing at url1_ by
145 // way of AddWindowWithOneTabToSessionService. If |pinned| is true, the
146 // tab is marked as pinned in the session service.
147 void CreateSessionServiceWithOneWindow(bool pinned
) {
148 // The profile takes ownership of this.
149 SessionService
* session_service
= new SessionService(profile());
150 SessionServiceFactory::SetForTestProfile(profile(), session_service
);
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::BrowserThread::GetBlockingPool()->FlushForTesting();
162 base::RunLoop().RunUntilIdle();
163 content::BrowserThread::GetBlockingPool()->FlushForTesting();
169 std::string user_agent_override_
;
170 scoped_ptr
<PersistentTabRestoreService
> service_
;
171 PersistentTabRestoreTimeFactory
* time_factory_
;
176 class TestTabRestoreServiceObserver
: public TabRestoreServiceObserver
{
178 TestTabRestoreServiceObserver() : got_loaded_(false) {}
180 void clear_got_loaded() { got_loaded_
= false; }
181 bool got_loaded() const { return got_loaded_
; }
183 // TabRestoreServiceObserver:
184 virtual void TabRestoreServiceChanged(TabRestoreService
* service
) OVERRIDE
{
186 virtual void TabRestoreServiceDestroyed(TabRestoreService
* service
) OVERRIDE
{
188 virtual void TabRestoreServiceLoaded(TabRestoreService
* service
) OVERRIDE
{
193 // Was TabRestoreServiceLoaded() invoked?
196 DISALLOW_COPY_AND_ASSIGN(TestTabRestoreServiceObserver
);
201 TEST_F(PersistentTabRestoreServiceTest
, Basic
) {
202 AddThreeNavigations();
204 // Have the service record the tab.
205 service_
->CreateHistoricalTab(web_contents(), -1);
207 // Make sure an entry was created.
208 ASSERT_EQ(1U, service_
->entries().size());
210 // Make sure the entry matches.
211 TabRestoreService::Entry
* entry
= service_
->entries().front();
212 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
213 Tab
* tab
= static_cast<Tab
*>(entry
);
214 EXPECT_FALSE(tab
->pinned
);
215 EXPECT_TRUE(tab
->extension_app_id
.empty());
216 ASSERT_EQ(3U, tab
->navigations
.size());
217 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
218 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
219 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
220 EXPECT_EQ("", tab
->user_agent_override
);
221 EXPECT_EQ(2, tab
->current_navigation_index
);
222 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
223 tab
->timestamp
.ToInternalValue());
227 // And check again, but set the user agent override this time.
228 web_contents()->SetUserAgentOverride(user_agent_override_
);
229 service_
->CreateHistoricalTab(web_contents(), -1);
231 // There should be two entries now.
232 ASSERT_EQ(2U, service_
->entries().size());
234 // Make sure the entry matches.
235 entry
= service_
->entries().front();
236 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
237 tab
= static_cast<Tab
*>(entry
);
238 EXPECT_FALSE(tab
->pinned
);
239 ASSERT_EQ(3U, tab
->navigations
.size());
240 EXPECT_EQ(url1_
, tab
->navigations
[0].virtual_url());
241 EXPECT_EQ(url2_
, tab
->navigations
[1].virtual_url());
242 EXPECT_EQ(url3_
, tab
->navigations
[2].virtual_url());
243 EXPECT_EQ(user_agent_override_
, tab
->user_agent_override
);
244 EXPECT_EQ(1, tab
->current_navigation_index
);
245 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
246 tab
->timestamp
.ToInternalValue());
249 // Make sure TabRestoreService doesn't create an entry for a tab with no
251 TEST_F(PersistentTabRestoreServiceTest
, DontCreateEmptyTab
) {
252 service_
->CreateHistoricalTab(web_contents(), -1);
253 EXPECT_TRUE(service_
->entries().empty());
256 // Tests restoring a single tab.
257 TEST_F(PersistentTabRestoreServiceTest
, Restore
) {
258 AddThreeNavigations();
260 // Have the service record the tab.
261 service_
->CreateHistoricalTab(web_contents(), -1);
263 // Recreate the service and have it load the tabs.
266 // One entry should be created.
267 ASSERT_EQ(1U, service_
->entries().size());
269 // And verify the entry.
270 PersistentTabRestoreService::Entry
* entry
= service_
->entries().front();
271 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
272 Tab
* tab
= static_cast<Tab
*>(entry
);
273 EXPECT_FALSE(tab
->pinned
);
274 ASSERT_EQ(3U, tab
->navigations
.size());
275 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
276 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
277 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
278 EXPECT_EQ(2, tab
->current_navigation_index
);
279 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
280 tab
->timestamp
.ToInternalValue());
283 // Tests restoring a single pinned tab.
284 TEST_F(PersistentTabRestoreServiceTest
, RestorePinnedAndApp
) {
285 AddThreeNavigations();
287 // Have the service record the tab.
288 service_
->CreateHistoricalTab(web_contents(), -1);
290 // One entry should be created.
291 ASSERT_EQ(1U, service_
->entries().size());
293 // We have to explicitly mark the tab as pinned as there is no browser for
295 TabRestoreService::Entry
* entry
= service_
->entries().front();
296 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
297 Tab
* tab
= static_cast<Tab
*>(entry
);
299 const std::string
extension_app_id("test");
300 tab
->extension_app_id
= extension_app_id
;
302 // Recreate the service and have it load the tabs.
305 // One entry should be created.
306 ASSERT_EQ(1U, service_
->entries().size());
308 // And verify the entry.
309 entry
= service_
->entries().front();
310 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
311 tab
= static_cast<Tab
*>(entry
);
312 EXPECT_TRUE(tab
->pinned
);
313 ASSERT_EQ(3U, tab
->navigations
.size());
314 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
315 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
316 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
317 EXPECT_EQ(2, tab
->current_navigation_index
);
318 EXPECT_TRUE(extension_app_id
== tab
->extension_app_id
);
321 // Make sure we persist entries to disk that have post data.
322 TEST_F(PersistentTabRestoreServiceTest
, DontPersistPostData
) {
323 AddThreeNavigations();
324 controller().GetEntryAtIndex(0)->SetHasPostData(true);
325 controller().GetEntryAtIndex(1)->SetHasPostData(true);
326 controller().GetEntryAtIndex(2)->SetHasPostData(true);
328 // Have the service record the tab.
329 service_
->CreateHistoricalTab(web_contents(), -1);
330 ASSERT_EQ(1U, service_
->entries().size());
332 // Recreate the service and have it load the tabs.
335 // One entry should be created.
336 ASSERT_EQ(1U, service_
->entries().size());
338 const TabRestoreService::Entry
* restored_entry
= service_
->entries().front();
339 ASSERT_EQ(TabRestoreService::TAB
, restored_entry
->type
);
341 const Tab
* restored_tab
=
342 static_cast<const Tab
*>(restored_entry
);
343 // There should be 3 navs.
344 ASSERT_EQ(3U, restored_tab
->navigations
.size());
345 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
346 restored_tab
->timestamp
.ToInternalValue());
349 // Make sure we don't persist entries to disk that have post data. This
350 // differs from DontPersistPostData1 in that all the navigations have post
351 // data, so that nothing should be persisted.
352 TEST_F(PersistentTabRestoreServiceTest
, DontLoadTwice
) {
353 AddThreeNavigations();
355 // Have the service record the tab.
356 service_
->CreateHistoricalTab(web_contents(), -1);
357 ASSERT_EQ(1U, service_
->entries().size());
359 // Recreate the service and have it load the tabs.
362 SynchronousLoadTabsFromLastSession();
364 // There should only be one entry.
365 ASSERT_EQ(1U, service_
->entries().size());
368 // Makes sure we load the previous session as necessary.
369 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSession
) {
370 CreateSessionServiceWithOneWindow(false);
372 SessionServiceFactory::GetForProfile(profile())->
373 MoveCurrentSessionToLastSession();
375 EXPECT_FALSE(service_
->IsLoaded());
377 TestTabRestoreServiceObserver observer
;
378 service_
->AddObserver(&observer
);
379 SynchronousLoadTabsFromLastSession();
380 EXPECT_TRUE(observer
.got_loaded());
381 service_
->RemoveObserver(&observer
);
383 // Make sure we get back one entry with one tab whose url is url1.
384 ASSERT_EQ(1U, service_
->entries().size());
385 TabRestoreService::Entry
* entry2
= service_
->entries().front();
386 ASSERT_EQ(TabRestoreService::WINDOW
, entry2
->type
);
387 TabRestoreService::Window
* window
=
388 static_cast<TabRestoreService::Window
*>(entry2
);
389 ASSERT_EQ(1U, window
->tabs
.size());
390 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
391 EXPECT_EQ(0, window
->selected_tab_index
);
392 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
393 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
394 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
395 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
398 // Makes sure we don't attempt to load previous sessions after a restore.
399 TEST_F(PersistentTabRestoreServiceTest
, DontLoadAfterRestore
) {
400 CreateSessionServiceWithOneWindow(false);
402 SessionServiceFactory::GetForProfile(profile())->
403 MoveCurrentSessionToLastSession();
405 profile()->set_restored_last_session(true);
407 SynchronousLoadTabsFromLastSession();
409 // Because we restored a session PersistentTabRestoreService shouldn't load
411 ASSERT_EQ(0U, service_
->entries().size());
414 // Makes sure we don't attempt to load previous sessions after a clean exit.
415 TEST_F(PersistentTabRestoreServiceTest
, DontLoadAfterCleanExit
) {
416 CreateSessionServiceWithOneWindow(false);
418 SessionServiceFactory::GetForProfile(profile())->
419 MoveCurrentSessionToLastSession();
421 profile()->set_last_session_exited_cleanly(true);
423 SynchronousLoadTabsFromLastSession();
425 ASSERT_EQ(0U, service_
->entries().size());
428 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSessionAndTabs
) {
429 CreateSessionServiceWithOneWindow(false);
431 SessionServiceFactory::GetForProfile(profile())->
432 MoveCurrentSessionToLastSession();
434 AddThreeNavigations();
436 service_
->CreateHistoricalTab(web_contents(), -1);
440 // We should get back two entries, one from the previous session and one from
441 // the tab restore service. The previous session entry should be first.
442 ASSERT_EQ(2U, service_
->entries().size());
443 // The first entry should come from the session service.
444 TabRestoreService::Entry
* entry
= service_
->entries().front();
445 ASSERT_EQ(TabRestoreService::WINDOW
, entry
->type
);
446 TabRestoreService::Window
* window
=
447 static_cast<TabRestoreService::Window
*>(entry
);
448 ASSERT_EQ(1U, window
->tabs
.size());
449 EXPECT_EQ(0, window
->selected_tab_index
);
450 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
451 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
452 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
453 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
454 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
456 // Then the closed tab.
457 entry
= *(++service_
->entries().begin());
458 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
459 Tab
* tab
= static_cast<Tab
*>(entry
);
460 ASSERT_FALSE(tab
->pinned
);
461 ASSERT_EQ(3U, tab
->navigations
.size());
462 EXPECT_EQ(2, tab
->current_navigation_index
);
463 EXPECT_EQ(time_factory_
->TimeNow().ToInternalValue(),
464 tab
->timestamp
.ToInternalValue());
465 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
466 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
467 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
470 // Make sure pinned state is correctly loaded from session service.
471 TEST_F(PersistentTabRestoreServiceTest
, LoadPreviousSessionAndTabsPinned
) {
472 CreateSessionServiceWithOneWindow(true);
474 SessionServiceFactory::GetForProfile(profile())->
475 MoveCurrentSessionToLastSession();
477 AddThreeNavigations();
479 service_
->CreateHistoricalTab(web_contents(), -1);
483 // We should get back two entries, one from the previous session and one from
484 // the tab restore service. The previous session entry should be first.
485 ASSERT_EQ(2U, service_
->entries().size());
486 // The first entry should come from the session service.
487 TabRestoreService::Entry
* entry
= service_
->entries().front();
488 ASSERT_EQ(TabRestoreService::WINDOW
, entry
->type
);
489 TabRestoreService::Window
* window
=
490 static_cast<TabRestoreService::Window
*>(entry
);
491 ASSERT_EQ(1U, window
->tabs
.size());
492 EXPECT_EQ(0, window
->selected_tab_index
);
493 EXPECT_TRUE(window
->tabs
[0].pinned
);
494 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
495 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
496 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
498 // Then the closed tab.
499 entry
= *(++service_
->entries().begin());
500 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
501 Tab
* tab
= static_cast<Tab
*>(entry
);
502 ASSERT_FALSE(tab
->pinned
);
503 ASSERT_EQ(3U, tab
->navigations
.size());
504 EXPECT_EQ(2, tab
->current_navigation_index
);
505 EXPECT_TRUE(url1_
== tab
->navigations
[0].virtual_url());
506 EXPECT_TRUE(url2_
== tab
->navigations
[1].virtual_url());
507 EXPECT_TRUE(url3_
== tab
->navigations
[2].virtual_url());
510 // Creates kMaxEntries + 1 windows in the session service and makes sure we only
511 // get back kMaxEntries on restore.
512 TEST_F(PersistentTabRestoreServiceTest
, ManyWindowsInSessionService
) {
513 CreateSessionServiceWithOneWindow(false);
515 for (size_t i
= 0; i
< kMaxEntries
; ++i
)
516 AddWindowWithOneTabToSessionService(false);
518 SessionServiceFactory::GetForProfile(profile())->
519 MoveCurrentSessionToLastSession();
521 AddThreeNavigations();
523 service_
->CreateHistoricalTab(web_contents(), -1);
527 // We should get back kMaxEntries entries. We added more, but
528 // TabRestoreService only allows up to kMaxEntries.
529 ASSERT_EQ(kMaxEntries
, service_
->entries().size());
531 // The first entry should come from the session service.
532 TabRestoreService::Entry
* entry
= service_
->entries().front();
533 ASSERT_EQ(TabRestoreService::WINDOW
, entry
->type
);
534 TabRestoreService::Window
* window
=
535 static_cast<TabRestoreService::Window
*>(entry
);
536 ASSERT_EQ(1U, window
->tabs
.size());
537 EXPECT_EQ(0, window
->selected_tab_index
);
538 EXPECT_EQ(0, window
->timestamp
.ToInternalValue());
539 ASSERT_EQ(1U, window
->tabs
[0].navigations
.size());
540 EXPECT_EQ(0, window
->tabs
[0].current_navigation_index
);
541 EXPECT_EQ(0, window
->tabs
[0].timestamp
.ToInternalValue());
542 EXPECT_TRUE(url1_
== window
->tabs
[0].navigations
[0].virtual_url());
545 // Makes sure we restore timestamps correctly.
546 TEST_F(PersistentTabRestoreServiceTest
, TimestampSurvivesRestore
) {
547 base::Time
tab_timestamp(base::Time::FromInternalValue(123456789));
549 AddThreeNavigations();
551 // Have the service record the tab.
552 service_
->CreateHistoricalTab(web_contents(), -1);
554 // Make sure an entry was created.
555 ASSERT_EQ(1U, service_
->entries().size());
557 // Make sure the entry matches.
558 std::vector
<SerializedNavigationEntry
> old_navigations
;
560 // |entry|/|tab| doesn't survive after RecreateService().
561 TabRestoreService::Entry
* entry
= service_
->entries().front();
562 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
563 Tab
* tab
= static_cast<Tab
*>(entry
);
564 tab
->timestamp
= tab_timestamp
;
565 old_navigations
= tab
->navigations
;
568 EXPECT_EQ(3U, old_navigations
.size());
569 for (size_t i
= 0; i
< old_navigations
.size(); ++i
) {
570 EXPECT_FALSE(old_navigations
[i
].timestamp().is_null());
573 // Set this, otherwise previous session won't be loaded.
574 profile()->set_last_session_exited_cleanly(false);
578 // One entry should be created.
579 ASSERT_EQ(1U, service_
->entries().size());
581 // And verify the entry.
582 TabRestoreService::Entry
* restored_entry
= service_
->entries().front();
583 ASSERT_EQ(TabRestoreService::TAB
, restored_entry
->type
);
585 static_cast<Tab
*>(restored_entry
);
586 EXPECT_EQ(tab_timestamp
.ToInternalValue(),
587 restored_tab
->timestamp
.ToInternalValue());
588 ASSERT_EQ(old_navigations
.size(), restored_tab
->navigations
.size());
589 for (size_t i
= 0; i
< restored_tab
->navigations
.size(); ++i
) {
590 EXPECT_EQ(old_navigations
[i
].timestamp(),
591 restored_tab
->navigations
[i
].timestamp());
595 // Makes sure we restore status codes correctly.
596 TEST_F(PersistentTabRestoreServiceTest
, StatusCodesSurviveRestore
) {
597 AddThreeNavigations();
599 // Have the service record the tab.
600 service_
->CreateHistoricalTab(web_contents(), -1);
602 // Make sure an entry was created.
603 ASSERT_EQ(1U, service_
->entries().size());
605 // Make sure the entry matches.
606 std::vector
<sessions::SerializedNavigationEntry
> old_navigations
;
608 // |entry|/|tab| doesn't survive after RecreateService().
609 TabRestoreService::Entry
* entry
= service_
->entries().front();
610 ASSERT_EQ(TabRestoreService::TAB
, entry
->type
);
611 Tab
* tab
= static_cast<Tab
*>(entry
);
612 old_navigations
= tab
->navigations
;
615 EXPECT_EQ(3U, old_navigations
.size());
616 for (size_t i
= 0; i
< old_navigations
.size(); ++i
) {
617 EXPECT_EQ(200, old_navigations
[i
].http_status_code());
620 // Set this, otherwise previous session won't be loaded.
621 profile()->set_last_session_exited_cleanly(false);
625 // One entry should be created.
626 ASSERT_EQ(1U, service_
->entries().size());
628 // And verify the entry.
629 TabRestoreService::Entry
* restored_entry
= service_
->entries().front();
630 ASSERT_EQ(TabRestoreService::TAB
, restored_entry
->type
);
632 static_cast<Tab
*>(restored_entry
);
633 ASSERT_EQ(old_navigations
.size(), restored_tab
->navigations
.size());
634 for (size_t i
= 0; i
< restored_tab
->navigations
.size(); ++i
) {
635 EXPECT_EQ(200, restored_tab
->navigations
[i
].http_status_code());
639 TEST_F(PersistentTabRestoreServiceTest
, PruneEntries
) {
640 service_
->ClearEntries();
641 ASSERT_TRUE(service_
->entries().empty());
643 const size_t max_entries
= kMaxEntries
;
644 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
645 SerializedNavigationEntry navigation
=
646 SerializedNavigationEntryTestHelper::CreateNavigation(
647 base::StringPrintf("http://%d", static_cast<int>(i
)),
648 base::StringPrintf("%d", static_cast<int>(i
)));
650 Tab
* tab
= new Tab();
651 tab
->navigations
.push_back(navigation
);
652 tab
->current_navigation_index
= 0;
654 mutable_entries()->push_back(tab
);
657 // Only keep kMaxEntries around.
658 EXPECT_EQ(max_entries
+ 5, service_
->entries().size());
660 EXPECT_EQ(max_entries
, service_
->entries().size());
661 // Pruning again does nothing.
663 EXPECT_EQ(max_entries
, service_
->entries().size());
665 // Prune older first.
666 const char kRecentUrl
[] = "http://recent";
667 SerializedNavigationEntry navigation
=
668 SerializedNavigationEntryTestHelper::CreateNavigation(kRecentUrl
,
670 Tab
* tab
= new Tab();
671 tab
->navigations
.push_back(navigation
);
672 tab
->current_navigation_index
= 0;
673 mutable_entries()->push_front(tab
);
674 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
676 EXPECT_EQ(max_entries
, service_
->entries().size());
677 EXPECT_EQ(GURL(kRecentUrl
),
678 static_cast<Tab
*>(service_
->entries().front())->
679 navigations
[0].virtual_url());
682 navigation
= SerializedNavigationEntryTestHelper::CreateNavigation(
683 chrome::kChromeUINewTabURL
, "New tab");
686 tab
->navigations
.push_back(navigation
);
687 tab
->current_navigation_index
= 0;
688 mutable_entries()->push_front(tab
);
690 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
692 EXPECT_EQ(max_entries
, service_
->entries().size());
693 EXPECT_EQ(GURL(kRecentUrl
),
694 static_cast<Tab
*>(service_
->entries().front())->
695 navigations
[0].virtual_url());
697 // Don't prune pinned NTPs.
700 tab
->current_navigation_index
= 0;
701 tab
->navigations
.push_back(navigation
);
702 mutable_entries()->push_front(tab
);
703 EXPECT_EQ(max_entries
+ 1, service_
->entries().size());
705 EXPECT_EQ(max_entries
, service_
->entries().size());
706 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL
),
707 static_cast<Tab
*>(service_
->entries().front())->
708 navigations
[0].virtual_url());
710 // Don't prune NTPs that have multiple navigations.
711 // (Erase the last NTP first.)
712 delete service_
->entries().front();
713 mutable_entries()->erase(mutable_entries()->begin());
715 tab
->current_navigation_index
= 1;
716 tab
->navigations
.push_back(navigation
);
717 tab
->navigations
.push_back(navigation
);
718 mutable_entries()->push_front(tab
);
719 EXPECT_EQ(max_entries
, service_
->entries().size());
721 EXPECT_EQ(max_entries
, service_
->entries().size());
722 EXPECT_EQ(GURL(chrome::kChromeUINewTabURL
),
723 static_cast<Tab
*>(service_
->entries().front())->
724 navigations
[1].virtual_url());
727 // Regression test for crbug.com/106082
728 TEST_F(PersistentTabRestoreServiceTest
, PruneIsCalled
) {
729 CreateSessionServiceWithOneWindow(false);
731 SessionServiceFactory::GetForProfile(profile())->
732 MoveCurrentSessionToLastSession();
734 profile()->set_restored_last_session(true);
736 const size_t max_entries
= kMaxEntries
;
737 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
739 GURL(base::StringPrintf("http://%d", static_cast<int>(i
))));
740 service_
->CreateHistoricalTab(web_contents(), -1);
743 EXPECT_EQ(max_entries
, service_
->entries().size());
744 // This should not crash.
745 SynchronousLoadTabsFromLastSession();
746 EXPECT_EQ(max_entries
, service_
->entries().size());
749 // Makes sure invoking LoadTabsFromLastSession() when the max number of entries
750 // have been added results in IsLoaded() returning true and notifies observers.
751 TEST_F(PersistentTabRestoreServiceTest
, GoToLoadedWhenHaveMaxEntries
) {
752 const size_t max_entries
= kMaxEntries
;
753 for (size_t i
= 0; i
< max_entries
+ 5; i
++) {
755 GURL(base::StringPrintf("http://%d", static_cast<int>(i
))));
756 service_
->CreateHistoricalTab(web_contents(), -1);
759 EXPECT_FALSE(service_
->IsLoaded());
760 TestTabRestoreServiceObserver observer
;
761 service_
->AddObserver(&observer
);
762 EXPECT_EQ(max_entries
, service_
->entries().size());
763 SynchronousLoadTabsFromLastSession();
764 EXPECT_TRUE(observer
.got_loaded());
765 EXPECT_TRUE(service_
->IsLoaded());
766 service_
->RemoveObserver(&observer
);