Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sessions / persistent_tab_restore_service_unittest.cc
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.
4
5 #include "chrome/browser/sessions/persistent_tab_restore_service.h"
6
7 #include <string>
8
9 #include "base/compiler_specific.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/threading/sequenced_worker_pool.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/sessions/session_service.h"
15 #include "chrome/browser/sessions/session_service_factory.h"
16 #include "chrome/browser/sessions/session_service_utils.h"
17 #include "chrome/browser/sessions/session_types.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 "content/public/browser/browser_thread.h"
26 #include "content/public/browser/navigation_controller.h"
27 #include "content/public/browser/navigation_entry.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/browser/notification_types.h"
30 #include "content/public/browser/web_contents.h"
31 #include "content/public/test/render_view_test.h"
32 #include "content/public/test/test_utils.h"
33 #include "content/public/test/web_contents_tester.h"
34 #include "testing/gtest/include/gtest/gtest.h"
35
36 typedef TabRestoreService::Tab Tab;
37 typedef TabRestoreService::Window Window;
38
39 using content::NavigationEntry;
40 using content::WebContentsTester;
41 using sessions::SerializedNavigationEntry;
42 using sessions::SerializedNavigationEntryTestHelper;
43
44 // Create subclass that overrides TimeNow so that we can control the time used
45 // for closed tabs and windows.
46 class PersistentTabRestoreTimeFactory : public TabRestoreService::TimeFactory {
47  public:
48   PersistentTabRestoreTimeFactory() : time_(base::Time::Now()) {}
49
50   ~PersistentTabRestoreTimeFactory() override {}
51
52   base::Time TimeNow() override { return time_; }
53
54  private:
55   base::Time time_;
56 };
57
58 class PersistentTabRestoreServiceTest : public ChromeRenderViewHostTestHarness {
59  public:
60   PersistentTabRestoreServiceTest()
61     : url1_("http://1"),
62       url2_("http://2"),
63       url3_("http://3"),
64       user_agent_override_(
65           "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19"
66           " (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19"),
67       time_factory_(NULL) {
68   }
69
70   ~PersistentTabRestoreServiceTest() override {}
71
72  protected:
73   enum {
74     kMaxEntries = TabRestoreServiceHelper::kMaxEntries,
75   };
76
77   // testing::Test:
78   void SetUp() override {
79     ChromeRenderViewHostTestHarness::SetUp();
80     time_factory_ = new PersistentTabRestoreTimeFactory();
81     service_.reset(new PersistentTabRestoreService(profile(), time_factory_));
82   }
83
84   void TearDown() override {
85     service_->Shutdown();
86     service_.reset();
87     delete time_factory_;
88     ChromeRenderViewHostTestHarness::TearDown();
89   }
90
91   TabRestoreService::Entries* mutable_entries() {
92     return service_->mutable_entries();
93   }
94
95   void PruneEntries() {
96     service_->PruneEntries();
97   }
98
99   void AddThreeNavigations() {
100     // Navigate to three URLs.
101     NavigateAndCommit(url1_);
102     NavigateAndCommit(url2_);
103     NavigateAndCommit(url3_);
104   }
105
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();
111   }
112
113   void RecreateService() {
114     // Must set service to null first so that it is destroyed before the new
115     // one is created.
116     service_->Shutdown();
117     content::RunAllBlockingPoolTasksUntilIdle();
118     service_.reset();
119     service_.reset(new PersistentTabRestoreService(profile(), time_factory_));
120     SynchronousLoadTabsFromLastSession();
121   }
122
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());
128     SessionID tab_id;
129     SessionID window_id;
130     session_service->SetWindowType(window_id,
131                                    Browser::TYPE_TABBED,
132                                    SessionService::TYPE_NORMAL);
133     session_service->SetTabWindow(window_id, tab_id);
134     session_service->SetTabIndexInWindow(window_id, tab_id, 0);
135     session_service->SetSelectedTabInWindow(window_id, 0);
136     if (pinned)
137       session_service->SetPinnedState(window_id, tab_id, true);
138     session_service->UpdateTabNavigation(
139         window_id, tab_id,
140         SerializedNavigationEntryTestHelper::CreateNavigation(
141             url1_.spec(), "title"));
142   }
143
144   // Creates a SessionService and assigns it to the Profile. The SessionService
145   // is configured with a single window with a single tab pointing at url1_ by
146   // way of AddWindowWithOneTabToSessionService. If |pinned| is true, the
147   // tab is marked as pinned in the session service.
148   void CreateSessionServiceWithOneWindow(bool pinned) {
149     // The profile takes ownership of this.
150     SessionService* session_service = new SessionService(profile());
151     SessionServiceFactory::SetForTestProfile(profile(), session_service);
152
153     AddWindowWithOneTabToSessionService(pinned);
154
155     // Set this, otherwise previous session won't be loaded.
156     profile()->set_last_session_exited_cleanly(false);
157   }
158
159   void SynchronousLoadTabsFromLastSession() {
160     // Ensures that the load is complete before continuing.
161     service_->LoadTabsFromLastSession();
162     content::RunAllBlockingPoolTasksUntilIdle();
163   }
164
165   GURL url1_;
166   GURL url2_;
167   GURL url3_;
168   std::string user_agent_override_;
169   scoped_ptr<PersistentTabRestoreService> service_;
170   PersistentTabRestoreTimeFactory* time_factory_;
171 };
172
173 namespace {
174
175 class TestTabRestoreServiceObserver : public TabRestoreServiceObserver {
176  public:
177   TestTabRestoreServiceObserver() : got_loaded_(false) {}
178
179   void clear_got_loaded() { got_loaded_ = false; }
180   bool got_loaded() const { return got_loaded_; }
181
182   // TabRestoreServiceObserver:
183   void TabRestoreServiceChanged(TabRestoreService* service) override {}
184   void TabRestoreServiceDestroyed(TabRestoreService* service) override {}
185   void TabRestoreServiceLoaded(TabRestoreService* service) override {
186     got_loaded_ = true;
187   }
188
189  private:
190   // Was TabRestoreServiceLoaded() invoked?
191   bool got_loaded_;
192
193   DISALLOW_COPY_AND_ASSIGN(TestTabRestoreServiceObserver);
194 };
195
196 }  // namespace
197
198 TEST_F(PersistentTabRestoreServiceTest, Basic) {
199   AddThreeNavigations();
200
201   // Have the service record the tab.
202   service_->CreateHistoricalTab(web_contents(), -1);
203
204   // Make sure an entry was created.
205   ASSERT_EQ(1U, service_->entries().size());
206
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());
221
222   NavigateToIndex(1);
223
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);
227
228   // There should be two entries now.
229   ASSERT_EQ(2U, service_->entries().size());
230
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());
244 }
245
246 // Make sure TabRestoreService doesn't create an entry for a tab with no
247 // navigations.
248 TEST_F(PersistentTabRestoreServiceTest, DontCreateEmptyTab) {
249   service_->CreateHistoricalTab(web_contents(), -1);
250   EXPECT_TRUE(service_->entries().empty());
251 }
252
253 // Tests restoring a single tab.
254 TEST_F(PersistentTabRestoreServiceTest, Restore) {
255   AddThreeNavigations();
256
257   // Have the service record the tab.
258   service_->CreateHistoricalTab(web_contents(), -1);
259
260   // Recreate the service and have it load the tabs.
261   RecreateService();
262
263   // One entry should be created.
264   ASSERT_EQ(1U, service_->entries().size());
265
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());
278 }
279
280 // Tests restoring a single pinned tab.
281 TEST_F(PersistentTabRestoreServiceTest, RestorePinnedAndApp) {
282   AddThreeNavigations();
283
284   // Have the service record the tab.
285   service_->CreateHistoricalTab(web_contents(), -1);
286
287   // One entry should be created.
288   ASSERT_EQ(1U, service_->entries().size());
289
290   // We have to explicitly mark the tab as pinned as there is no browser for
291   // these tests.
292   TabRestoreService::Entry* entry = service_->entries().front();
293   ASSERT_EQ(TabRestoreService::TAB, entry->type);
294   Tab* tab = static_cast<Tab*>(entry);
295   tab->pinned = true;
296   const std::string extension_app_id("test");
297   tab->extension_app_id = extension_app_id;
298
299   // Recreate the service and have it load the tabs.
300   RecreateService();
301
302   // One entry should be created.
303   ASSERT_EQ(1U, service_->entries().size());
304
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);
316 }
317
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);
324
325   // Have the service record the tab.
326   service_->CreateHistoricalTab(web_contents(), -1);
327   ASSERT_EQ(1U, service_->entries().size());
328
329   // Recreate the service and have it load the tabs.
330   RecreateService();
331
332   // One entry should be created.
333   ASSERT_EQ(1U, service_->entries().size());
334
335   const TabRestoreService::Entry* restored_entry = service_->entries().front();
336   ASSERT_EQ(TabRestoreService::TAB, restored_entry->type);
337
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());
344 }
345
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();
351
352   // Have the service record the tab.
353   service_->CreateHistoricalTab(web_contents(), -1);
354   ASSERT_EQ(1U, service_->entries().size());
355
356   // Recreate the service and have it load the tabs.
357   RecreateService();
358
359   SynchronousLoadTabsFromLastSession();
360
361   // There should only be one entry.
362   ASSERT_EQ(1U, service_->entries().size());
363 }
364
365 // Makes sure we load the previous session as necessary.
366 TEST_F(PersistentTabRestoreServiceTest, LoadPreviousSession) {
367   CreateSessionServiceWithOneWindow(false);
368
369   SessionServiceFactory::GetForProfile(profile())->
370       MoveCurrentSessionToLastSession();
371
372   EXPECT_FALSE(service_->IsLoaded());
373
374   TestTabRestoreServiceObserver observer;
375   service_->AddObserver(&observer);
376   SynchronousLoadTabsFromLastSession();
377   EXPECT_TRUE(observer.got_loaded());
378   service_->RemoveObserver(&observer);
379
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());
393 }
394
395 // Makes sure we don't attempt to load previous sessions after a restore.
396 TEST_F(PersistentTabRestoreServiceTest, DontLoadAfterRestore) {
397   CreateSessionServiceWithOneWindow(false);
398
399   SessionServiceFactory::GetForProfile(profile())->
400       MoveCurrentSessionToLastSession();
401
402   profile()->set_restored_last_session(true);
403
404   SynchronousLoadTabsFromLastSession();
405
406   // Because we restored a session PersistentTabRestoreService shouldn't load
407   // the tabs.
408   ASSERT_EQ(0U, service_->entries().size());
409 }
410
411 // Makes sure we don't attempt to load previous sessions after a clean exit.
412 TEST_F(PersistentTabRestoreServiceTest, DontLoadAfterCleanExit) {
413   CreateSessionServiceWithOneWindow(false);
414
415   SessionServiceFactory::GetForProfile(profile())->
416       MoveCurrentSessionToLastSession();
417
418   profile()->set_last_session_exited_cleanly(true);
419
420   SynchronousLoadTabsFromLastSession();
421
422   ASSERT_EQ(0U, service_->entries().size());
423 }
424
425 TEST_F(PersistentTabRestoreServiceTest, LoadPreviousSessionAndTabs) {
426   CreateSessionServiceWithOneWindow(false);
427
428   SessionServiceFactory::GetForProfile(profile())->
429       MoveCurrentSessionToLastSession();
430
431   AddThreeNavigations();
432
433   service_->CreateHistoricalTab(web_contents(), -1);
434
435   RecreateService();
436
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());
452
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());
465 }
466
467 // Make sure pinned state is correctly loaded from session service.
468 TEST_F(PersistentTabRestoreServiceTest, LoadPreviousSessionAndTabsPinned) {
469   CreateSessionServiceWithOneWindow(true);
470
471   SessionServiceFactory::GetForProfile(profile())->
472       MoveCurrentSessionToLastSession();
473
474   AddThreeNavigations();
475
476   service_->CreateHistoricalTab(web_contents(), -1);
477
478   RecreateService();
479
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());
494
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());
505 }
506
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);
511
512   for (size_t i = 0; i < kMaxEntries; ++i)
513     AddWindowWithOneTabToSessionService(false);
514
515   SessionServiceFactory::GetForProfile(profile())->
516       MoveCurrentSessionToLastSession();
517
518   AddThreeNavigations();
519
520   service_->CreateHistoricalTab(web_contents(), -1);
521
522   RecreateService();
523
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());
527
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());
540 }
541
542 // Makes sure we restore timestamps correctly.
543 TEST_F(PersistentTabRestoreServiceTest, TimestampSurvivesRestore) {
544   base::Time tab_timestamp(base::Time::FromInternalValue(123456789));
545
546   AddThreeNavigations();
547
548   // Have the service record the tab.
549   service_->CreateHistoricalTab(web_contents(), -1);
550
551   // Make sure an entry was created.
552   ASSERT_EQ(1U, service_->entries().size());
553
554   // Make sure the entry matches.
555   std::vector<SerializedNavigationEntry> old_navigations;
556   {
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;
563   }
564
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());
568   }
569
570   // Set this, otherwise previous session won't be loaded.
571   profile()->set_last_session_exited_cleanly(false);
572
573   RecreateService();
574
575   // One entry should be created.
576   ASSERT_EQ(1U, service_->entries().size());
577
578   // And verify the entry.
579   TabRestoreService::Entry* restored_entry = service_->entries().front();
580   ASSERT_EQ(TabRestoreService::TAB, restored_entry->type);
581   Tab* restored_tab =
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());
589   }
590 }
591
592 // Makes sure we restore status codes correctly.
593 TEST_F(PersistentTabRestoreServiceTest, StatusCodesSurviveRestore) {
594   AddThreeNavigations();
595
596   // Have the service record the tab.
597   service_->CreateHistoricalTab(web_contents(), -1);
598
599   // Make sure an entry was created.
600   ASSERT_EQ(1U, service_->entries().size());
601
602   // Make sure the entry matches.
603   std::vector<sessions::SerializedNavigationEntry> old_navigations;
604   {
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;
610   }
611
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());
615   }
616
617   // Set this, otherwise previous session won't be loaded.
618   profile()->set_last_session_exited_cleanly(false);
619
620   RecreateService();
621
622   // One entry should be created.
623   ASSERT_EQ(1U, service_->entries().size());
624
625   // And verify the entry.
626   TabRestoreService::Entry* restored_entry = service_->entries().front();
627   ASSERT_EQ(TabRestoreService::TAB, restored_entry->type);
628   Tab* restored_tab =
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());
633   }
634 }
635
636 TEST_F(PersistentTabRestoreServiceTest, PruneEntries) {
637   service_->ClearEntries();
638   ASSERT_TRUE(service_->entries().empty());
639
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::StringPrintf("%d", static_cast<int>(i)));
646
647     Tab* tab = new Tab();
648     tab->navigations.push_back(navigation);
649     tab->current_navigation_index = 0;
650
651     mutable_entries()->push_back(tab);
652   }
653
654   // Only keep kMaxEntries around.
655   EXPECT_EQ(max_entries + 5, service_->entries().size());
656   PruneEntries();
657   EXPECT_EQ(max_entries, service_->entries().size());
658   // Pruning again does nothing.
659   PruneEntries();
660   EXPECT_EQ(max_entries, service_->entries().size());
661
662   // Prune older first.
663   const char kRecentUrl[] = "http://recent";
664   SerializedNavigationEntry navigation =
665       SerializedNavigationEntryTestHelper::CreateNavigation(kRecentUrl,
666                                                             "Most recent");
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());
672   PruneEntries();
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());
677
678   // Ignore NTPs.
679   navigation = SerializedNavigationEntryTestHelper::CreateNavigation(
680       chrome::kChromeUINewTabURL, "New tab");
681
682   tab = new Tab();
683   tab->navigations.push_back(navigation);
684   tab->current_navigation_index = 0;
685   mutable_entries()->push_front(tab);
686
687   EXPECT_EQ(max_entries + 1, service_->entries().size());
688   PruneEntries();
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());
693
694   // Don't prune pinned NTPs.
695   tab = new Tab();
696   tab->pinned = true;
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());
701   PruneEntries();
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());
706
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());
711   tab = new Tab();
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());
717   PruneEntries();
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());
722 }
723
724 // Regression test for crbug.com/106082
725 TEST_F(PersistentTabRestoreServiceTest, PruneIsCalled) {
726   CreateSessionServiceWithOneWindow(false);
727
728   SessionServiceFactory::GetForProfile(profile())->
729       MoveCurrentSessionToLastSession();
730
731   profile()->set_restored_last_session(true);
732
733   const size_t max_entries = kMaxEntries;
734   for (size_t i = 0; i < max_entries + 5; i++) {
735     NavigateAndCommit(
736         GURL(base::StringPrintf("http://%d", static_cast<int>(i))));
737     service_->CreateHistoricalTab(web_contents(), -1);
738   }
739
740   EXPECT_EQ(max_entries, service_->entries().size());
741   // This should not crash.
742   SynchronousLoadTabsFromLastSession();
743   EXPECT_EQ(max_entries, service_->entries().size());
744 }
745
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++) {
751     NavigateAndCommit(
752         GURL(base::StringPrintf("http://%d", static_cast<int>(i))));
753     service_->CreateHistoricalTab(web_contents(), -1);
754   }
755
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);
764 }