Home | History | Annotate | Download | only in sessions
      1 // Copyright (c) 2012 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 "base/bind.h"
      6 #include "base/bind_helpers.h"
      7 #include "base/file_util.h"
      8 #include "base/files/scoped_temp_dir.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/memory/scoped_vector.h"
     11 #include "base/path_service.h"
     12 #include "base/stl_util.h"
     13 #include "base/strings/string_number_conversions.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/time/time.h"
     16 #include "chrome/browser/chrome_notification_types.h"
     17 #include "chrome/browser/defaults.h"
     18 #include "chrome/browser/sessions/session_backend.h"
     19 #include "chrome/browser/sessions/session_service.h"
     20 #include "chrome/browser/sessions/session_service_test_helper.h"
     21 #include "chrome/browser/sessions/session_types.h"
     22 #include "chrome/common/chrome_paths.h"
     23 #include "chrome/common/url_constants.h"
     24 #include "chrome/test/base/browser_with_test_window_test.h"
     25 #include "chrome/test/base/testing_profile.h"
     26 #include "components/sessions/serialized_navigation_entry_test_helper.h"
     27 #include "content/public/browser/navigation_entry.h"
     28 #include "content/public/browser/notification_observer.h"
     29 #include "content/public/browser/notification_registrar.h"
     30 #include "content/public/browser/notification_service.h"
     31 #include "content/public/common/page_state.h"
     32 #include "testing/gtest/include/gtest/gtest.h"
     33 
     34 using content::NavigationEntry;
     35 using sessions::SerializedNavigationEntry;
     36 using sessions::SerializedNavigationEntryTestHelper;
     37 
     38 class SessionServiceTest : public BrowserWithTestWindowTest,
     39                            public content::NotificationObserver {
     40  public:
     41   SessionServiceTest() : window_bounds(0, 1, 2, 3), sync_save_count_(0) {}
     42 
     43  protected:
     44   virtual void SetUp() {
     45     BrowserWithTestWindowTest::SetUp();
     46     std::string b = base::Int64ToString(base::Time::Now().ToInternalValue());
     47 
     48     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     49     path_ = temp_dir_.path().Append(FILE_PATH_LITERAL("SessionTestDirs"));
     50     ASSERT_TRUE(base::CreateDirectory(path_));
     51     path_ = path_.AppendASCII(b);
     52 
     53     SessionService* session_service = new SessionService(path_);
     54     helper_.SetService(session_service);
     55 
     56     service()->SetWindowType(
     57         window_id, Browser::TYPE_TABBED, SessionService::TYPE_NORMAL);
     58     service()->SetWindowBounds(window_id,
     59                                window_bounds,
     60                                ui::SHOW_STATE_NORMAL);
     61   }
     62 
     63   // Upon notification, increment the sync_save_count variable
     64   virtual void Observe(int type,
     65                        const content::NotificationSource& source,
     66                        const content::NotificationDetails& details) OVERRIDE {
     67     ASSERT_EQ(type, chrome::NOTIFICATION_SESSION_SERVICE_SAVED);
     68     sync_save_count_++;
     69   }
     70 
     71   virtual void TearDown() {
     72     helper_.SetService(NULL);
     73     BrowserWithTestWindowTest::TearDown();
     74   }
     75 
     76   void UpdateNavigation(
     77       const SessionID& window_id,
     78       const SessionID& tab_id,
     79       const SerializedNavigationEntry& navigation,
     80       bool select) {
     81     service()->UpdateTabNavigation(window_id, tab_id, navigation);
     82     if (select) {
     83       service()->SetSelectedNavigationIndex(
     84           window_id, tab_id, navigation.index());
     85     }
     86   }
     87 
     88   void ReadWindows(std::vector<SessionWindow*>* windows,
     89                    SessionID::id_type* active_window_id) {
     90     // Forces closing the file.
     91     helper_.SetService(NULL);
     92 
     93     SessionService* session_service = new SessionService(path_);
     94     helper_.SetService(session_service);
     95 
     96     SessionID::id_type* non_null_active_window_id = active_window_id;
     97     SessionID::id_type dummy_active_window_id = 0;
     98     if (!non_null_active_window_id)
     99       non_null_active_window_id = &dummy_active_window_id;
    100     helper_.ReadWindows(windows, non_null_active_window_id);
    101   }
    102 
    103   // Configures the session service with one window with one tab and a single
    104   // navigation. If |pinned_state| is true or |write_always| is true, the
    105   // pinned state of the tab is updated. The session service is then recreated
    106   // and the pinned state of the read back tab is returned.
    107   bool CreateAndWriteSessionWithOneTab(bool pinned_state, bool write_always) {
    108     SessionID tab_id;
    109     SerializedNavigationEntry nav1 =
    110         SerializedNavigationEntryTestHelper::CreateNavigation(
    111             "http://google.com", "abc");
    112 
    113     helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    114     UpdateNavigation(window_id, tab_id, nav1, true);
    115 
    116     if (pinned_state || write_always)
    117       helper_.service()->SetPinnedState(window_id, tab_id, pinned_state);
    118 
    119     ScopedVector<SessionWindow> windows;
    120     ReadWindows(&(windows.get()), NULL);
    121 
    122     EXPECT_EQ(1U, windows.size());
    123     if (HasFatalFailure())
    124       return false;
    125     EXPECT_EQ(1U, windows[0]->tabs.size());
    126     if (HasFatalFailure())
    127       return false;
    128 
    129     SessionTab* tab = windows[0]->tabs[0];
    130     helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
    131 
    132     return tab->pinned;
    133   }
    134 
    135   void CreateAndWriteSessionWithTwoWindows(
    136       const SessionID& window2_id,
    137       const SessionID& tab1_id,
    138       const SessionID& tab2_id,
    139       SerializedNavigationEntry* nav1,
    140       SerializedNavigationEntry* nav2) {
    141     *nav1 = SerializedNavigationEntryTestHelper::CreateNavigation(
    142         "http://google.com", "abc");
    143     *nav2 = SerializedNavigationEntryTestHelper::CreateNavigation(
    144         "http://google2.com", "abcd");
    145 
    146     helper_.PrepareTabInWindow(window_id, tab1_id, 0, true);
    147     UpdateNavigation(window_id, tab1_id, *nav1, true);
    148 
    149     const gfx::Rect window2_bounds(3, 4, 5, 6);
    150     service()->SetWindowType(
    151         window2_id, Browser::TYPE_TABBED, SessionService::TYPE_NORMAL);
    152     service()->SetWindowBounds(window2_id,
    153                                window2_bounds,
    154                                ui::SHOW_STATE_MAXIMIZED);
    155     helper_.PrepareTabInWindow(window2_id, tab2_id, 0, true);
    156     UpdateNavigation(window2_id, tab2_id, *nav2, true);
    157   }
    158 
    159   SessionService* service() { return helper_.service(); }
    160 
    161   SessionBackend* backend() { return helper_.backend(); }
    162 
    163   const gfx::Rect window_bounds;
    164 
    165   SessionID window_id;
    166 
    167   int sync_save_count_;
    168 
    169   // Path used in testing.
    170   base::ScopedTempDir temp_dir_;
    171   base::FilePath path_;
    172 
    173   SessionServiceTestHelper helper_;
    174 };
    175 
    176 TEST_F(SessionServiceTest, Basic) {
    177   SessionID tab_id;
    178   ASSERT_NE(window_id.id(), tab_id.id());
    179 
    180   SerializedNavigationEntry nav1 =
    181       SerializedNavigationEntryTestHelper::CreateNavigation(
    182           "http://google.com", "abc");
    183   SerializedNavigationEntryTestHelper::SetOriginalRequestURL(
    184       GURL("http://original.request.com"), &nav1);
    185 
    186   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    187   UpdateNavigation(window_id, tab_id, nav1, true);
    188 
    189   ScopedVector<SessionWindow> windows;
    190   ReadWindows(&(windows.get()), NULL);
    191 
    192   ASSERT_EQ(1U, windows.size());
    193   ASSERT_TRUE(window_bounds == windows[0]->bounds);
    194   ASSERT_EQ(0, windows[0]->selected_tab_index);
    195   ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
    196   ASSERT_EQ(1U, windows[0]->tabs.size());
    197   ASSERT_EQ(Browser::TYPE_TABBED, windows[0]->type);
    198 
    199   SessionTab* tab = windows[0]->tabs[0];
    200   helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
    201 
    202   helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
    203 }
    204 
    205 // Make sure we persist post entries.
    206 TEST_F(SessionServiceTest, PersistPostData) {
    207   SessionID tab_id;
    208   ASSERT_NE(window_id.id(), tab_id.id());
    209 
    210   SerializedNavigationEntry nav1 =
    211       SerializedNavigationEntryTestHelper::CreateNavigation(
    212           "http://google.com", "abc");
    213   SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1);
    214 
    215   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    216   UpdateNavigation(window_id, tab_id, nav1, true);
    217 
    218   ScopedVector<SessionWindow> windows;
    219   ReadWindows(&(windows.get()), NULL);
    220 
    221   helper_.AssertSingleWindowWithSingleTab(windows.get(), 1);
    222 }
    223 
    224 TEST_F(SessionServiceTest, ClosingTabStaysClosed) {
    225   SessionID tab_id;
    226   SessionID tab2_id;
    227   ASSERT_NE(tab_id.id(), tab2_id.id());
    228 
    229   SerializedNavigationEntry nav1 =
    230       SerializedNavigationEntryTestHelper::CreateNavigation(
    231           "http://google.com", "abc");
    232   SerializedNavigationEntry nav2 =
    233       SerializedNavigationEntryTestHelper::CreateNavigation(
    234           "http://google2.com", "abcd");
    235 
    236   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    237   UpdateNavigation(window_id, tab_id, nav1, true);
    238 
    239   helper_.PrepareTabInWindow(window_id, tab2_id, 1, false);
    240   UpdateNavigation(window_id, tab2_id, nav2, true);
    241   service()->TabClosed(window_id, tab2_id, false);
    242 
    243   ScopedVector<SessionWindow> windows;
    244   ReadWindows(&(windows.get()), NULL);
    245 
    246   ASSERT_EQ(1U, windows.size());
    247   ASSERT_EQ(0, windows[0]->selected_tab_index);
    248   ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
    249   ASSERT_EQ(1U, windows[0]->tabs.size());
    250 
    251   SessionTab* tab = windows[0]->tabs[0];
    252   helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
    253 
    254   helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
    255 }
    256 
    257 TEST_F(SessionServiceTest, Pruning) {
    258   SessionID tab_id;
    259 
    260   SerializedNavigationEntry nav1 =
    261       SerializedNavigationEntryTestHelper::CreateNavigation(
    262           "http://google.com", "abc");
    263   SerializedNavigationEntry nav2 =
    264       SerializedNavigationEntryTestHelper::CreateNavigation(
    265           "http://google2.com", "abcd");
    266 
    267   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    268   for (int i = 0; i < 6; ++i) {
    269     SerializedNavigationEntry* nav = (i % 2) == 0 ? &nav1 : &nav2;
    270     nav->set_index(i);
    271     UpdateNavigation(window_id, tab_id, *nav, true);
    272   }
    273   service()->TabNavigationPathPrunedFromBack(window_id, tab_id, 3);
    274 
    275   ScopedVector<SessionWindow> windows;
    276   ReadWindows(&(windows.get()), NULL);
    277 
    278   ASSERT_EQ(1U, windows.size());
    279   ASSERT_EQ(0, windows[0]->selected_tab_index);
    280   ASSERT_EQ(1U, windows[0]->tabs.size());
    281 
    282   SessionTab* tab = windows[0]->tabs[0];
    283   // We left the selected index at 5, then pruned. When rereading the
    284   // index should get reset to last valid navigation, which is 2.
    285   helper_.AssertTabEquals(window_id, tab_id, 0, 2, 3, *tab);
    286 
    287   ASSERT_EQ(3u, tab->navigations.size());
    288   helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
    289   helper_.AssertNavigationEquals(nav2, tab->navigations[1]);
    290   helper_.AssertNavigationEquals(nav1, tab->navigations[2]);
    291 }
    292 
    293 TEST_F(SessionServiceTest, TwoWindows) {
    294   SessionID window2_id;
    295   SessionID tab1_id;
    296   SessionID tab2_id;
    297   SerializedNavigationEntry nav1;
    298   SerializedNavigationEntry nav2;
    299 
    300   CreateAndWriteSessionWithTwoWindows(
    301       window2_id, tab1_id, tab2_id, &nav1, &nav2);
    302 
    303   ScopedVector<SessionWindow> windows;
    304   ReadWindows(&(windows.get()), NULL);
    305 
    306   ASSERT_EQ(2U, windows.size());
    307   ASSERT_EQ(0, windows[0]->selected_tab_index);
    308   ASSERT_EQ(0, windows[1]->selected_tab_index);
    309   ASSERT_EQ(1U, windows[0]->tabs.size());
    310   ASSERT_EQ(1U, windows[1]->tabs.size());
    311 
    312   SessionTab* rt1;
    313   SessionTab* rt2;
    314   if (windows[0]->window_id.id() == window_id.id()) {
    315     ASSERT_EQ(window2_id.id(), windows[1]->window_id.id());
    316     ASSERT_EQ(ui::SHOW_STATE_NORMAL, windows[0]->show_state);
    317     ASSERT_EQ(ui::SHOW_STATE_MAXIMIZED, windows[1]->show_state);
    318     rt1 = windows[0]->tabs[0];
    319     rt2 = windows[1]->tabs[0];
    320   } else {
    321     ASSERT_EQ(window2_id.id(), windows[0]->window_id.id());
    322     ASSERT_EQ(window_id.id(), windows[1]->window_id.id());
    323     ASSERT_EQ(ui::SHOW_STATE_MAXIMIZED, windows[0]->show_state);
    324     ASSERT_EQ(ui::SHOW_STATE_NORMAL, windows[1]->show_state);
    325     rt1 = windows[1]->tabs[0];
    326     rt2 = windows[0]->tabs[0];
    327   }
    328   SessionTab* tab = rt1;
    329   helper_.AssertTabEquals(window_id, tab1_id, 0, 0, 1, *tab);
    330   helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
    331 
    332   tab = rt2;
    333   helper_.AssertTabEquals(window2_id, tab2_id, 0, 0, 1, *tab);
    334   helper_.AssertNavigationEquals(nav2, tab->navigations[0]);
    335 }
    336 
    337 TEST_F(SessionServiceTest, WindowWithNoTabsGetsPruned) {
    338   SessionID window2_id;
    339   SessionID tab1_id;
    340   SessionID tab2_id;
    341 
    342   SerializedNavigationEntry nav1 =
    343       SerializedNavigationEntryTestHelper::CreateNavigation(
    344           "http://google.com", "abc");
    345 
    346   helper_.PrepareTabInWindow(window_id, tab1_id, 0, true);
    347   UpdateNavigation(window_id, tab1_id, nav1, true);
    348 
    349   const gfx::Rect window2_bounds(3, 4, 5, 6);
    350   service()->SetWindowType(
    351       window2_id, Browser::TYPE_TABBED, SessionService::TYPE_NORMAL);
    352   service()->SetWindowBounds(window2_id,
    353                              window2_bounds,
    354                              ui::SHOW_STATE_NORMAL);
    355   helper_.PrepareTabInWindow(window2_id, tab2_id, 0, true);
    356 
    357   ScopedVector<SessionWindow> windows;
    358   ReadWindows(&(windows.get()), NULL);
    359 
    360   ASSERT_EQ(1U, windows.size());
    361   ASSERT_EQ(0, windows[0]->selected_tab_index);
    362   ASSERT_EQ(1U, windows[0]->tabs.size());
    363   ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
    364 
    365   SessionTab* tab = windows[0]->tabs[0];
    366   helper_.AssertTabEquals(window_id, tab1_id, 0, 0, 1, *tab);
    367   helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
    368 }
    369 
    370 TEST_F(SessionServiceTest, ClosingWindowDoesntCloseTabs) {
    371   SessionID tab_id;
    372   SessionID tab2_id;
    373   ASSERT_NE(tab_id.id(), tab2_id.id());
    374 
    375   SerializedNavigationEntry nav1 =
    376       SerializedNavigationEntryTestHelper::CreateNavigation(
    377           "http://google.com", "abc");
    378   SerializedNavigationEntry nav2 =
    379       SerializedNavigationEntryTestHelper::CreateNavigation(
    380           "http://google2.com", "abcd");
    381 
    382   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    383   UpdateNavigation(window_id, tab_id, nav1, true);
    384 
    385   helper_.PrepareTabInWindow(window_id, tab2_id, 1, false);
    386   UpdateNavigation(window_id, tab2_id, nav2, true);
    387 
    388   service()->WindowClosing(window_id);
    389 
    390   ScopedVector<SessionWindow> windows;
    391   ReadWindows(&(windows.get()), NULL);
    392 
    393   ASSERT_EQ(1U, windows.size());
    394   ASSERT_EQ(0, windows[0]->selected_tab_index);
    395   ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
    396   ASSERT_EQ(2U, windows[0]->tabs.size());
    397 
    398   SessionTab* tab = windows[0]->tabs[0];
    399   helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
    400   helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
    401 
    402   tab = windows[0]->tabs[1];
    403   helper_.AssertTabEquals(window_id, tab2_id, 1, 0, 1, *tab);
    404   helper_.AssertNavigationEquals(nav2, tab->navigations[0]);
    405 }
    406 
    407 TEST_F(SessionServiceTest, WindowCloseCommittedAfterNavigate) {
    408   SessionID window2_id;
    409   SessionID tab_id;
    410   SessionID tab2_id;
    411   ASSERT_NE(window2_id.id(), window_id.id());
    412 
    413   service()->SetWindowType(
    414       window2_id, Browser::TYPE_TABBED, SessionService::TYPE_NORMAL);
    415   service()->SetWindowBounds(window2_id,
    416                              window_bounds,
    417                              ui::SHOW_STATE_NORMAL);
    418 
    419   SerializedNavigationEntry nav1 =
    420       SerializedNavigationEntryTestHelper::CreateNavigation(
    421           "http://google.com", "abc");
    422   SerializedNavigationEntry nav2 =
    423       SerializedNavigationEntryTestHelper::CreateNavigation(
    424           "http://google2.com", "abcd");
    425 
    426   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    427   UpdateNavigation(window_id, tab_id, nav1, true);
    428 
    429   helper_.PrepareTabInWindow(window2_id, tab2_id, 0, false);
    430   UpdateNavigation(window2_id, tab2_id, nav2, true);
    431 
    432   service()->WindowClosing(window2_id);
    433   service()->TabClosed(window2_id, tab2_id, false);
    434   service()->WindowClosed(window2_id);
    435 
    436   ScopedVector<SessionWindow> windows;
    437   ReadWindows(&(windows.get()), NULL);
    438 
    439   ASSERT_EQ(1U, windows.size());
    440   ASSERT_EQ(0, windows[0]->selected_tab_index);
    441   ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
    442   ASSERT_EQ(1U, windows[0]->tabs.size());
    443 
    444   SessionTab* tab = windows[0]->tabs[0];
    445   helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
    446   helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
    447 }
    448 
    449 // Makes sure we don't track popups.
    450 TEST_F(SessionServiceTest, IgnorePopups) {
    451   if (browser_defaults::kRestorePopups)
    452     return;  // This test is only applicable if popups aren't restored.
    453 
    454   SessionID window2_id;
    455   SessionID tab_id;
    456   SessionID tab2_id;
    457   ASSERT_NE(window2_id.id(), window_id.id());
    458 
    459   service()->SetWindowType(
    460       window2_id, Browser::TYPE_POPUP, SessionService::TYPE_NORMAL);
    461   service()->SetWindowBounds(window2_id,
    462                              window_bounds,
    463                              ui::SHOW_STATE_NORMAL);
    464 
    465   SerializedNavigationEntry nav1 =
    466       SerializedNavigationEntryTestHelper::CreateNavigation(
    467           "http://google.com", "abc");
    468   SerializedNavigationEntry nav2 =
    469       SerializedNavigationEntryTestHelper::CreateNavigation(
    470           "http://google2.com", "abcd");
    471 
    472   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    473   UpdateNavigation(window_id, tab_id, nav1, true);
    474 
    475   helper_.PrepareTabInWindow(window2_id, tab2_id, 0, false);
    476   UpdateNavigation(window2_id, tab2_id, nav2, true);
    477 
    478   ScopedVector<SessionWindow> windows;
    479   ReadWindows(&(windows.get()), NULL);
    480 
    481   ASSERT_EQ(1U, windows.size());
    482   ASSERT_EQ(0, windows[0]->selected_tab_index);
    483   ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
    484   ASSERT_EQ(1U, windows[0]->tabs.size());
    485 
    486   SessionTab* tab = windows[0]->tabs[0];
    487   helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
    488   helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
    489 }
    490 
    491 // Makes sure we track popups.
    492 TEST_F(SessionServiceTest, RestorePopup) {
    493   if (!browser_defaults::kRestorePopups)
    494     return;  // This test is only applicable if popups are restored.
    495 
    496   SessionID window2_id;
    497   SessionID tab_id;
    498   SessionID tab2_id;
    499   ASSERT_NE(window2_id.id(), window_id.id());
    500 
    501   service()->SetWindowType(
    502       window2_id, Browser::TYPE_POPUP, SessionService::TYPE_NORMAL);
    503   service()->SetWindowBounds(window2_id,
    504                              window_bounds,
    505                              ui::SHOW_STATE_NORMAL);
    506 
    507   SerializedNavigationEntry nav1 =
    508       SerializedNavigationEntryTestHelper::CreateNavigation(
    509           "http://google.com", "abc");
    510   SerializedNavigationEntry nav2 =
    511       SerializedNavigationEntryTestHelper::CreateNavigation(
    512           "http://google2.com", "abcd");
    513 
    514   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    515   UpdateNavigation(window_id, tab_id, nav1, true);
    516 
    517   helper_.PrepareTabInWindow(window2_id, tab2_id, 0, false);
    518   UpdateNavigation(window2_id, tab2_id, nav2, true);
    519 
    520   ScopedVector<SessionWindow> windows;
    521   ReadWindows(&(windows.get()), NULL);
    522 
    523   ASSERT_EQ(2U, windows.size());
    524   int tabbed_index = windows[0]->type == Browser::TYPE_TABBED ?
    525       0 : 1;
    526   int popup_index = tabbed_index == 0 ? 1 : 0;
    527   ASSERT_EQ(0, windows[tabbed_index]->selected_tab_index);
    528   ASSERT_EQ(window_id.id(), windows[tabbed_index]->window_id.id());
    529   ASSERT_EQ(1U, windows[tabbed_index]->tabs.size());
    530 
    531   SessionTab* tab = windows[tabbed_index]->tabs[0];
    532   helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
    533   helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
    534 
    535   ASSERT_EQ(0, windows[popup_index]->selected_tab_index);
    536   ASSERT_EQ(window2_id.id(), windows[popup_index]->window_id.id());
    537   ASSERT_EQ(1U, windows[popup_index]->tabs.size());
    538 
    539   tab = windows[popup_index]->tabs[0];
    540   helper_.AssertTabEquals(window2_id, tab2_id, 0, 0, 1, *tab);
    541   helper_.AssertNavigationEquals(nav2, tab->navigations[0]);
    542 }
    543 
    544 #if defined (OS_CHROMEOS)
    545 // Makes sure we track apps. Only applicable on chromeos.
    546 TEST_F(SessionServiceTest, RestoreApp) {
    547   SessionID window2_id;
    548   SessionID tab_id;
    549   SessionID tab2_id;
    550   ASSERT_NE(window2_id.id(), window_id.id());
    551 
    552   service()->SetWindowType(
    553       window2_id, Browser::TYPE_POPUP, SessionService::TYPE_APP);
    554   service()->SetWindowBounds(window2_id,
    555                              window_bounds,
    556                              ui::SHOW_STATE_NORMAL);
    557   service()->SetWindowAppName(window2_id, "TestApp");
    558 
    559   SerializedNavigationEntry nav1 =
    560       SerializedNavigationEntryTestHelper::CreateNavigation(
    561           "http://google.com", "abc");
    562   SerializedNavigationEntry nav2 =
    563       SerializedNavigationEntryTestHelper::CreateNavigation(
    564           "http://google2.com", "abcd");
    565 
    566   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    567   UpdateNavigation(window_id, tab_id, nav1, true);
    568 
    569   helper_.PrepareTabInWindow(window2_id, tab2_id, 0, false);
    570   UpdateNavigation(window2_id, tab2_id, nav2, true);
    571 
    572   ScopedVector<SessionWindow> windows;
    573   ReadWindows(&(windows.get()), NULL);
    574 
    575   ASSERT_EQ(2U, windows.size());
    576   int tabbed_index = windows[0]->type == Browser::TYPE_TABBED ?
    577       0 : 1;
    578   int app_index = tabbed_index == 0 ? 1 : 0;
    579   ASSERT_EQ(0, windows[tabbed_index]->selected_tab_index);
    580   ASSERT_EQ(window_id.id(), windows[tabbed_index]->window_id.id());
    581   ASSERT_EQ(1U, windows[tabbed_index]->tabs.size());
    582 
    583   SessionTab* tab = windows[tabbed_index]->tabs[0];
    584   helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
    585   helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
    586 
    587   ASSERT_EQ(0, windows[app_index]->selected_tab_index);
    588   ASSERT_EQ(window2_id.id(), windows[app_index]->window_id.id());
    589   ASSERT_EQ(1U, windows[app_index]->tabs.size());
    590   ASSERT_TRUE(windows[app_index]->type == Browser::TYPE_POPUP);
    591   ASSERT_EQ("TestApp", windows[app_index]->app_name);
    592 
    593   tab = windows[app_index]->tabs[0];
    594   helper_.AssertTabEquals(window2_id, tab2_id, 0, 0, 1, *tab);
    595   helper_.AssertNavigationEquals(nav2, tab->navigations[0]);
    596 }
    597 #endif  // defined (OS_CHROMEOS)
    598 
    599 // Tests pruning from the front.
    600 TEST_F(SessionServiceTest, PruneFromFront) {
    601   const std::string base_url("http://google.com/");
    602   SessionID tab_id;
    603 
    604   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    605 
    606   // Add 5 navigations, with the 4th selected.
    607   for (int i = 0; i < 5; ++i) {
    608     SerializedNavigationEntry nav =
    609         SerializedNavigationEntryTestHelper::CreateNavigation(
    610             base_url + base::IntToString(i), "a");
    611     nav.set_index(i);
    612     UpdateNavigation(window_id, tab_id, nav, (i == 3));
    613   }
    614 
    615   // Prune the first two navigations from the front.
    616   helper_.service()->TabNavigationPathPrunedFromFront(window_id, tab_id, 2);
    617 
    618   // Read back in.
    619   ScopedVector<SessionWindow> windows;
    620   ReadWindows(&(windows.get()), NULL);
    621 
    622   ASSERT_EQ(1U, windows.size());
    623   ASSERT_EQ(0, windows[0]->selected_tab_index);
    624   ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
    625   ASSERT_EQ(1U, windows[0]->tabs.size());
    626 
    627   // There shouldn't be an app id.
    628   EXPECT_TRUE(windows[0]->tabs[0]->extension_app_id.empty());
    629 
    630   // We should be left with three navigations, the 2nd selected.
    631   SessionTab* tab = windows[0]->tabs[0];
    632   ASSERT_EQ(1, tab->current_navigation_index);
    633   EXPECT_EQ(3U, tab->navigations.size());
    634   EXPECT_TRUE(GURL(base_url + base::IntToString(2)) ==
    635               tab->navigations[0].virtual_url());
    636   EXPECT_TRUE(GURL(base_url + base::IntToString(3)) ==
    637               tab->navigations[1].virtual_url());
    638   EXPECT_TRUE(GURL(base_url + base::IntToString(4)) ==
    639               tab->navigations[2].virtual_url());
    640 }
    641 
    642 // Prunes from front so that we have no entries.
    643 TEST_F(SessionServiceTest, PruneToEmpty) {
    644   const std::string base_url("http://google.com/");
    645   SessionID tab_id;
    646 
    647   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    648 
    649   // Add 5 navigations, with the 4th selected.
    650   for (int i = 0; i < 5; ++i) {
    651     SerializedNavigationEntry nav =
    652         SerializedNavigationEntryTestHelper::CreateNavigation(
    653             base_url + base::IntToString(i), "a");
    654     nav.set_index(i);
    655     UpdateNavigation(window_id, tab_id, nav, (i == 3));
    656   }
    657 
    658   // Prune the first two navigations from the front.
    659   helper_.service()->TabNavigationPathPrunedFromFront(window_id, tab_id, 5);
    660 
    661   // Read back in.
    662   ScopedVector<SessionWindow> windows;
    663   ReadWindows(&(windows.get()), NULL);
    664 
    665   ASSERT_EQ(0U, windows.size());
    666 }
    667 
    668 // Don't set the pinned state and make sure the pinned value is false.
    669 TEST_F(SessionServiceTest, PinnedDefaultsToFalse) {
    670   EXPECT_FALSE(CreateAndWriteSessionWithOneTab(false, false));
    671 }
    672 
    673 // Explicitly set the pinned state to false and make sure we get back false.
    674 TEST_F(SessionServiceTest, PinnedFalseWhenSetToFalse) {
    675   EXPECT_FALSE(CreateAndWriteSessionWithOneTab(false, true));
    676 }
    677 
    678 // Explicitly set the pinned state to true and make sure we get back true.
    679 TEST_F(SessionServiceTest, PinnedTrue) {
    680   EXPECT_TRUE(CreateAndWriteSessionWithOneTab(true, true));
    681 }
    682 
    683 // Make sure application extension ids are persisted.
    684 TEST_F(SessionServiceTest, PersistApplicationExtensionID) {
    685   SessionID tab_id;
    686   ASSERT_NE(window_id.id(), tab_id.id());
    687   std::string app_id("foo");
    688 
    689   SerializedNavigationEntry nav1 =
    690       SerializedNavigationEntryTestHelper::CreateNavigation(
    691           "http://google.com", "abc");
    692 
    693   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    694   UpdateNavigation(window_id, tab_id, nav1, true);
    695   helper_.SetTabExtensionAppID(window_id, tab_id, app_id);
    696 
    697   ScopedVector<SessionWindow> windows;
    698   ReadWindows(&(windows.get()), NULL);
    699 
    700   helper_.AssertSingleWindowWithSingleTab(windows.get(), 1);
    701   EXPECT_TRUE(app_id == windows[0]->tabs[0]->extension_app_id);
    702 }
    703 
    704 // Check that user agent overrides are persisted.
    705 TEST_F(SessionServiceTest, PersistUserAgentOverrides) {
    706   SessionID tab_id;
    707   ASSERT_NE(window_id.id(), tab_id.id());
    708   std::string user_agent_override = "Mozilla/5.0 (X11; Linux x86_64) "
    709       "AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.45 "
    710       "Safari/535.19";
    711 
    712   SerializedNavigationEntry nav1 =
    713       SerializedNavigationEntryTestHelper::CreateNavigation(
    714           "http://google.com", "abc");
    715   SerializedNavigationEntryTestHelper::SetIsOverridingUserAgent(true, &nav1);
    716 
    717   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    718   UpdateNavigation(window_id, tab_id, nav1, true);
    719   helper_.SetTabUserAgentOverride(window_id, tab_id, user_agent_override);
    720 
    721   ScopedVector<SessionWindow> windows;
    722   ReadWindows(&(windows.get()), NULL);
    723   helper_.AssertSingleWindowWithSingleTab(windows.get(), 1);
    724 
    725   SessionTab* tab = windows[0]->tabs[0];
    726   helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
    727   helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
    728   EXPECT_TRUE(user_agent_override == tab->user_agent_override);
    729 }
    730 
    731 // Test that the notification for SESSION_SERVICE_SAVED is working properly.
    732 TEST_F(SessionServiceTest, SavedSessionNotification) {
    733   content::NotificationRegistrar registrar_;
    734   registrar_.Add(this, chrome::NOTIFICATION_SESSION_SERVICE_SAVED,
    735                  content::NotificationService::AllSources());
    736   service()->Save();
    737   EXPECT_EQ(sync_save_count_, 1);
    738 }
    739 
    740 // Makes sure a tab closed by a user gesture is not restored.
    741 TEST_F(SessionServiceTest, CloseTabUserGesture) {
    742   SessionID tab_id;
    743   ASSERT_NE(window_id.id(), tab_id.id());
    744 
    745   SerializedNavigationEntry nav1 =
    746       SerializedNavigationEntryTestHelper::CreateNavigation(
    747           "http://google.com", "abc");
    748 
    749   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    750   UpdateNavigation(window_id, tab_id, nav1, true);
    751   service()->TabClosed(window_id, tab_id, true);
    752 
    753   ScopedVector<SessionWindow> windows;
    754   ReadWindows(&(windows.get()), NULL);
    755 
    756   ASSERT_TRUE(windows.empty());
    757 }
    758 
    759 // Verifies SetWindowBounds maps SHOW_STATE_DEFAULT to SHOW_STATE_NORMAL.
    760 TEST_F(SessionServiceTest, DontPersistDefault) {
    761   SessionID tab_id;
    762   ASSERT_NE(window_id.id(), tab_id.id());
    763   SerializedNavigationEntry nav1 =
    764       SerializedNavigationEntryTestHelper::CreateNavigation(
    765           "http://google.com", "abc");
    766   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    767   UpdateNavigation(window_id, tab_id, nav1, true);
    768   service()->SetWindowBounds(window_id,
    769                              window_bounds,
    770                              ui::SHOW_STATE_DEFAULT);
    771 
    772   ScopedVector<SessionWindow> windows;
    773   ReadWindows(&(windows.get()), NULL);
    774   ASSERT_EQ(1U, windows.size());
    775   EXPECT_EQ(ui::SHOW_STATE_NORMAL, windows[0]->show_state);
    776 }
    777 
    778 TEST_F(SessionServiceTest, KeepPostDataWithoutPasswords) {
    779   SessionID tab_id;
    780   ASSERT_NE(window_id.id(), tab_id.id());
    781 
    782   // Create a page state representing a HTTP body without posted passwords.
    783   content::PageState page_state =
    784       content::PageState::CreateForTesting(GURL(), false, "data", NULL);
    785 
    786   // Create a TabNavigation containing page_state and representing a POST
    787   // request.
    788   SerializedNavigationEntry nav1 =
    789       SerializedNavigationEntryTestHelper::CreateNavigation(
    790           "http://google.com", "title");
    791   SerializedNavigationEntryTestHelper::SetPageState(page_state, &nav1);
    792   SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1);
    793 
    794   // Create a TabNavigation containing page_state and representing a normal
    795   // request.
    796   SerializedNavigationEntry nav2 =
    797       SerializedNavigationEntryTestHelper::CreateNavigation(
    798           "http://google.com/nopost", "title");
    799   SerializedNavigationEntryTestHelper::SetPageState(page_state, &nav2);
    800   nav2.set_index(1);
    801 
    802   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    803   UpdateNavigation(window_id, tab_id, nav1, true);
    804   UpdateNavigation(window_id, tab_id, nav2, true);
    805 
    806   ScopedVector<SessionWindow> windows;
    807   ReadWindows(&(windows.get()), NULL);
    808 
    809   helper_.AssertSingleWindowWithSingleTab(windows.get(), 2);
    810 
    811   // Expected: the page state of both navigations was saved and restored.
    812   ASSERT_EQ(2u, windows[0]->tabs[0]->navigations.size());
    813   helper_.AssertNavigationEquals(nav1, windows[0]->tabs[0]->navigations[0]);
    814   helper_.AssertNavigationEquals(nav2, windows[0]->tabs[0]->navigations[1]);
    815 }
    816 
    817 TEST_F(SessionServiceTest, RemovePostDataWithPasswords) {
    818   SessionID tab_id;
    819   ASSERT_NE(window_id.id(), tab_id.id());
    820 
    821   // Create a page state representing a HTTP body with posted passwords.
    822   content::PageState page_state =
    823       content::PageState::CreateForTesting(GURL(), true, "data", NULL);
    824 
    825   // Create a TabNavigation containing page_state and representing a POST
    826   // request with passwords.
    827   SerializedNavigationEntry nav1 =
    828       SerializedNavigationEntryTestHelper::CreateNavigation(
    829           "http://google.com", "title");
    830   SerializedNavigationEntryTestHelper::SetPageState(page_state, &nav1);
    831   SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1);
    832   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    833   UpdateNavigation(window_id, tab_id, nav1, true);
    834 
    835   ScopedVector<SessionWindow> windows;
    836   ReadWindows(&(windows.get()), NULL);
    837 
    838   helper_.AssertSingleWindowWithSingleTab(windows.get(), 1);
    839 
    840   // Expected: the HTTP body was removed from the page state of the POST
    841   // navigation with passwords.
    842   EXPECT_NE(page_state, windows[0]->tabs[0]->navigations[0].page_state());
    843 }
    844 
    845 // This test is only applicable to chromeos.
    846 #if defined(OS_CHROMEOS)
    847 // Verifies migration of tab/window closed works.
    848 TEST_F(SessionServiceTest, CanOpenV1TabClosed) {
    849   base::FilePath v1_file_path;
    850   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &v1_file_path));
    851   // v1_session_file contains a tab closed command with the original id. The
    852   // file was generated from ClosingTabStaysClosed. If we successfully processed
    853   // the file we'll have one tab.
    854   v1_file_path =
    855       v1_file_path.AppendASCII("sessions").AppendASCII("v1_session_file");
    856   base::FilePath dest_file_path(path_);
    857   dest_file_path = dest_file_path.AppendASCII("Current Session");
    858 
    859   // Forces closing the file.
    860   helper_.SetService(NULL);
    861 
    862   ASSERT_TRUE(base::CopyFile(v1_file_path, dest_file_path));
    863 
    864   SessionService* session_service = new SessionService(path_);
    865   helper_.SetService(session_service);
    866   ScopedVector<SessionWindow> windows;
    867   SessionID::id_type active_window_id = 0;
    868   helper_.ReadWindows(&(windows.get()), &active_window_id);
    869   ASSERT_EQ(1u, windows.size());
    870   EXPECT_EQ(1u, windows[0]->tabs.size());
    871 }
    872 #endif  // defined(OS_CHROMEOS)
    873 
    874 TEST_F(SessionServiceTest, ReplacePendingNavigation) {
    875   const std::string base_url("http://google.com/");
    876   SessionID tab_id;
    877 
    878   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    879 
    880   // Add 5 navigations, some with the same index
    881   for (int i = 0; i < 5; ++i) {
    882     SerializedNavigationEntry nav =
    883         SerializedNavigationEntryTestHelper::CreateNavigation(
    884             base_url + base::IntToString(i), "a");
    885     nav.set_index(i / 2);
    886     UpdateNavigation(window_id, tab_id, nav, true);
    887   }
    888 
    889   // Read back in.
    890   ScopedVector<SessionWindow> windows;
    891   ReadWindows(&(windows.get()), NULL);
    892 
    893   // The ones with index 0, and 2 should have been replaced by 1 and 3.
    894   ASSERT_EQ(1U, windows.size());
    895   ASSERT_EQ(1U, windows[0]->tabs.size());
    896   EXPECT_EQ(3U, windows[0]->tabs[0]->navigations.size());
    897   EXPECT_EQ(GURL(base_url + base::IntToString(1)),
    898             windows[0]->tabs[0]->navigations[0].virtual_url());
    899   EXPECT_EQ(GURL(base_url + base::IntToString(3)),
    900             windows[0]->tabs[0]->navigations[1].virtual_url());
    901   EXPECT_EQ(GURL(base_url + base::IntToString(4)),
    902             windows[0]->tabs[0]->navigations[2].virtual_url());
    903 }
    904 
    905 TEST_F(SessionServiceTest, ReplacePendingNavigationAndPrune) {
    906   const std::string base_url("http://google.com/");
    907   SessionID tab_id;
    908 
    909   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
    910 
    911   for (int i = 0; i < 5; ++i) {
    912     SerializedNavigationEntry nav =
    913         SerializedNavigationEntryTestHelper::CreateNavigation(
    914             base_url + base::IntToString(i), "a");
    915     nav.set_index(i);
    916     UpdateNavigation(window_id, tab_id, nav, true);
    917   }
    918 
    919   // Prune all those navigations.
    920   helper_.service()->TabNavigationPathPrunedFromFront(window_id, tab_id, 5);
    921 
    922   // Add another navigation to replace the last one.
    923   SerializedNavigationEntry nav =
    924       SerializedNavigationEntryTestHelper::CreateNavigation(
    925         base_url + base::IntToString(5), "a");
    926   nav.set_index(4);
    927   UpdateNavigation(window_id, tab_id, nav, true);
    928 
    929   // Read back in.
    930   ScopedVector<SessionWindow> windows;
    931   ReadWindows(&(windows.get()), NULL);
    932 
    933   // We should still have that last navigation at the end,
    934   // even though it replaced one that was set before the prune.
    935   ASSERT_EQ(1U, windows.size());
    936   ASSERT_EQ(1U, windows[0]->tabs.size());
    937   ASSERT_EQ(1U, windows[0]->tabs[0]->navigations.size());
    938   EXPECT_EQ(GURL(base_url + base::IntToString(5)),
    939             windows[0]->tabs[0]->navigations[0].virtual_url());
    940 }
    941 
    942 TEST_F(SessionServiceTest, RestoreActivation1) {
    943   SessionID window2_id;
    944   SessionID tab1_id;
    945   SessionID tab2_id;
    946   SerializedNavigationEntry nav1;
    947   SerializedNavigationEntry nav2;
    948 
    949   CreateAndWriteSessionWithTwoWindows(
    950       window2_id, tab1_id, tab2_id, &nav1, &nav2);
    951 
    952   service()->ScheduleCommand(
    953       service()->CreateSetActiveWindowCommand(window2_id));
    954   service()->ScheduleCommand(
    955       service()->CreateSetActiveWindowCommand(window_id));
    956 
    957   ScopedVector<SessionWindow> windows;
    958   SessionID::id_type active_window_id = 0;
    959   ReadWindows(&(windows.get()), &active_window_id);
    960   EXPECT_EQ(window_id.id(), active_window_id);
    961 }
    962 
    963 // It's easier to have two separate tests with setup/teardown than to manualy
    964 // reset the state for the different flavors of the test.
    965 TEST_F(SessionServiceTest, RestoreActivation2) {
    966   SessionID window2_id;
    967   SessionID tab1_id;
    968   SessionID tab2_id;
    969   SerializedNavigationEntry nav1;
    970   SerializedNavigationEntry nav2;
    971 
    972   CreateAndWriteSessionWithTwoWindows(
    973       window2_id, tab1_id, tab2_id, &nav1, &nav2);
    974 
    975   service()->ScheduleCommand(
    976       service()->CreateSetActiveWindowCommand(window2_id));
    977   service()->ScheduleCommand(
    978       service()->CreateSetActiveWindowCommand(window_id));
    979   service()->ScheduleCommand(
    980       service()->CreateSetActiveWindowCommand(window2_id));
    981 
    982   ScopedVector<SessionWindow> windows;
    983   SessionID::id_type active_window_id = 0;
    984   ReadWindows(&(windows.get()), &active_window_id);
    985   EXPECT_EQ(window2_id.id(), active_window_id);
    986 }
    987 
    988 // Makes sure we don't track blacklisted URLs.
    989 TEST_F(SessionServiceTest, IgnoreBlacklistedUrls) {
    990   SessionID tab_id;
    991 
    992   SerializedNavigationEntry nav1 =
    993       SerializedNavigationEntryTestHelper::CreateNavigation(
    994           "http://google.com", "abc");
    995   SerializedNavigationEntry nav2 =
    996       SerializedNavigationEntryTestHelper::CreateNavigation(
    997           chrome::kChromeUIQuitURL, "quit");
    998   SerializedNavigationEntry nav3 =
    999       SerializedNavigationEntryTestHelper::CreateNavigation(
   1000           chrome::kChromeUIRestartURL, "restart");
   1001 
   1002   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
   1003   UpdateNavigation(window_id, tab_id, nav1, true);
   1004   UpdateNavigation(window_id, tab_id, nav2, true);
   1005   UpdateNavigation(window_id, tab_id, nav3, true);
   1006 
   1007   ScopedVector<SessionWindow> windows;
   1008   ReadWindows(&(windows.get()), NULL);
   1009 
   1010   ASSERT_EQ(1U, windows.size());
   1011   ASSERT_EQ(0, windows[0]->selected_tab_index);
   1012   ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
   1013   ASSERT_EQ(1U, windows[0]->tabs.size());
   1014 
   1015   SessionTab* tab = windows[0]->tabs[0];
   1016   helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
   1017   helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
   1018 }
   1019