Upstream version 10.39.225.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_types.h"
17 #include "chrome/browser/sessions/tab_restore_service_factory.h"
18 #include "chrome/browser/sessions/tab_restore_service_observer.h"
19 #include "chrome/common/url_constants.h"
20 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
21 #include "chrome/test/base/chrome_render_view_test.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "components/sessions/serialized_navigation_entry_test_helper.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/navigation_controller.h"
26 #include "content/public/browser/navigation_entry.h"
27 #include "content/public/browser/notification_service.h"
28 #include "content/public/browser/notification_types.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/test/render_view_test.h"
31 #include "content/public/test/test_utils.h"
32 #include "content/public/test/web_contents_tester.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34
35 typedef TabRestoreService::Tab Tab;
36 typedef TabRestoreService::Window Window;
37
38 using content::NavigationEntry;
39 using content::WebContentsTester;
40 using sessions::SerializedNavigationEntry;
41 using sessions::SerializedNavigationEntryTestHelper;
42
43 // Create subclass that overrides TimeNow so that we can control the time used
44 // for closed tabs and windows.
45 class PersistentTabRestoreTimeFactory : public TabRestoreService::TimeFactory {
46  public:
47   PersistentTabRestoreTimeFactory() : time_(base::Time::Now()) {}
48
49   virtual ~PersistentTabRestoreTimeFactory() {}
50
51   virtual base::Time TimeNow() OVERRIDE {
52     return time_;
53   }
54
55  private:
56   base::Time time_;
57 };
58
59 class PersistentTabRestoreServiceTest : public ChromeRenderViewHostTestHarness {
60  public:
61   PersistentTabRestoreServiceTest()
62     : url1_("http://1"),
63       url2_("http://2"),
64       url3_("http://3"),
65       user_agent_override_(
66           "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19"
67           " (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19"),
68       time_factory_(NULL) {
69   }
70
71   virtual ~PersistentTabRestoreServiceTest() {
72   }
73
74  protected:
75   enum {
76     kMaxEntries = TabRestoreServiceHelper::kMaxEntries,
77   };
78
79   // testing::Test:
80   virtual void SetUp() OVERRIDE {
81     ChromeRenderViewHostTestHarness::SetUp();
82     time_factory_ = new PersistentTabRestoreTimeFactory();
83     service_.reset(new PersistentTabRestoreService(profile(), time_factory_));
84   }
85
86   virtual void TearDown() OVERRIDE {
87     service_->Shutdown();
88     service_.reset();
89     delete time_factory_;
90     ChromeRenderViewHostTestHarness::TearDown();
91   }
92
93   TabRestoreService::Entries* mutable_entries() {
94     return service_->mutable_entries();
95   }
96
97   void PruneEntries() {
98     service_->PruneEntries();
99   }
100
101   void AddThreeNavigations() {
102     // Navigate to three URLs.
103     NavigateAndCommit(url1_);
104     NavigateAndCommit(url2_);
105     NavigateAndCommit(url3_);
106   }
107
108   void NavigateToIndex(int index) {
109     // Navigate back. We have to do this song and dance as NavigationController
110     // isn't happy if you navigate immediately while going back.
111     controller().GoToIndex(index);
112     WebContentsTester::For(web_contents())->CommitPendingNavigation();
113   }
114
115   void RecreateService() {
116     // Must set service to null first so that it is destroyed before the new
117     // one is created.
118     service_->Shutdown();
119     content::RunAllBlockingPoolTasksUntilIdle();
120     service_.reset();
121     service_.reset(new PersistentTabRestoreService(profile(), time_factory_));
122     SynchronousLoadTabsFromLastSession();
123   }
124
125   // Adds a window with one tab and url to the profile's session service.
126   // If |pinned| is true, the tab is marked as pinned in the session service.
127   void AddWindowWithOneTabToSessionService(bool pinned) {
128     SessionService* session_service =
129         SessionServiceFactory::GetForProfile(profile());
130     SessionID tab_id;
131     SessionID window_id;
132     session_service->SetWindowType(
133         window_id, Browser::TYPE_TABBED, 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);
137     if (pinned)
138       session_service->SetPinnedState(window_id, tab_id, true);
139     session_service->UpdateTabNavigation(
140         window_id, tab_id,
141         SerializedNavigationEntryTestHelper::CreateNavigation(
142             url1_.spec(), "title"));
143   }
144
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     // The profile takes ownership of this.
151     SessionService* session_service = new SessionService(profile());
152     SessionServiceFactory::SetForTestProfile(profile(), session_service);
153
154     AddWindowWithOneTabToSessionService(pinned);
155
156     // Set this, otherwise previous session won't be loaded.
157     profile()->set_last_session_exited_cleanly(false);
158   }
159
160   void SynchronousLoadTabsFromLastSession() {
161     // Ensures that the load is complete before continuing.
162     service_->LoadTabsFromLastSession();
163     content::RunAllBlockingPoolTasksUntilIdle();
164   }
165
166   GURL url1_;
167   GURL url2_;
168   GURL url3_;
169   std::string user_agent_override_;
170   scoped_ptr<PersistentTabRestoreService> service_;
171   PersistentTabRestoreTimeFactory* time_factory_;
172 };
173
174 namespace {
175
176 class TestTabRestoreServiceObserver : public TabRestoreServiceObserver {
177  public:
178   TestTabRestoreServiceObserver() : got_loaded_(false) {}
179
180   void clear_got_loaded() { got_loaded_ = false; }
181   bool got_loaded() const { return got_loaded_; }
182
183   // TabRestoreServiceObserver:
184   virtual void TabRestoreServiceChanged(TabRestoreService* service) OVERRIDE {
185   }
186   virtual void TabRestoreServiceDestroyed(TabRestoreService* service) OVERRIDE {
187   }
188   virtual void TabRestoreServiceLoaded(TabRestoreService* service) OVERRIDE {
189     got_loaded_ = true;
190   }
191
192  private:
193   // Was TabRestoreServiceLoaded() invoked?
194   bool got_loaded_;
195
196   DISALLOW_COPY_AND_ASSIGN(TestTabRestoreServiceObserver);
197 };
198
199 }  // namespace
200
201 TEST_F(PersistentTabRestoreServiceTest, Basic) {
202   AddThreeNavigations();
203
204   // Have the service record the tab.
205   service_->CreateHistoricalTab(web_contents(), -1);
206
207   // Make sure an entry was created.
208   ASSERT_EQ(1U, service_->entries().size());
209
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());
224
225   NavigateToIndex(1);
226
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);
230
231   // There should be two entries now.
232   ASSERT_EQ(2U, service_->entries().size());
233
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());
247 }
248
249 // Make sure TabRestoreService doesn't create an entry for a tab with no
250 // navigations.
251 TEST_F(PersistentTabRestoreServiceTest, DontCreateEmptyTab) {
252   service_->CreateHistoricalTab(web_contents(), -1);
253   EXPECT_TRUE(service_->entries().empty());
254 }
255
256 // Tests restoring a single tab.
257 TEST_F(PersistentTabRestoreServiceTest, Restore) {
258   AddThreeNavigations();
259
260   // Have the service record the tab.
261   service_->CreateHistoricalTab(web_contents(), -1);
262
263   // Recreate the service and have it load the tabs.
264   RecreateService();
265
266   // One entry should be created.
267   ASSERT_EQ(1U, service_->entries().size());
268
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());
281 }
282
283 // Tests restoring a single pinned tab.
284 TEST_F(PersistentTabRestoreServiceTest, RestorePinnedAndApp) {
285   AddThreeNavigations();
286
287   // Have the service record the tab.
288   service_->CreateHistoricalTab(web_contents(), -1);
289
290   // One entry should be created.
291   ASSERT_EQ(1U, service_->entries().size());
292
293   // We have to explicitly mark the tab as pinned as there is no browser for
294   // these tests.
295   TabRestoreService::Entry* entry = service_->entries().front();
296   ASSERT_EQ(TabRestoreService::TAB, entry->type);
297   Tab* tab = static_cast<Tab*>(entry);
298   tab->pinned = true;
299   const std::string extension_app_id("test");
300   tab->extension_app_id = extension_app_id;
301
302   // Recreate the service and have it load the tabs.
303   RecreateService();
304
305   // One entry should be created.
306   ASSERT_EQ(1U, service_->entries().size());
307
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);
319 }
320
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);
327
328   // Have the service record the tab.
329   service_->CreateHistoricalTab(web_contents(), -1);
330   ASSERT_EQ(1U, service_->entries().size());
331
332   // Recreate the service and have it load the tabs.
333   RecreateService();
334
335   // One entry should be created.
336   ASSERT_EQ(1U, service_->entries().size());
337
338   const TabRestoreService::Entry* restored_entry = service_->entries().front();
339   ASSERT_EQ(TabRestoreService::TAB, restored_entry->type);
340
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());
347 }
348
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();
354
355   // Have the service record the tab.
356   service_->CreateHistoricalTab(web_contents(), -1);
357   ASSERT_EQ(1U, service_->entries().size());
358
359   // Recreate the service and have it load the tabs.
360   RecreateService();
361
362   SynchronousLoadTabsFromLastSession();
363
364   // There should only be one entry.
365   ASSERT_EQ(1U, service_->entries().size());
366 }
367
368 // Makes sure we load the previous session as necessary.
369 TEST_F(PersistentTabRestoreServiceTest, LoadPreviousSession) {
370   CreateSessionServiceWithOneWindow(false);
371
372   SessionServiceFactory::GetForProfile(profile())->
373       MoveCurrentSessionToLastSession();
374
375   EXPECT_FALSE(service_->IsLoaded());
376
377   TestTabRestoreServiceObserver observer;
378   service_->AddObserver(&observer);
379   SynchronousLoadTabsFromLastSession();
380   EXPECT_TRUE(observer.got_loaded());
381   service_->RemoveObserver(&observer);
382
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());
396 }
397
398 // Makes sure we don't attempt to load previous sessions after a restore.
399 TEST_F(PersistentTabRestoreServiceTest, DontLoadAfterRestore) {
400   CreateSessionServiceWithOneWindow(false);
401
402   SessionServiceFactory::GetForProfile(profile())->
403       MoveCurrentSessionToLastSession();
404
405   profile()->set_restored_last_session(true);
406
407   SynchronousLoadTabsFromLastSession();
408
409   // Because we restored a session PersistentTabRestoreService shouldn't load
410   // the tabs.
411   ASSERT_EQ(0U, service_->entries().size());
412 }
413
414 // Makes sure we don't attempt to load previous sessions after a clean exit.
415 TEST_F(PersistentTabRestoreServiceTest, DontLoadAfterCleanExit) {
416   CreateSessionServiceWithOneWindow(false);
417
418   SessionServiceFactory::GetForProfile(profile())->
419       MoveCurrentSessionToLastSession();
420
421   profile()->set_last_session_exited_cleanly(true);
422
423   SynchronousLoadTabsFromLastSession();
424
425   ASSERT_EQ(0U, service_->entries().size());
426 }
427
428 TEST_F(PersistentTabRestoreServiceTest, LoadPreviousSessionAndTabs) {
429   CreateSessionServiceWithOneWindow(false);
430
431   SessionServiceFactory::GetForProfile(profile())->
432       MoveCurrentSessionToLastSession();
433
434   AddThreeNavigations();
435
436   service_->CreateHistoricalTab(web_contents(), -1);
437
438   RecreateService();
439
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());
455
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());
468 }
469
470 // Make sure pinned state is correctly loaded from session service.
471 TEST_F(PersistentTabRestoreServiceTest, LoadPreviousSessionAndTabsPinned) {
472   CreateSessionServiceWithOneWindow(true);
473
474   SessionServiceFactory::GetForProfile(profile())->
475       MoveCurrentSessionToLastSession();
476
477   AddThreeNavigations();
478
479   service_->CreateHistoricalTab(web_contents(), -1);
480
481   RecreateService();
482
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());
497
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());
508 }
509
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);
514
515   for (size_t i = 0; i < kMaxEntries; ++i)
516     AddWindowWithOneTabToSessionService(false);
517
518   SessionServiceFactory::GetForProfile(profile())->
519       MoveCurrentSessionToLastSession();
520
521   AddThreeNavigations();
522
523   service_->CreateHistoricalTab(web_contents(), -1);
524
525   RecreateService();
526
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());
530
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());
543 }
544
545 // Makes sure we restore timestamps correctly.
546 TEST_F(PersistentTabRestoreServiceTest, TimestampSurvivesRestore) {
547   base::Time tab_timestamp(base::Time::FromInternalValue(123456789));
548
549   AddThreeNavigations();
550
551   // Have the service record the tab.
552   service_->CreateHistoricalTab(web_contents(), -1);
553
554   // Make sure an entry was created.
555   ASSERT_EQ(1U, service_->entries().size());
556
557   // Make sure the entry matches.
558   std::vector<SerializedNavigationEntry> old_navigations;
559   {
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;
566   }
567
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());
571   }
572
573   // Set this, otherwise previous session won't be loaded.
574   profile()->set_last_session_exited_cleanly(false);
575
576   RecreateService();
577
578   // One entry should be created.
579   ASSERT_EQ(1U, service_->entries().size());
580
581   // And verify the entry.
582   TabRestoreService::Entry* restored_entry = service_->entries().front();
583   ASSERT_EQ(TabRestoreService::TAB, restored_entry->type);
584   Tab* restored_tab =
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());
592   }
593 }
594
595 // Makes sure we restore status codes correctly.
596 TEST_F(PersistentTabRestoreServiceTest, StatusCodesSurviveRestore) {
597   AddThreeNavigations();
598
599   // Have the service record the tab.
600   service_->CreateHistoricalTab(web_contents(), -1);
601
602   // Make sure an entry was created.
603   ASSERT_EQ(1U, service_->entries().size());
604
605   // Make sure the entry matches.
606   std::vector<sessions::SerializedNavigationEntry> old_navigations;
607   {
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;
613   }
614
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());
618   }
619
620   // Set this, otherwise previous session won't be loaded.
621   profile()->set_last_session_exited_cleanly(false);
622
623   RecreateService();
624
625   // One entry should be created.
626   ASSERT_EQ(1U, service_->entries().size());
627
628   // And verify the entry.
629   TabRestoreService::Entry* restored_entry = service_->entries().front();
630   ASSERT_EQ(TabRestoreService::TAB, restored_entry->type);
631   Tab* restored_tab =
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());
636   }
637 }
638
639 TEST_F(PersistentTabRestoreServiceTest, PruneEntries) {
640   service_->ClearEntries();
641   ASSERT_TRUE(service_->entries().empty());
642
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)));
649
650     Tab* tab = new Tab();
651     tab->navigations.push_back(navigation);
652     tab->current_navigation_index = 0;
653
654     mutable_entries()->push_back(tab);
655   }
656
657   // Only keep kMaxEntries around.
658   EXPECT_EQ(max_entries + 5, service_->entries().size());
659   PruneEntries();
660   EXPECT_EQ(max_entries, service_->entries().size());
661   // Pruning again does nothing.
662   PruneEntries();
663   EXPECT_EQ(max_entries, service_->entries().size());
664
665   // Prune older first.
666   const char kRecentUrl[] = "http://recent";
667   SerializedNavigationEntry navigation =
668       SerializedNavigationEntryTestHelper::CreateNavigation(kRecentUrl,
669                                                             "Most recent");
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());
675   PruneEntries();
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());
680
681   // Ignore NTPs.
682   navigation = SerializedNavigationEntryTestHelper::CreateNavigation(
683       chrome::kChromeUINewTabURL, "New tab");
684
685   tab = new Tab();
686   tab->navigations.push_back(navigation);
687   tab->current_navigation_index = 0;
688   mutable_entries()->push_front(tab);
689
690   EXPECT_EQ(max_entries + 1, service_->entries().size());
691   PruneEntries();
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());
696
697   // Don't prune pinned NTPs.
698   tab = new Tab();
699   tab->pinned = true;
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());
704   PruneEntries();
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());
709
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());
714   tab = new Tab();
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());
720   PruneEntries();
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());
725 }
726
727 // Regression test for crbug.com/106082
728 TEST_F(PersistentTabRestoreServiceTest, PruneIsCalled) {
729   CreateSessionServiceWithOneWindow(false);
730
731   SessionServiceFactory::GetForProfile(profile())->
732       MoveCurrentSessionToLastSession();
733
734   profile()->set_restored_last_session(true);
735
736   const size_t max_entries = kMaxEntries;
737   for (size_t i = 0; i < max_entries + 5; i++) {
738     NavigateAndCommit(
739         GURL(base::StringPrintf("http://%d", static_cast<int>(i))));
740     service_->CreateHistoricalTab(web_contents(), -1);
741   }
742
743   EXPECT_EQ(max_entries, service_->entries().size());
744   // This should not crash.
745   SynchronousLoadTabsFromLastSession();
746   EXPECT_EQ(max_entries, service_->entries().size());
747 }
748
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++) {
754     NavigateAndCommit(
755         GURL(base::StringPrintf("http://%d", static_cast<int>(i))));
756     service_->CreateHistoricalTab(web_contents(), -1);
757   }
758
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);
767 }