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