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