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