1// Copyright (c) 2011 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/file_util.h"
6#include "base/memory/scoped_ptr.h"
7#include "base/memory/scoped_vector.h"
8#include "base/memory/scoped_temp_dir.h"
9#include "base/path_service.h"
10#include "base/stl_util-inl.h"
11#include "base/string_number_conversions.h"
12#include "base/time.h"
13#include "base/utf_string_conversions.h"
14#include "chrome/browser/defaults.h"
15#include "chrome/browser/sessions/session_backend.h"
16#include "chrome/browser/sessions/session_service.h"
17#include "chrome/browser/sessions/session_service_test_helper.h"
18#include "chrome/browser/sessions/session_types.h"
19#include "chrome/common/chrome_paths.h"
20#include "chrome/test/browser_with_test_window_test.h"
21#include "chrome/test/file_test_utils.h"
22#include "chrome/test/testing_profile.h"
23#include "content/browser/tab_contents/navigation_entry.h"
24#include "content/common/notification_observer.h"
25#include "content/common/notification_registrar.h"
26#include "content/common/notification_service.h"
27#include "content/common/notification_type.h"
28#include "testing/gtest/include/gtest/gtest.h"
29
30class SessionServiceTest : public BrowserWithTestWindowTest,
31                           public NotificationObserver {
32 public:
33  SessionServiceTest() : window_bounds(0, 1, 2, 3), sync_save_count_(0){}
34
35 protected:
36  virtual void SetUp() {
37    BrowserWithTestWindowTest::SetUp();
38    std::string b = base::Int64ToString(base::Time::Now().ToInternalValue());
39
40    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
41    path_ = temp_dir_.path().Append(FILE_PATH_LITERAL("SessionTestDirs"));
42    file_util::CreateDirectory(path_);
43    path_deleter_.reset(new FileAutoDeleter(path_));
44    path_ = path_.AppendASCII(b);
45
46    SessionService* session_service = new SessionService(path_);
47    helper_.set_service(session_service);
48
49    service()->SetWindowType(window_id, Browser::TYPE_NORMAL);
50    service()->SetWindowBounds(window_id, window_bounds, false);
51  }
52
53  // Upon notification, increment the sync_save_count variable
54  void Observe(NotificationType type,
55               const NotificationSource& source,
56               const NotificationDetails& details) {
57    ASSERT_EQ(type.value, NotificationType::SESSION_SERVICE_SAVED);
58    sync_save_count_++;
59  }
60
61  virtual void TearDown() {
62    helper_.set_service(NULL);
63    path_deleter_.reset();
64  }
65
66  void UpdateNavigation(const SessionID& window_id,
67                        const SessionID& tab_id,
68                        const TabNavigation& navigation,
69                        int index,
70                        bool select) {
71    NavigationEntry entry;
72    entry.set_url(navigation.virtual_url());
73    entry.set_referrer(navigation.referrer());
74    entry.set_title(navigation.title());
75    entry.set_content_state(navigation.state());
76    entry.set_transition_type(navigation.transition());
77    entry.set_has_post_data(
78        navigation.type_mask() & TabNavigation::HAS_POST_DATA);
79    service()->UpdateTabNavigation(window_id, tab_id, index, entry);
80    if (select)
81      service()->SetSelectedNavigationIndex(window_id, tab_id, index);
82  }
83
84  void ReadWindows(std::vector<SessionWindow*>* windows) {
85    // Forces closing the file.
86    helper_.set_service(NULL);
87
88    SessionService* session_service = new SessionService(path_);
89    helper_.set_service(session_service);
90    helper_.ReadWindows(windows);
91  }
92
93  // Configures the session service with one window with one tab and a single
94  // navigation. If |pinned_state| is true or |write_always| is true, the
95  // pinned state of the tab is updated. The session service is then recreated
96  // and the pinned state of the read back tab is returned.
97  bool CreateAndWriteSessionWithOneTab(bool pinned_state, bool write_always) {
98    SessionID tab_id;
99    TabNavigation nav1(0, GURL("http://google.com"),
100                       GURL("http://www.referrer.com"),
101                       ASCIIToUTF16("abc"), "def",
102                       PageTransition::QUALIFIER_MASK);
103
104    helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
105    UpdateNavigation(window_id, tab_id, nav1, 0, true);
106
107    if (pinned_state || write_always)
108      helper_.service()->SetPinnedState(window_id, tab_id, pinned_state);
109
110    ScopedVector<SessionWindow> windows;
111    ReadWindows(&(windows.get()));
112
113    EXPECT_EQ(1U, windows->size());
114    if (HasFatalFailure())
115      return false;
116    EXPECT_EQ(1U, windows[0]->tabs.size());
117    if (HasFatalFailure())
118      return false;
119
120    SessionTab* tab = windows[0]->tabs[0];
121    helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
122
123    return tab->pinned;
124  }
125
126  SessionService* service() { return helper_.service(); }
127
128  SessionBackend* backend() { return helper_.backend(); }
129
130  const gfx::Rect window_bounds;
131
132  SessionID window_id;
133
134  int sync_save_count_;
135
136  // Path used in testing.
137  ScopedTempDir temp_dir_;
138  FilePath path_;
139  scoped_ptr<FileAutoDeleter> path_deleter_;
140
141  SessionServiceTestHelper helper_;
142};
143
144TEST_F(SessionServiceTest, Basic) {
145  SessionID tab_id;
146  ASSERT_NE(window_id.id(), tab_id.id());
147
148  TabNavigation nav1(0, GURL("http://google.com"),
149                     GURL("http://www.referrer.com"),
150                     ASCIIToUTF16("abc"), "def",
151                     PageTransition::QUALIFIER_MASK);
152
153  helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
154  UpdateNavigation(window_id, tab_id, nav1, 0, true);
155
156  ScopedVector<SessionWindow> windows;
157  ReadWindows(&(windows.get()));
158
159  ASSERT_EQ(1U, windows->size());
160  ASSERT_TRUE(window_bounds == windows[0]->bounds);
161  ASSERT_EQ(0, windows[0]->selected_tab_index);
162  ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
163  ASSERT_EQ(1U, windows[0]->tabs.size());
164  ASSERT_EQ(Browser::TYPE_NORMAL, windows[0]->type);
165
166  SessionTab* tab = windows[0]->tabs[0];
167  helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
168
169  helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
170}
171
172// Make sure we persist post entries.
173TEST_F(SessionServiceTest, PersistPostData) {
174  SessionID tab_id;
175  ASSERT_NE(window_id.id(), tab_id.id());
176
177  TabNavigation nav1(0, GURL("http://google.com"), GURL(),
178                     ASCIIToUTF16("abc"), std::string(),
179                     PageTransition::QUALIFIER_MASK);
180  nav1.set_type_mask(TabNavigation::HAS_POST_DATA);
181
182  helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
183  UpdateNavigation(window_id, tab_id, nav1, 0, true);
184
185  ScopedVector<SessionWindow> windows;
186  ReadWindows(&(windows.get()));
187
188  helper_.AssertSingleWindowWithSingleTab(windows.get(), 1);
189}
190
191TEST_F(SessionServiceTest, ClosingTabStaysClosed) {
192  SessionID tab_id;
193  SessionID tab2_id;
194  ASSERT_NE(tab_id.id(), tab2_id.id());
195
196  TabNavigation nav1(0, GURL("http://google.com"), GURL(),
197                     ASCIIToUTF16("abc"), "def",
198                     PageTransition::QUALIFIER_MASK);
199  TabNavigation nav2(0, GURL("http://google2.com"), GURL(),
200                     ASCIIToUTF16("abcd"), "defg",
201                     PageTransition::AUTO_BOOKMARK);
202
203  helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
204  UpdateNavigation(window_id, tab_id, nav1, 0, true);
205
206  helper_.PrepareTabInWindow(window_id, tab2_id, 1, false);
207  UpdateNavigation(window_id, tab2_id, nav2, 0, true);
208  service()->TabClosed(window_id, tab2_id, false);
209
210  ScopedVector<SessionWindow> windows;
211  ReadWindows(&(windows.get()));
212
213  ASSERT_EQ(1U, windows->size());
214  ASSERT_EQ(0, windows[0]->selected_tab_index);
215  ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
216  ASSERT_EQ(1U, windows[0]->tabs.size());
217
218  SessionTab* tab = windows[0]->tabs[0];
219  helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
220
221  helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
222}
223
224TEST_F(SessionServiceTest, Pruning) {
225  SessionID tab_id;
226
227  TabNavigation nav1(0, GURL("http://google.com"), GURL(),
228                     ASCIIToUTF16("abc"), "def",
229                     PageTransition::QUALIFIER_MASK);
230  TabNavigation nav2(0, GURL("http://google2.com"), GURL(),
231                     ASCIIToUTF16("abcd"), "defg",
232                     PageTransition::AUTO_BOOKMARK);
233
234  helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
235  for (int i = 0; i < 6; ++i) {
236    TabNavigation& nav = (i % 2) == 0 ? nav1 : nav2;
237    UpdateNavigation(window_id, tab_id, nav, i, true);
238  }
239  service()->TabNavigationPathPrunedFromBack(window_id, tab_id, 3);
240
241  ScopedVector<SessionWindow> windows;
242  ReadWindows(&(windows.get()));
243
244  ASSERT_EQ(1U, windows->size());
245  ASSERT_EQ(0, windows[0]->selected_tab_index);
246  ASSERT_EQ(1U, windows[0]->tabs.size());
247
248  SessionTab* tab = windows[0]->tabs[0];
249  // We left the selected index at 5, then pruned. When rereading the
250  // index should get reset to last valid navigation, which is 2.
251  helper_.AssertTabEquals(window_id, tab_id, 0, 2, 3, *tab);
252
253  helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
254  helper_.AssertNavigationEquals(nav2, tab->navigations[1]);
255  helper_.AssertNavigationEquals(nav1, tab->navigations[2]);
256}
257
258TEST_F(SessionServiceTest, TwoWindows) {
259  SessionID window2_id;
260  SessionID tab1_id;
261  SessionID tab2_id;
262
263  TabNavigation nav1(0, GURL("http://google.com"), GURL(),
264                     ASCIIToUTF16("abc"), "def",
265                     PageTransition::QUALIFIER_MASK);
266  TabNavigation nav2(0, GURL("http://google2.com"), GURL(),
267                     ASCIIToUTF16("abcd"), "defg",
268                     PageTransition::AUTO_BOOKMARK);
269
270  helper_.PrepareTabInWindow(window_id, tab1_id, 0, true);
271  UpdateNavigation(window_id, tab1_id, nav1, 0, true);
272
273  const gfx::Rect window2_bounds(3, 4, 5, 6);
274  service()->SetWindowType(window2_id, Browser::TYPE_NORMAL);
275  service()->SetWindowBounds(window2_id, window2_bounds, true);
276  helper_.PrepareTabInWindow(window2_id, tab2_id, 0, true);
277  UpdateNavigation(window2_id, tab2_id, nav2, 0, true);
278
279  ScopedVector<SessionWindow> windows;
280  ReadWindows(&(windows.get()));
281
282  ASSERT_EQ(2U, windows->size());
283  ASSERT_EQ(0, windows[0]->selected_tab_index);
284  ASSERT_EQ(0, windows[1]->selected_tab_index);
285  ASSERT_EQ(1U, windows[0]->tabs.size());
286  ASSERT_EQ(1U, windows[1]->tabs.size());
287
288  SessionTab* rt1;
289  SessionTab* rt2;
290  if (windows[0]->window_id.id() == window_id.id()) {
291    ASSERT_EQ(window2_id.id(), windows[1]->window_id.id());
292    ASSERT_FALSE(windows[0]->is_maximized);
293    ASSERT_TRUE(windows[1]->is_maximized);
294    rt1 = windows[0]->tabs[0];
295    rt2 = windows[1]->tabs[0];
296  } else {
297    ASSERT_EQ(window2_id.id(), windows[0]->window_id.id());
298    ASSERT_EQ(window_id.id(), windows[1]->window_id.id());
299    ASSERT_TRUE(windows[0]->is_maximized);
300    ASSERT_FALSE(windows[1]->is_maximized);
301    rt1 = windows[1]->tabs[0];
302    rt2 = windows[0]->tabs[0];
303  }
304  SessionTab* tab = rt1;
305  helper_.AssertTabEquals(window_id, tab1_id, 0, 0, 1, *tab);
306  helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
307
308  tab = rt2;
309  helper_.AssertTabEquals(window2_id, tab2_id, 0, 0, 1, *tab);
310  helper_.AssertNavigationEquals(nav2, tab->navigations[0]);
311}
312
313TEST_F(SessionServiceTest, WindowWithNoTabsGetsPruned) {
314  SessionID window2_id;
315  SessionID tab1_id;
316  SessionID tab2_id;
317
318  TabNavigation nav1(0, GURL("http://google.com"), GURL(),
319                     ASCIIToUTF16("abc"), "def",
320                     PageTransition::QUALIFIER_MASK);
321
322  helper_.PrepareTabInWindow(window_id, tab1_id, 0, true);
323  UpdateNavigation(window_id, tab1_id, nav1, 0, true);
324
325  const gfx::Rect window2_bounds(3, 4, 5, 6);
326  service()->SetWindowType(window2_id, Browser::TYPE_NORMAL);
327  service()->SetWindowBounds(window2_id, window2_bounds, false);
328  helper_.PrepareTabInWindow(window2_id, tab2_id, 0, true);
329
330  ScopedVector<SessionWindow> windows;
331  ReadWindows(&(windows.get()));
332
333  ASSERT_EQ(1U, windows->size());
334  ASSERT_EQ(0, windows[0]->selected_tab_index);
335  ASSERT_EQ(1U, windows[0]->tabs.size());
336  ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
337
338  SessionTab* tab = windows[0]->tabs[0];
339  helper_.AssertTabEquals(window_id, tab1_id, 0, 0, 1, *tab);
340  helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
341}
342
343TEST_F(SessionServiceTest, ClosingWindowDoesntCloseTabs) {
344  SessionID tab_id;
345  SessionID tab2_id;
346  ASSERT_NE(tab_id.id(), tab2_id.id());
347
348  TabNavigation nav1(0, GURL("http://google.com"), GURL(),
349                     ASCIIToUTF16("abc"), "def",
350                     PageTransition::QUALIFIER_MASK);
351  TabNavigation nav2(0, GURL("http://google2.com"), GURL(),
352                     ASCIIToUTF16("abcd"), "defg",
353                     PageTransition::AUTO_BOOKMARK);
354
355  helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
356  UpdateNavigation(window_id, tab_id, nav1, 0, true);
357
358  helper_.PrepareTabInWindow(window_id, tab2_id, 1, false);
359  UpdateNavigation(window_id, tab2_id, nav2, 0, true);
360
361  service()->WindowClosing(window_id);
362
363  ScopedVector<SessionWindow> windows;
364  ReadWindows(&(windows.get()));
365
366  ASSERT_EQ(1U, windows->size());
367  ASSERT_EQ(0, windows[0]->selected_tab_index);
368  ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
369  ASSERT_EQ(2U, windows[0]->tabs.size());
370
371  SessionTab* tab = windows[0]->tabs[0];
372  helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
373  helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
374
375  tab = windows[0]->tabs[1];
376  helper_.AssertTabEquals(window_id, tab2_id, 1, 0, 1, *tab);
377  helper_.AssertNavigationEquals(nav2, tab->navigations[0]);
378}
379
380TEST_F(SessionServiceTest, WindowCloseCommittedAfterNavigate) {
381  SessionID window2_id;
382  SessionID tab_id;
383  SessionID tab2_id;
384  ASSERT_NE(window2_id.id(), window_id.id());
385
386  service()->SetWindowType(window2_id, Browser::TYPE_NORMAL);
387  service()->SetWindowBounds(window2_id, window_bounds, false);
388
389  TabNavigation nav1(0, GURL("http://google.com"), GURL(),
390                     ASCIIToUTF16("abc"), "def",
391                     PageTransition::QUALIFIER_MASK);
392  TabNavigation nav2(0, GURL("http://google2.com"), GURL(),
393                     ASCIIToUTF16("abcd"), "defg",
394                     PageTransition::AUTO_BOOKMARK);
395
396  helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
397  UpdateNavigation(window_id, tab_id, nav1, 0, true);
398
399  helper_.PrepareTabInWindow(window2_id, tab2_id, 0, false);
400  UpdateNavigation(window2_id, tab2_id, nav2, 0, true);
401
402  service()->WindowClosing(window2_id);
403  service()->TabClosed(window2_id, tab2_id, false);
404  service()->WindowClosed(window2_id);
405
406  ScopedVector<SessionWindow> windows;
407  ReadWindows(&(windows.get()));
408
409  ASSERT_EQ(1U, windows->size());
410  ASSERT_EQ(0, windows[0]->selected_tab_index);
411  ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
412  ASSERT_EQ(1U, windows[0]->tabs.size());
413
414  SessionTab* tab = windows[0]->tabs[0];
415  helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
416  helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
417}
418
419// Makes sure we don't track popups.
420TEST_F(SessionServiceTest, IgnorePopups) {
421  if (browser_defaults::kRestorePopups)
422    return;  // This test is only applicable if popups aren't restored.
423
424  SessionID window2_id;
425  SessionID tab_id;
426  SessionID tab2_id;
427  ASSERT_NE(window2_id.id(), window_id.id());
428
429  service()->SetWindowType(window2_id, Browser::TYPE_POPUP);
430  service()->SetWindowBounds(window2_id, window_bounds, false);
431
432  TabNavigation nav1(0, GURL("http://google.com"), GURL(),
433                     ASCIIToUTF16("abc"), "def",
434                     PageTransition::QUALIFIER_MASK);
435  TabNavigation nav2(0, GURL("http://google2.com"), GURL(),
436                     ASCIIToUTF16("abcd"), "defg",
437                     PageTransition::AUTO_BOOKMARK);
438
439  helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
440  UpdateNavigation(window_id, tab_id, nav1, 0, true);
441
442  helper_.PrepareTabInWindow(window2_id, tab2_id, 0, false);
443  UpdateNavigation(window2_id, tab2_id, nav2, 0, true);
444
445  ScopedVector<SessionWindow> windows;
446  ReadWindows(&(windows.get()));
447
448  ASSERT_EQ(1U, windows->size());
449  ASSERT_EQ(0, windows[0]->selected_tab_index);
450  ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
451  ASSERT_EQ(1U, windows[0]->tabs.size());
452
453  SessionTab* tab = windows[0]->tabs[0];
454  helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
455  helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
456}
457
458// Makes sure we track popups.
459TEST_F(SessionServiceTest, RestorePopup) {
460  if (!browser_defaults::kRestorePopups)
461    return;  // This test is only applicable if popups are restored.
462
463  SessionID window2_id;
464  SessionID tab_id;
465  SessionID tab2_id;
466  ASSERT_NE(window2_id.id(), window_id.id());
467
468  service()->SetWindowType(window2_id, Browser::TYPE_POPUP);
469  service()->SetWindowBounds(window2_id, window_bounds, false);
470
471  TabNavigation nav1(0, GURL("http://google.com"), GURL(),
472                     ASCIIToUTF16("abc"), "def",
473                     PageTransition::QUALIFIER_MASK);
474  TabNavigation nav2(0, GURL("http://google2.com"), GURL(),
475                     ASCIIToUTF16("abcd"), "defg",
476                     PageTransition::AUTO_BOOKMARK);
477
478  helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
479  UpdateNavigation(window_id, tab_id, nav1, 0, true);
480
481  helper_.PrepareTabInWindow(window2_id, tab2_id, 0, false);
482  UpdateNavigation(window2_id, tab2_id, nav2, 0, true);
483
484  ScopedVector<SessionWindow> windows;
485  ReadWindows(&(windows.get()));
486
487  ASSERT_EQ(2U, windows->size());
488  int normal_index = windows[0]->type == Browser::TYPE_NORMAL ?
489      0 : 1;
490  int popup_index = normal_index == 0 ? 1 : 0;
491  ASSERT_EQ(0, windows[normal_index]->selected_tab_index);
492  ASSERT_EQ(window_id.id(), windows[normal_index]->window_id.id());
493  ASSERT_EQ(1U, windows[normal_index]->tabs.size());
494
495  SessionTab* tab = windows[normal_index]->tabs[0];
496  helper_.AssertTabEquals(window_id, tab_id, 0, 0, 1, *tab);
497  helper_.AssertNavigationEquals(nav1, tab->navigations[0]);
498
499  ASSERT_EQ(0, windows[popup_index]->selected_tab_index);
500  ASSERT_EQ(window2_id.id(), windows[popup_index]->window_id.id());
501  ASSERT_EQ(1U, windows[popup_index]->tabs.size());
502
503  tab = windows[popup_index]->tabs[0];
504  helper_.AssertTabEquals(window2_id, tab2_id, 0, 0, 1, *tab);
505  helper_.AssertNavigationEquals(nav2, tab->navigations[0]);
506}
507
508// Tests pruning from the front.
509TEST_F(SessionServiceTest, PruneFromFront) {
510  const std::string base_url("http://google.com/");
511  SessionID tab_id;
512
513  helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
514
515  // Add 5 navigations, with the 4th selected.
516  for (int i = 0; i < 5; ++i) {
517    TabNavigation nav(0, GURL(base_url + base::IntToString(i)), GURL(),
518                      ASCIIToUTF16("a"), "b", PageTransition::QUALIFIER_MASK);
519    UpdateNavigation(window_id, tab_id, nav, i, (i == 3));
520  }
521
522  // Prune the first two navigations from the front.
523  helper_.service()->TabNavigationPathPrunedFromFront(window_id, tab_id, 2);
524
525  // Read back in.
526  ScopedVector<SessionWindow> windows;
527  ReadWindows(&(windows.get()));
528
529  ASSERT_EQ(1U, windows->size());
530  ASSERT_EQ(0, windows[0]->selected_tab_index);
531  ASSERT_EQ(window_id.id(), windows[0]->window_id.id());
532  ASSERT_EQ(1U, windows[0]->tabs.size());
533
534  // There shouldn't be an app id.
535  EXPECT_TRUE(windows[0]->tabs[0]->extension_app_id.empty());
536
537  // We should be left with three navigations, the 2nd selected.
538  SessionTab* tab = windows[0]->tabs[0];
539  ASSERT_EQ(1, tab->current_navigation_index);
540  EXPECT_EQ(3U, tab->navigations.size());
541  EXPECT_TRUE(GURL(base_url + base::IntToString(2)) ==
542              tab->navigations[0].virtual_url());
543  EXPECT_TRUE(GURL(base_url + base::IntToString(3)) ==
544              tab->navigations[1].virtual_url());
545  EXPECT_TRUE(GURL(base_url + base::IntToString(4)) ==
546              tab->navigations[2].virtual_url());
547}
548
549// Prunes from front so that we have no entries.
550TEST_F(SessionServiceTest, PruneToEmpty) {
551  const std::string base_url("http://google.com/");
552  SessionID tab_id;
553
554  helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
555
556  // Add 5 navigations, with the 4th selected.
557  for (int i = 0; i < 5; ++i) {
558    TabNavigation nav(0, GURL(base_url + base::IntToString(i)), GURL(),
559                      ASCIIToUTF16("a"), "b", PageTransition::QUALIFIER_MASK);
560    UpdateNavigation(window_id, tab_id, nav, i, (i == 3));
561  }
562
563  // Prune the first two navigations from the front.
564  helper_.service()->TabNavigationPathPrunedFromFront(window_id, tab_id, 5);
565
566  // Read back in.
567  ScopedVector<SessionWindow> windows;
568  ReadWindows(&(windows.get()));
569
570  ASSERT_EQ(0U, windows->size());
571}
572
573// Don't set the pinned state and make sure the pinned value is false.
574TEST_F(SessionServiceTest, PinnedDefaultsToFalse) {
575  EXPECT_FALSE(CreateAndWriteSessionWithOneTab(false, false));
576}
577
578// Explicitly set the pinned state to false and make sure we get back false.
579TEST_F(SessionServiceTest, PinnedFalseWhenSetToFalse) {
580  EXPECT_FALSE(CreateAndWriteSessionWithOneTab(false, true));
581}
582
583// Make sure application extension ids are persisted.
584TEST_F(SessionServiceTest, PersistApplicationExtensionID) {
585  SessionID tab_id;
586  ASSERT_NE(window_id.id(), tab_id.id());
587  std::string app_id("foo");
588
589  TabNavigation nav1(0, GURL("http://google.com"), GURL(),
590                     ASCIIToUTF16("abc"), std::string(),
591                     PageTransition::QUALIFIER_MASK);
592
593  helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
594  UpdateNavigation(window_id, tab_id, nav1, 0, true);
595  helper_.SetTabExtensionAppID(window_id, tab_id, app_id);
596
597  ScopedVector<SessionWindow> windows;
598  ReadWindows(&(windows.get()));
599
600  helper_.AssertSingleWindowWithSingleTab(windows.get(), 1);
601  EXPECT_TRUE(app_id == windows[0]->tabs[0]->extension_app_id);
602}
603
604// Explicitly set the pinned state to true and make sure we get back true.
605TEST_F(SessionServiceTest, PinnedTrue) {
606  EXPECT_TRUE(CreateAndWriteSessionWithOneTab(true, true));
607}
608
609class GetCurrentSessionCallbackHandler {
610 public:
611  void OnGotSession(int handle, std::vector<SessionWindow*>* windows) {
612    EXPECT_EQ(1U, windows->size());
613    EXPECT_EQ(2U, (*windows)[0]->tabs.size());
614    EXPECT_EQ(2U, (*windows)[0]->tabs[0]->navigations.size());
615    EXPECT_EQ(GURL("http://bar/1"),
616              (*windows)[0]->tabs[0]->navigations[0].virtual_url());
617    EXPECT_EQ(GURL("http://bar/2"),
618              (*windows)[0]->tabs[0]->navigations[1].virtual_url());
619    EXPECT_EQ(2U, (*windows)[0]->tabs[1]->navigations.size());
620    EXPECT_EQ(GURL("http://foo/1"),
621              (*windows)[0]->tabs[1]->navigations[0].virtual_url());
622    EXPECT_EQ(GURL("http://foo/2"),
623              (*windows)[0]->tabs[1]->navigations[1].virtual_url());
624  }
625};
626
627TEST_F(SessionServiceTest, GetCurrentSession) {
628  AddTab(browser(), GURL("http://foo/1"));
629  NavigateAndCommitActiveTab(GURL("http://foo/2"));
630  AddTab(browser(), GURL("http://bar/1"));
631  NavigateAndCommitActiveTab(GURL("http://bar/2"));
632
633  CancelableRequestConsumer consumer;
634  GetCurrentSessionCallbackHandler handler;
635  service()->GetCurrentSession(&consumer,
636      NewCallback(&handler, &GetCurrentSessionCallbackHandler::OnGotSession));
637}
638
639// Test that the notification for SESSION_SERVICE_SAVED is working properly.
640TEST_F(SessionServiceTest, SavedSessionNotification) {
641  NotificationRegistrar registrar_;
642  registrar_.Add(this, NotificationType::SESSION_SERVICE_SAVED,
643                 NotificationService::AllSources());
644  service()->Save();
645  EXPECT_EQ(sync_save_count_, 1);
646}
647
648// Makes sure a tab closed by a user gesture is not restored.
649TEST_F(SessionServiceTest, CloseTabUserGesture) {
650  SessionID tab_id;
651  ASSERT_NE(window_id.id(), tab_id.id());
652
653  TabNavigation nav1(0, GURL("http://google.com"),
654                     GURL("http://www.referrer.com"),
655                     ASCIIToUTF16("abc"), "def",
656                     PageTransition::QUALIFIER_MASK);
657
658  helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
659  UpdateNavigation(window_id, tab_id, nav1, 0, true);
660  service()->TabClosed(window_id, tab_id, true);
661
662  ScopedVector<SessionWindow> windows;
663  ReadWindows(&(windows.get()));
664
665  ASSERT_TRUE(windows->empty());
666}
667