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