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.
5 #include "base/basictypes.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/extensions/bookmark_app_helper.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_sync_data.h"
11 #include "chrome/browser/extensions/extension_sync_service.h"
12 #include "chrome/browser/extensions/launch_util.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/sync/test/integration/apps_helper.h"
15 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
16 #include "chrome/browser/sync/test/integration/sync_app_helper.h"
17 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
18 #include "chrome/browser/sync/test/integration/sync_test.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/public/test/test_utils.h"
21 #include "extensions/browser/app_sorting.h"
22 #include "extensions/browser/extension_prefs.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/common/constants.h"
26 #include "sync/api/string_ordinal.h"
28 using apps_helper::AllProfilesHaveSameAppsAsVerifier
;
29 using apps_helper::CopyNTPOrdinals
;
30 using apps_helper::DisableApp
;
31 using apps_helper::EnableApp
;
32 using apps_helper::FixNTPOrdinalCollisions
;
33 using apps_helper::GetAppLaunchOrdinalForApp
;
34 using apps_helper::HasSameAppsAsVerifier
;
35 using apps_helper::IncognitoDisableApp
;
36 using apps_helper::IncognitoEnableApp
;
37 using apps_helper::InstallApp
;
38 using apps_helper::InstallPlatformApp
;
39 using apps_helper::SetAppLaunchOrdinalForApp
;
40 using apps_helper::SetPageOrdinalForApp
;
41 using apps_helper::UninstallApp
;
42 using apps_helper::AwaitAllProfilesHaveSameApps
;
46 extensions::ExtensionRegistry
* GetExtensionRegistry(Profile
* profile
) {
47 return extensions::ExtensionRegistry::Get(profile
);
50 ExtensionService
* GetExtensionService(Profile
* profile
) {
51 return extensions::ExtensionSystem::Get(profile
)->extension_service();
56 class TwoClientAppsSyncTest
: public SyncTest
{
58 TwoClientAppsSyncTest() : SyncTest(TWO_CLIENT
) {}
60 ~TwoClientAppsSyncTest() override
{}
62 bool TestUsesSelfNotifications() override
{ return false; }
65 DISALLOW_COPY_AND_ASSIGN(TwoClientAppsSyncTest
);
68 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, StartWithNoApps
) {
69 ASSERT_TRUE(SetupSync());
71 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
74 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, StartWithSameApps
) {
75 ASSERT_TRUE(SetupClients());
77 const int kNumApps
= 5;
78 for (int i
= 0; i
< kNumApps
; ++i
) {
79 InstallApp(GetProfile(0), i
);
80 InstallApp(GetProfile(1), i
);
81 InstallApp(verifier(), i
);
84 ASSERT_TRUE(SetupSync());
86 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
89 // Install some apps on both clients, some on only one client, some on only the
90 // other, and sync. Both clients should end up with all apps, and the app and
91 // page ordinals should be identical.
92 // Disabled, see http://crbug.com/434438 for details.
93 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, DISABLED_StartWithDifferentApps
) {
94 ASSERT_TRUE(SetupClients());
98 const int kNumCommonApps
= 5;
99 for (int j
= 0; j
< kNumCommonApps
; ++i
, ++j
) {
100 InstallApp(GetProfile(0), i
);
101 InstallApp(GetProfile(1), i
);
102 InstallApp(verifier(), i
);
105 const int kNumProfile0Apps
= 10;
106 for (int j
= 0; j
< kNumProfile0Apps
; ++i
, ++j
) {
107 InstallApp(GetProfile(0), i
);
108 InstallApp(verifier(), i
);
109 CopyNTPOrdinals(GetProfile(0), verifier(), i
);
112 const int kNumProfile1Apps
= 10;
113 for (int j
= 0; j
< kNumProfile1Apps
; ++i
, ++j
) {
114 InstallApp(GetProfile(1), i
);
115 InstallApp(verifier(), i
);
116 CopyNTPOrdinals(GetProfile(1), verifier(), i
);
119 const int kNumPlatformApps
= 5;
120 for (int j
= 0; j
< kNumPlatformApps
; ++i
, ++j
) {
121 InstallPlatformApp(GetProfile(1), i
);
122 InstallPlatformApp(verifier(), i
);
123 CopyNTPOrdinals(GetProfile(1), verifier(), i
);
126 FixNTPOrdinalCollisions(verifier());
128 ASSERT_TRUE(SetupSync());
130 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
133 // Install some apps on both clients, then sync. Then install some apps on only
134 // one client, some on only the other, and then sync again. Both clients should
135 // end up with all apps, and the app and page ordinals should be identical.
136 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, InstallDifferentApps
) {
137 ASSERT_TRUE(SetupClients());
141 const int kNumCommonApps
= 5;
142 for (int j
= 0; j
< kNumCommonApps
; ++i
, ++j
) {
143 InstallApp(GetProfile(0), i
);
144 InstallApp(GetProfile(1), i
);
145 InstallApp(verifier(), i
);
148 ASSERT_TRUE(SetupSync());
150 const int kNumProfile0Apps
= 10;
151 for (int j
= 0; j
< kNumProfile0Apps
; ++i
, ++j
) {
152 InstallApp(GetProfile(0), i
);
153 InstallApp(verifier(), i
);
154 CopyNTPOrdinals(GetProfile(0), verifier(), i
);
157 const int kNumProfile1Apps
= 10;
158 for (int j
= 0; j
< kNumProfile1Apps
; ++i
, ++j
) {
159 InstallApp(GetProfile(1), i
);
160 InstallApp(verifier(), i
);
161 CopyNTPOrdinals(GetProfile(1), verifier(), i
);
164 FixNTPOrdinalCollisions(verifier());
166 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
170 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, Add
) {
171 ASSERT_TRUE(SetupSync());
172 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
174 InstallApp(GetProfile(0), 0);
175 InstallApp(verifier(), 0);
177 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
181 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, Uninstall
) {
182 ASSERT_TRUE(SetupSync());
183 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
185 InstallApp(GetProfile(0), 0);
186 InstallApp(verifier(), 0);
187 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
189 UninstallApp(GetProfile(0), 0);
190 UninstallApp(verifier(), 0);
191 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
194 // Install an app on one client, then sync. Then uninstall the app on the first
195 // client and sync again. Now install a new app on the first client and sync.
196 // Both client should only have the second app, with identical app and page
198 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, UninstallThenInstall
) {
199 ASSERT_TRUE(SetupSync());
201 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
203 InstallApp(GetProfile(0), 0);
204 InstallApp(verifier(), 0);
205 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
207 UninstallApp(GetProfile(0), 0);
208 UninstallApp(verifier(), 0);
209 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
211 InstallApp(GetProfile(0), 1);
212 InstallApp(verifier(), 1);
213 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
217 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, Merge
) {
218 ASSERT_TRUE(SetupSync());
219 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
221 InstallApp(GetProfile(0), 0);
222 InstallApp(verifier(), 0);
223 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
225 UninstallApp(GetProfile(0), 0);
226 UninstallApp(verifier(), 0);
228 InstallApp(GetProfile(0), 1);
229 InstallApp(verifier(), 1);
231 InstallApp(GetProfile(0), 2);
232 InstallApp(GetProfile(1), 2);
233 InstallApp(verifier(), 2);
235 InstallApp(GetProfile(1), 3);
236 InstallApp(verifier(), 3);
238 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
242 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, UpdateEnableDisableApp
) {
243 ASSERT_TRUE(SetupSync());
244 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
246 InstallApp(GetProfile(0), 0);
247 InstallApp(verifier(), 0);
248 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
250 DisableApp(GetProfile(0), 0);
251 DisableApp(verifier(), 0);
252 ASSERT_TRUE(HasSameAppsAsVerifier(0));
253 ASSERT_FALSE(HasSameAppsAsVerifier(1));
255 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
257 EnableApp(GetProfile(1), 0);
258 EnableApp(verifier(), 0);
259 ASSERT_TRUE(HasSameAppsAsVerifier(1));
260 ASSERT_FALSE(HasSameAppsAsVerifier(0));
262 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
266 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, UpdateIncognitoEnableDisable
) {
267 ASSERT_TRUE(SetupSync());
268 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
270 InstallApp(GetProfile(0), 0);
271 InstallApp(verifier(), 0);
272 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
274 IncognitoEnableApp(GetProfile(0), 0);
275 IncognitoEnableApp(verifier(), 0);
276 ASSERT_TRUE(HasSameAppsAsVerifier(0));
277 ASSERT_FALSE(HasSameAppsAsVerifier(1));
279 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
281 IncognitoDisableApp(GetProfile(1), 0);
282 IncognitoDisableApp(verifier(), 0);
283 ASSERT_TRUE(HasSameAppsAsVerifier(1));
284 ASSERT_FALSE(HasSameAppsAsVerifier(0));
286 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
289 // Install the same app on both clients, then sync. Change the page ordinal on
290 // one client and sync. Both clients should have the updated page ordinal for
292 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, UpdatePageOrdinal
) {
293 ASSERT_TRUE(SetupSync());
294 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
296 syncer::StringOrdinal initial_page
=
297 syncer::StringOrdinal::CreateInitialOrdinal();
298 InstallApp(GetProfile(0), 0);
299 InstallApp(verifier(), 0);
300 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
302 syncer::StringOrdinal second_page
= initial_page
.CreateAfter();
303 SetPageOrdinalForApp(GetProfile(0), 0, second_page
);
304 SetPageOrdinalForApp(verifier(), 0, second_page
);
305 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
308 // Install the same app on both clients, then sync. Change the app launch
309 // ordinal on one client and sync. Both clients should have the updated app
310 // launch ordinal for the app.
311 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, UpdateAppLaunchOrdinal
) {
312 ASSERT_TRUE(SetupSync());
313 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
315 InstallApp(GetProfile(0), 0);
316 InstallApp(verifier(), 0);
317 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
319 syncer::StringOrdinal initial_position
=
320 GetAppLaunchOrdinalForApp(GetProfile(0), 0);
322 syncer::StringOrdinal second_position
= initial_position
.CreateAfter();
323 SetAppLaunchOrdinalForApp(GetProfile(0), 0, second_position
);
324 SetAppLaunchOrdinalForApp(verifier(), 0, second_position
);
325 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
328 // Adjust the CWS location within a page on the first client and sync. Adjust
329 // which page the CWS appears on and sync. Both clients should have the same
330 // page and app launch ordinal values for the CWS.
331 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, UpdateCWSOrdinals
) {
332 ASSERT_TRUE(SetupSync());
333 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
335 // Change the app launch ordinal.
336 syncer::StringOrdinal cws_app_launch_ordinal
=
337 extensions::ExtensionPrefs::Get(GetProfile(0))
339 ->GetAppLaunchOrdinal(extensions::kWebStoreAppId
);
340 extensions::ExtensionPrefs::Get(GetProfile(0))
342 ->SetAppLaunchOrdinal(extensions::kWebStoreAppId
,
343 cws_app_launch_ordinal
.CreateAfter());
344 extensions::ExtensionPrefs::Get(verifier())
346 ->SetAppLaunchOrdinal(extensions::kWebStoreAppId
,
347 cws_app_launch_ordinal
.CreateAfter());
348 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
350 // Change the page ordinal.
351 syncer::StringOrdinal cws_page_ordinal
=
352 extensions::ExtensionPrefs::Get(GetProfile(1))
354 ->GetPageOrdinal(extensions::kWebStoreAppId
);
355 extensions::ExtensionPrefs::Get(GetProfile(1))->app_sorting()->SetPageOrdinal(
356 extensions::kWebStoreAppId
, cws_page_ordinal
.CreateAfter());
357 extensions::ExtensionPrefs::Get(verifier())->app_sorting()->SetPageOrdinal(
358 extensions::kWebStoreAppId
, cws_page_ordinal
.CreateAfter());
359 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
362 // Adjust the launch type on the first client and sync. Both clients should
363 // have the same launch type values for the CWS.
364 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, UpdateLaunchType
) {
365 ASSERT_TRUE(SetupSync());
366 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
368 // Change the launch type to window.
369 extensions::SetLaunchType(GetProfile(1), extensions::kWebStoreAppId
,
370 extensions::LAUNCH_TYPE_WINDOW
);
371 extensions::SetLaunchType(verifier(), extensions::kWebStoreAppId
,
372 extensions::LAUNCH_TYPE_WINDOW
);
373 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
375 // Change the launch type to regular tab.
376 extensions::SetLaunchType(GetProfile(1), extensions::kWebStoreAppId
,
377 extensions::LAUNCH_TYPE_REGULAR
);
378 ASSERT_FALSE(HasSameAppsAsVerifier(1));
379 extensions::SetLaunchType(verifier(), extensions::kWebStoreAppId
,
380 extensions::LAUNCH_TYPE_REGULAR
);
381 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
384 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, UnexpectedLaunchType
) {
385 ASSERT_TRUE(SetupSync());
386 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
388 extensions::SetLaunchType(GetProfile(1), extensions::kWebStoreAppId
,
389 extensions::LAUNCH_TYPE_REGULAR
);
390 extensions::SetLaunchType(verifier(), extensions::kWebStoreAppId
,
391 extensions::LAUNCH_TYPE_REGULAR
);
392 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
394 const extensions::Extension
* extension
=
395 GetExtensionRegistry(GetProfile(1))->GetExtensionById(
396 extensions::kWebStoreAppId
,
397 extensions::ExtensionRegistry::EVERYTHING
);
398 ASSERT_TRUE(extension
);
400 ExtensionSyncService
* extension_sync_service
=
401 ExtensionSyncService::Get(GetProfile(1));
403 extensions::ExtensionSyncData
original_data(
404 extension_sync_service
->CreateSyncData(*extension
));
406 // Create an invalid launch type and ensure it doesn't get down-synced. This
407 // simulates the case of a future launch type being added which old versions
408 // don't yet understand.
409 extensions::ExtensionSyncData
invalid_launch_type_data(
411 original_data
.enabled(),
412 original_data
.disable_reasons(),
413 original_data
.incognito_enabled(),
414 original_data
.remote_install(),
415 original_data
.all_urls_enabled(),
416 original_data
.app_launch_ordinal(),
417 original_data
.page_ordinal(),
418 extensions::NUM_LAUNCH_TYPES
);
419 extension_sync_service
->ApplySyncData(invalid_launch_type_data
);
421 // The launch type should remain the same.
422 ASSERT_TRUE(AwaitAllProfilesHaveSameApps());
425 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest
, BookmarkApp
) {
426 ASSERT_TRUE(SetupSync());
427 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
429 size_t num_extensions
=
430 GetExtensionRegistry(GetProfile(0))->enabled_extensions().size();
432 WebApplicationInfo web_app_info
;
433 web_app_info
.app_url
= GURL("http://www.chromium.org");
434 web_app_info
.title
= base::UTF8ToUTF16("Test name");
435 web_app_info
.description
= base::UTF8ToUTF16("Test description");
438 content::WindowedNotificationObserver
windowed_observer(
439 extensions::NOTIFICATION_CRX_INSTALLER_DONE
,
440 content::NotificationService::AllSources());
441 extensions::CreateOrUpdateBookmarkApp(GetExtensionService(GetProfile(0)),
443 windowed_observer
.Wait();
444 EXPECT_EQ(num_extensions
,
445 GetExtensionRegistry(GetProfile(0))->enabled_extensions().size());
448 content::WindowedNotificationObserver
windowed_observer(
449 extensions::NOTIFICATION_CRX_INSTALLER_DONE
,
450 content::NotificationService::AllSources());
451 extensions::CreateOrUpdateBookmarkApp(GetExtensionService(verifier()),
453 windowed_observer
.Wait();
454 EXPECT_EQ(num_extensions
,
455 GetExtensionRegistry(verifier())->enabled_extensions().size());
458 // Wait for the synced app to install.
459 content::WindowedNotificationObserver
windowed_observer(
460 extensions::NOTIFICATION_CRX_INSTALLER_DONE
,
461 base::Bind(&AllProfilesHaveSameAppsAsVerifier
));
462 windowed_observer
.Wait();
466 // TODO(akalin): Add tests exercising:
467 // - Offline installation/uninstallation behavior
468 // - App-specific properties