• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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 "chrome/browser/extensions/api/sessions/sessions_api.h"
6 
7 #include "base/command_line.h"
8 #include "base/path_service.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/extensions/api/tabs/tabs_api.h"
11 #include "chrome/browser/extensions/extension_apitest.h"
12 #include "chrome/browser/extensions/extension_function_test_utils.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/browser/sync/open_tabs_ui_delegate.h"
15 #include "chrome/browser/sync/profile_sync_service.h"
16 #include "chrome/browser/sync/profile_sync_service_factory.h"
17 #include "chrome/browser/sync/profile_sync_service_mock.h"
18 #include "chrome/common/chrome_paths.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/test/base/in_process_browser_test.h"
21 #include "chrome/test/base/test_switches.h"
22 #include "chrome/test/base/testing_browser_process.h"
23 #include "sync/api/attachments/attachment_id.h"
24 #include "sync/api/attachments/attachment_service_proxy_for_test.h"
25 #include "sync/api/fake_sync_change_processor.h"
26 #include "sync/api/sync_error_factory_mock.h"
27 
28 #if defined(OS_CHROMEOS)
29 #include "chromeos/chromeos_switches.h"
30 #endif
31 
32 namespace utils = extension_function_test_utils;
33 
34 namespace extensions {
35 
36 namespace {
37 
38 // If more sessions are added to session tags, num sessions should be updated.
39 const char* kSessionTags[] = {"tag0", "tag1", "tag2", "tag3", "tag4"};
40 const size_t kNumSessions = 5;
41 
BuildSessionSpecifics(const std::string & tag,sync_pb::SessionSpecifics * meta)42 void BuildSessionSpecifics(const std::string& tag,
43                            sync_pb::SessionSpecifics* meta) {
44   meta->set_session_tag(tag);
45   sync_pb::SessionHeader* header = meta->mutable_header();
46   header->set_device_type(sync_pb::SyncEnums_DeviceType_TYPE_LINUX);
47   header->set_client_name(tag);
48 }
49 
BuildWindowSpecifics(int window_id,const std::vector<int> & tab_list,sync_pb::SessionSpecifics * meta)50 void BuildWindowSpecifics(int window_id,
51                           const std::vector<int>& tab_list,
52                           sync_pb::SessionSpecifics* meta) {
53   sync_pb::SessionHeader* header = meta->mutable_header();
54   sync_pb::SessionWindow* window = header->add_window();
55   window->set_window_id(window_id);
56   window->set_selected_tab_index(0);
57   window->set_browser_type(sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
58   for (std::vector<int>::const_iterator iter = tab_list.begin();
59        iter != tab_list.end(); ++iter) {
60     window->add_tab(*iter);
61   }
62 }
63 
BuildTabSpecifics(const std::string & tag,int window_id,int tab_id,sync_pb::SessionSpecifics * tab_base)64 void BuildTabSpecifics(const std::string& tag, int window_id, int tab_id,
65                        sync_pb::SessionSpecifics* tab_base) {
66   tab_base->set_session_tag(tag);
67   tab_base->set_tab_node_id(0);
68   sync_pb::SessionTab* tab = tab_base->mutable_tab();
69   tab->set_tab_id(tab_id);
70   tab->set_tab_visual_index(1);
71   tab->set_current_navigation_index(0);
72   tab->set_pinned(true);
73   tab->set_extension_app_id("app_id");
74   sync_pb::TabNavigation* navigation = tab->add_navigation();
75   navigation->set_virtual_url("http://foo/1");
76   navigation->set_referrer("referrer");
77   navigation->set_title("title");
78   navigation->set_page_transition(sync_pb::SyncEnums_PageTransition_TYPED);
79 }
80 
81 } // namespace
82 
83 class ExtensionSessionsTest : public InProcessBrowserTest {
84  public:
85   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE;
86   virtual void SetUpOnMainThread() OVERRIDE;
87  protected:
88   void CreateTestProfileSyncService();
89   void CreateTestExtension();
90   void CreateSessionModels();
91 
92   template <class T>
CreateFunction(bool has_callback)93   scoped_refptr<T> CreateFunction(bool has_callback) {
94     scoped_refptr<T> fn(new T());
95     fn->set_extension(extension_.get());
96     fn->set_has_callback(has_callback);
97     return fn;
98   };
99 
100   Browser* browser_;
101   scoped_refptr<extensions::Extension> extension_;
102 };
103 
SetUpCommandLine(CommandLine * command_line)104 void ExtensionSessionsTest::SetUpCommandLine(CommandLine* command_line) {
105 #if defined(OS_CHROMEOS)
106   command_line->AppendSwitch(
107       chromeos::switches::kIgnoreUserProfileMappingForTests);
108 #endif
109 }
110 
SetUpOnMainThread()111 void ExtensionSessionsTest::SetUpOnMainThread() {
112   CreateTestProfileSyncService();
113   CreateTestExtension();
114 }
115 
CreateTestProfileSyncService()116 void ExtensionSessionsTest::CreateTestProfileSyncService() {
117   ProfileManager* profile_manager = g_browser_process->profile_manager();
118   base::FilePath path;
119   PathService::Get(chrome::DIR_USER_DATA, &path);
120   path = path.AppendASCII("test_profile");
121   if (!base::PathExists(path))
122     CHECK(base::CreateDirectory(path));
123   Profile* profile =
124       Profile::CreateProfile(path, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
125   profile_manager->RegisterTestingProfile(profile, true, false);
126   ProfileSyncServiceMock* service = static_cast<ProfileSyncServiceMock*>(
127       ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
128       profile, &ProfileSyncServiceMock::BuildMockProfileSyncService));
129   browser_ = new Browser(Browser::CreateParams(
130       profile, chrome::HOST_DESKTOP_TYPE_NATIVE));
131 
132   syncer::ModelTypeSet preferred_types;
133   preferred_types.Put(syncer::SESSIONS);
134   GoogleServiceAuthError no_error(GoogleServiceAuthError::NONE);
135   ON_CALL(*service, IsSessionsDataTypeControllerRunning())
136       .WillByDefault(testing::Return(true));
137   ON_CALL(*service, GetRegisteredDataTypes())
138       .WillByDefault(testing::Return(syncer::UserTypes()));
139   ON_CALL(*service, GetPreferredDataTypes()).WillByDefault(
140       testing::Return(preferred_types));
141   EXPECT_CALL(*service, GetAuthError()).WillRepeatedly(
142       testing::ReturnRef(no_error));
143   ON_CALL(*service, GetActiveDataTypes()).WillByDefault(
144       testing::Return(preferred_types));
145   ON_CALL(*service, GetLocalDeviceInfoMock()).WillByDefault(
146       testing::Return(new browser_sync::DeviceInfo(
147           std::string(kSessionTags[0]),
148           "machine name",
149           "Chromium 10k",
150           "Chrome 10k",
151           sync_pb::SyncEnums_DeviceType_TYPE_LINUX)));
152   ON_CALL(*service, GetLocalSyncCacheGUID()).WillByDefault(
153       testing::Return(std::string(kSessionTags[0])));
154   EXPECT_CALL(*service, AddObserver(testing::_)).Times(testing::AnyNumber());
155   EXPECT_CALL(*service, RemoveObserver(testing::_)).Times(testing::AnyNumber());
156 
157   service->Initialize();
158 }
159 
CreateTestExtension()160 void ExtensionSessionsTest::CreateTestExtension() {
161   scoped_ptr<base::DictionaryValue> test_extension_value(
162       utils::ParseDictionary(
163       "{\"name\": \"Test\", \"version\": \"1.0\", "
164       "\"permissions\": [\"sessions\", \"tabs\"]}"));
165   extension_ = utils::CreateExtension(test_extension_value.get());
166 }
167 
CreateSessionModels()168 void ExtensionSessionsTest::CreateSessionModels() {
169   syncer::SyncDataList initial_data;
170   for (size_t index = 0; index < kNumSessions; ++index) {
171     // Fill an instance of session specifics with a foreign session's data.
172     sync_pb::SessionSpecifics meta;
173     BuildSessionSpecifics(kSessionTags[index], &meta);
174     SessionID::id_type tab_nums1[] = {5, 10, 13, 17};
175     std::vector<SessionID::id_type> tab_list1(
176         tab_nums1, tab_nums1 + arraysize(tab_nums1));
177     BuildWindowSpecifics(index, tab_list1, &meta);
178     std::vector<sync_pb::SessionSpecifics> tabs1;
179     tabs1.resize(tab_list1.size());
180     for (size_t i = 0; i < tab_list1.size(); ++i) {
181       BuildTabSpecifics(kSessionTags[index], 0, tab_list1[i], &tabs1[i]);
182     }
183 
184     sync_pb::EntitySpecifics entity;
185     entity.mutable_session()->CopyFrom(meta);
186     initial_data.push_back(syncer::SyncData::CreateRemoteData(
187         1,
188         entity,
189         base::Time(),
190         syncer::AttachmentIdList(),
191         syncer::AttachmentServiceProxyForTest::Create()));
192     for (size_t i = 0; i < tabs1.size(); i++) {
193       sync_pb::EntitySpecifics entity;
194       entity.mutable_session()->CopyFrom(tabs1[i]);
195       initial_data.push_back(syncer::SyncData::CreateRemoteData(
196           i + 2,
197           entity,
198           base::Time(),
199           syncer::AttachmentIdList(),
200           syncer::AttachmentServiceProxyForTest::Create()));
201     }
202   }
203 
204   ProfileSyncServiceFactory::GetForProfile(browser_->profile())->
205       GetSessionsSyncableService()->
206           MergeDataAndStartSyncing(syncer::SESSIONS, initial_data,
207       scoped_ptr<syncer::SyncChangeProcessor>(
208           new syncer::FakeSyncChangeProcessor()),
209       scoped_ptr<syncer::SyncErrorFactory>(
210           new syncer::SyncErrorFactoryMock()));
211 }
212 
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest,GetDevices)213 IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetDevices) {
214   CreateSessionModels();
215 
216   scoped_ptr<base::ListValue> result(utils::ToList(
217       utils::RunFunctionAndReturnSingleResult(
218           CreateFunction<SessionsGetDevicesFunction>(true).get(),
219           "[{\"maxResults\": 0}]",
220           browser_)));
221   ASSERT_TRUE(result);
222   base::ListValue* devices = result.get();
223   EXPECT_EQ(5u, devices->GetSize());
224   base::DictionaryValue* device = NULL;
225   base::ListValue* sessions = NULL;
226   for (size_t i = 0; i < devices->GetSize(); ++i) {
227     EXPECT_TRUE(devices->GetDictionary(i, &device));
228     EXPECT_EQ(kSessionTags[i], utils::GetString(device, "info"));
229     EXPECT_EQ(kSessionTags[i], utils::GetString(device, "deviceName"));
230     EXPECT_TRUE(device->GetList("sessions", &sessions));
231     EXPECT_EQ(0u, sessions->GetSize());
232   }
233 }
234 
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest,GetDevicesMaxResults)235 IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetDevicesMaxResults) {
236   CreateSessionModels();
237 
238   scoped_ptr<base::ListValue> result(utils::ToList(
239       utils::RunFunctionAndReturnSingleResult(
240           CreateFunction<SessionsGetDevicesFunction>(true).get(),
241           "[]",
242           browser_)));
243   ASSERT_TRUE(result);
244   base::ListValue* devices = result.get();
245   EXPECT_EQ(5u, devices->GetSize());
246   base::DictionaryValue* device = NULL;
247   base::ListValue* sessions = NULL;
248   for (size_t i = 0; i < devices->GetSize(); ++i) {
249     EXPECT_TRUE(devices->GetDictionary(i, &device));
250     EXPECT_EQ(kSessionTags[i], utils::GetString(device, "info"));
251     EXPECT_EQ(kSessionTags[i], utils::GetString(device, "deviceName"));
252     EXPECT_TRUE(device->GetList("sessions", &sessions));
253     EXPECT_EQ(1u, sessions->GetSize());
254   }
255 }
256 
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest,GetDevicesListEmpty)257 IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetDevicesListEmpty) {
258   scoped_ptr<base::ListValue> result(utils::ToList(
259       utils::RunFunctionAndReturnSingleResult(
260           CreateFunction<SessionsGetDevicesFunction>(true).get(),
261           "[]",
262           browser_)));
263 
264   ASSERT_TRUE(result);
265   base::ListValue* devices = result.get();
266   EXPECT_EQ(0u, devices->GetSize());
267 }
268 
269 // Flaky timeout: http://crbug.com/278372
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest,DISABLED_RestoreForeignSessionWindow)270 IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest,
271                        DISABLED_RestoreForeignSessionWindow) {
272   CreateSessionModels();
273 
274   scoped_ptr<base::DictionaryValue> restored_window_session(utils::ToDictionary(
275       utils::RunFunctionAndReturnSingleResult(
276           CreateFunction<SessionsRestoreFunction>(true).get(),
277           "[\"tag3.3\"]",
278           browser_,
279           utils::INCLUDE_INCOGNITO)));
280   ASSERT_TRUE(restored_window_session);
281 
282   scoped_ptr<base::ListValue> result(utils::ToList(
283       utils::RunFunctionAndReturnSingleResult(
284           CreateFunction<WindowsGetAllFunction>(true).get(),
285           "[]",
286           browser_)));
287   ASSERT_TRUE(result);
288 
289   base::ListValue* windows = result.get();
290   EXPECT_EQ(2u, windows->GetSize());
291   base::DictionaryValue* restored_window = NULL;
292   EXPECT_TRUE(restored_window_session->GetDictionary("window",
293                                                      &restored_window));
294   base::DictionaryValue* window = NULL;
295   int restored_id = utils::GetInteger(restored_window, "id");
296   for (size_t i = 0; i < windows->GetSize(); ++i) {
297     EXPECT_TRUE(windows->GetDictionary(i, &window));
298     if (utils::GetInteger(window, "id") == restored_id)
299       break;
300   }
301   EXPECT_EQ(restored_id, utils::GetInteger(window, "id"));
302 }
303 
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest,RestoreForeignSessionInvalidId)304 IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, RestoreForeignSessionInvalidId) {
305   CreateSessionModels();
306 
307   EXPECT_TRUE(MatchPattern(utils::RunFunctionAndReturnError(
308       CreateFunction<SessionsRestoreFunction>(true).get(),
309       "[\"tag3.0\"]",
310       browser_), "Invalid session id: \"tag3.0\"."));
311 }
312 
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest,RestoreInIncognito)313 IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, RestoreInIncognito) {
314   CreateSessionModels();
315 
316   EXPECT_TRUE(MatchPattern(utils::RunFunctionAndReturnError(
317       CreateFunction<SessionsRestoreFunction>(true).get(),
318       "[\"1\"]",
319       CreateIncognitoBrowser()),
320       "Can not restore sessions in incognito mode."));
321 }
322 
IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest,GetRecentlyClosedIncognito)323 IN_PROC_BROWSER_TEST_F(ExtensionSessionsTest, GetRecentlyClosedIncognito) {
324   scoped_ptr<base::ListValue> result(utils::ToList(
325       utils::RunFunctionAndReturnSingleResult(
326           CreateFunction<SessionsGetRecentlyClosedFunction>(true).get(),
327           "[]",
328           CreateIncognitoBrowser())));
329   ASSERT_TRUE(result);
330   base::ListValue* sessions = result.get();
331   EXPECT_EQ(0u, sessions->GetSize());
332 }
333 
334 // Flaky on ChromeOS, times out on OSX Debug http://crbug.com/251199
335 #if defined(OS_CHROMEOS) || (defined(OS_MACOSX) && !defined(NDEBUG))
336 #define MAYBE_SessionsApis DISABLED_SessionsApis
337 #else
338 #define MAYBE_SessionsApis SessionsApis
339 #endif
IN_PROC_BROWSER_TEST_F(ExtensionApiTest,MAYBE_SessionsApis)340 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_SessionsApis) {
341 #if defined(OS_WIN) && defined(USE_ASH)
342   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
343   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
344     return;
345 #endif
346 
347   ASSERT_TRUE(RunExtensionSubtest("sessions",
348                                   "sessions.html")) << message_;
349 }
350 
351 }  // namespace extensions
352