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/app_sync_data.h"
9 #include "chrome/browser/extensions/bookmark_app_helper.h"
10 #include "chrome/browser/extensions/extension_service.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 "chrome/common/extensions/extension_constants.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/test/test_utils.h"
22 #include "extensions/browser/app_sorting.h"
23 #include "extensions/browser/extension_prefs.h"
24 #include "extensions/browser/extension_registry.h"
25 #include "extensions/browser/extension_system.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::AwaitAllProfilesHaveSameAppsAsVerifier;
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 virtual ~TwoClientAppsSyncTest() {}
62 virtual 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(AwaitAllProfilesHaveSameAppsAsVerifier());
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(AwaitAllProfilesHaveSameAppsAsVerifier());
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 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, StartWithDifferentApps) {
93 ASSERT_TRUE(SetupClients());
97 const int kNumCommonApps = 5;
98 for (int j = 0; j < kNumCommonApps; ++i, ++j) {
99 InstallApp(GetProfile(0), i);
100 InstallApp(GetProfile(1), i);
101 InstallApp(verifier(), i);
104 const int kNumProfile0Apps = 10;
105 for (int j = 0; j < kNumProfile0Apps; ++i, ++j) {
106 InstallApp(GetProfile(0), i);
107 InstallApp(verifier(), i);
108 CopyNTPOrdinals(GetProfile(0), verifier(), i);
111 const int kNumProfile1Apps = 10;
112 for (int j = 0; j < kNumProfile1Apps; ++i, ++j) {
113 InstallApp(GetProfile(1), i);
114 InstallApp(verifier(), i);
115 CopyNTPOrdinals(GetProfile(1), verifier(), i);
118 const int kNumPlatformApps = 5;
119 for (int j = 0; j < kNumPlatformApps; ++i, ++j) {
120 InstallPlatformApp(GetProfile(1), i);
121 InstallPlatformApp(verifier(), i);
122 CopyNTPOrdinals(GetProfile(1), verifier(), i);
125 FixNTPOrdinalCollisions(verifier());
127 ASSERT_TRUE(SetupSync());
129 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
132 // Install some apps on both clients, then sync. Then install some apps on only
133 // one client, some on only the other, and then sync again. Both clients should
134 // end up with all apps, and the app and page ordinals should be identical.
135 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, InstallDifferentApps) {
136 ASSERT_TRUE(SetupClients());
140 const int kNumCommonApps = 5;
141 for (int j = 0; j < kNumCommonApps; ++i, ++j) {
142 InstallApp(GetProfile(0), i);
143 InstallApp(GetProfile(1), i);
144 InstallApp(verifier(), i);
147 ASSERT_TRUE(SetupSync());
149 const int kNumProfile0Apps = 10;
150 for (int j = 0; j < kNumProfile0Apps; ++i, ++j) {
151 InstallApp(GetProfile(0), i);
152 InstallApp(verifier(), i);
153 CopyNTPOrdinals(GetProfile(0), verifier(), i);
156 const int kNumProfile1Apps = 10;
157 for (int j = 0; j < kNumProfile1Apps; ++i, ++j) {
158 InstallApp(GetProfile(1), i);
159 InstallApp(verifier(), i);
160 CopyNTPOrdinals(GetProfile(1), verifier(), i);
163 FixNTPOrdinalCollisions(verifier());
165 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
169 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, Add) {
170 ASSERT_TRUE(SetupSync());
171 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
173 InstallApp(GetProfile(0), 0);
174 InstallApp(verifier(), 0);
176 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
180 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, Uninstall) {
181 ASSERT_TRUE(SetupSync());
182 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
184 InstallApp(GetProfile(0), 0);
185 InstallApp(verifier(), 0);
186 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
188 UninstallApp(GetProfile(0), 0);
189 UninstallApp(verifier(), 0);
190 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
193 // Install an app on one client, then sync. Then uninstall the app on the first
194 // client and sync again. Now install a new app on the first client and sync.
195 // Both client should only have the second app, with identical app and page
197 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UninstallThenInstall) {
198 ASSERT_TRUE(SetupSync());
200 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
202 InstallApp(GetProfile(0), 0);
203 InstallApp(verifier(), 0);
204 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
206 UninstallApp(GetProfile(0), 0);
207 UninstallApp(verifier(), 0);
208 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
210 InstallApp(GetProfile(0), 1);
211 InstallApp(verifier(), 1);
212 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
216 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, Merge) {
217 ASSERT_TRUE(SetupSync());
218 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
220 InstallApp(GetProfile(0), 0);
221 InstallApp(verifier(), 0);
222 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
224 UninstallApp(GetProfile(0), 0);
225 UninstallApp(verifier(), 0);
227 InstallApp(GetProfile(0), 1);
228 InstallApp(verifier(), 1);
230 InstallApp(GetProfile(0), 2);
231 InstallApp(GetProfile(1), 2);
232 InstallApp(verifier(), 2);
234 InstallApp(GetProfile(1), 3);
235 InstallApp(verifier(), 3);
237 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
241 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateEnableDisableApp) {
242 ASSERT_TRUE(SetupSync());
243 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
245 InstallApp(GetProfile(0), 0);
246 InstallApp(verifier(), 0);
247 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
249 DisableApp(GetProfile(0), 0);
250 DisableApp(verifier(), 0);
251 ASSERT_TRUE(HasSameAppsAsVerifier(0));
252 ASSERT_FALSE(HasSameAppsAsVerifier(1));
254 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
256 EnableApp(GetProfile(1), 0);
257 EnableApp(verifier(), 0);
258 ASSERT_TRUE(HasSameAppsAsVerifier(1));
259 ASSERT_FALSE(HasSameAppsAsVerifier(0));
261 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
265 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateIncognitoEnableDisable) {
266 ASSERT_TRUE(SetupSync());
267 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
269 InstallApp(GetProfile(0), 0);
270 InstallApp(verifier(), 0);
271 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
273 IncognitoEnableApp(GetProfile(0), 0);
274 IncognitoEnableApp(verifier(), 0);
275 ASSERT_TRUE(HasSameAppsAsVerifier(0));
276 ASSERT_FALSE(HasSameAppsAsVerifier(1));
278 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
280 IncognitoDisableApp(GetProfile(1), 0);
281 IncognitoDisableApp(verifier(), 0);
282 ASSERT_TRUE(HasSameAppsAsVerifier(1));
283 ASSERT_FALSE(HasSameAppsAsVerifier(0));
285 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
288 // Install the same app on both clients, then sync. Change the page ordinal on
289 // one client and sync. Both clients should have the updated page ordinal for
291 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdatePageOrdinal) {
292 ASSERT_TRUE(SetupSync());
293 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
295 syncer::StringOrdinal initial_page =
296 syncer::StringOrdinal::CreateInitialOrdinal();
297 InstallApp(GetProfile(0), 0);
298 InstallApp(verifier(), 0);
299 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
301 syncer::StringOrdinal second_page = initial_page.CreateAfter();
302 SetPageOrdinalForApp(GetProfile(0), 0, second_page);
303 SetPageOrdinalForApp(verifier(), 0, second_page);
304 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
307 // Install the same app on both clients, then sync. Change the app launch
308 // ordinal on one client and sync. Both clients should have the updated app
309 // launch ordinal for the app.
310 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateAppLaunchOrdinal) {
311 ASSERT_TRUE(SetupSync());
312 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
314 InstallApp(GetProfile(0), 0);
315 InstallApp(verifier(), 0);
316 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
318 syncer::StringOrdinal initial_position =
319 GetAppLaunchOrdinalForApp(GetProfile(0), 0);
321 syncer::StringOrdinal second_position = initial_position.CreateAfter();
322 SetAppLaunchOrdinalForApp(GetProfile(0), 0, second_position);
323 SetAppLaunchOrdinalForApp(verifier(), 0, second_position);
324 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
327 // Adjust the CWS location within a page on the first client and sync. Adjust
328 // which page the CWS appears on and sync. Both clients should have the same
329 // page and app launch ordinal values for the CWS.
330 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateCWSOrdinals) {
331 ASSERT_TRUE(SetupSync());
332 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
334 // Change the app launch ordinal.
335 syncer::StringOrdinal cws_app_launch_ordinal =
336 extensions::ExtensionPrefs::Get(GetProfile(0))
338 ->GetAppLaunchOrdinal(extension_misc::kWebStoreAppId);
339 extensions::ExtensionPrefs::Get(GetProfile(0))
341 ->SetAppLaunchOrdinal(extension_misc::kWebStoreAppId,
342 cws_app_launch_ordinal.CreateAfter());
343 extensions::ExtensionPrefs::Get(verifier())
345 ->SetAppLaunchOrdinal(extension_misc::kWebStoreAppId,
346 cws_app_launch_ordinal.CreateAfter());
347 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
349 // Change the page ordinal.
350 syncer::StringOrdinal cws_page_ordinal =
351 extensions::ExtensionPrefs::Get(GetProfile(1))
353 ->GetPageOrdinal(extension_misc::kWebStoreAppId);
354 extensions::ExtensionPrefs::Get(GetProfile(1))->app_sorting()->SetPageOrdinal(
355 extension_misc::kWebStoreAppId, cws_page_ordinal.CreateAfter());
356 extensions::ExtensionPrefs::Get(verifier())->app_sorting()->SetPageOrdinal(
357 extension_misc::kWebStoreAppId, cws_page_ordinal.CreateAfter());
358 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
361 // Adjust the launch type on the first client and sync. Both clients should
362 // have the same launch type values for the CWS.
363 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateLaunchType) {
364 ASSERT_TRUE(SetupSync());
365 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
367 // Change the launch type to window.
368 extensions::SetLaunchType(GetExtensionService(GetProfile(1)),
369 extension_misc::kWebStoreAppId,
370 extensions::LAUNCH_TYPE_WINDOW);
371 extensions::SetLaunchType(GetExtensionService(verifier()),
372 extension_misc::kWebStoreAppId,
373 extensions::LAUNCH_TYPE_WINDOW);
374 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
376 // Change the launch type to regular tab.
377 extensions::SetLaunchType(GetExtensionService(GetProfile(1)),
378 extension_misc::kWebStoreAppId,
379 extensions::LAUNCH_TYPE_REGULAR);
380 ASSERT_FALSE(HasSameAppsAsVerifier(1));
381 extensions::SetLaunchType(GetExtensionService(verifier()),
382 extension_misc::kWebStoreAppId,
383 extensions::LAUNCH_TYPE_REGULAR);
384 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
387 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UnexpectedLaunchType) {
388 ASSERT_TRUE(SetupSync());
389 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
391 extensions::SetLaunchType(GetExtensionService(GetProfile(1)),
392 extension_misc::kWebStoreAppId,
393 extensions::LAUNCH_TYPE_REGULAR);
394 extensions::SetLaunchType(GetExtensionService(verifier()),
395 extension_misc::kWebStoreAppId,
396 extensions::LAUNCH_TYPE_REGULAR);
397 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
399 const extensions::Extension* extension =
400 GetExtensionRegistry(GetProfile(1))->GetExtensionById(
401 extension_misc::kWebStoreAppId,
402 extensions::ExtensionRegistry::EVERYTHING);
403 ASSERT_TRUE(extension);
405 ExtensionSyncService* extension_sync_service =
406 ExtensionSyncService::Get(GetProfile(1));
408 extensions::AppSyncData original_data(
409 extension_sync_service->GetAppSyncData(*extension));
411 // Create an invalid launch type and ensure it doesn't get down-synced. This
412 // simulates the case of a future launch type being added which old versions
413 // don't yet understand.
414 extensions::AppSyncData invalid_launch_type_data(
416 original_data.extension_sync_data().enabled(),
417 original_data.extension_sync_data().incognito_enabled(),
418 original_data.extension_sync_data().remote_install(),
419 original_data.app_launch_ordinal(),
420 original_data.page_ordinal(),
421 extensions::NUM_LAUNCH_TYPES);
422 extension_sync_service->ProcessAppSyncData(invalid_launch_type_data);
424 // The launch type should remain the same.
425 ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
428 IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, BookmarkApp) {
429 ASSERT_TRUE(SetupSync());
430 ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
432 size_t num_extensions =
433 GetExtensionRegistry(GetProfile(0))->enabled_extensions().size();
435 WebApplicationInfo web_app_info;
436 web_app_info.app_url = GURL("http://www.chromium.org");
437 web_app_info.title = base::UTF8ToUTF16("Test name");
438 web_app_info.description = base::UTF8ToUTF16("Test description");
441 content::WindowedNotificationObserver windowed_observer(
442 extensions::NOTIFICATION_CRX_INSTALLER_DONE,
443 content::NotificationService::AllSources());
444 extensions::CreateOrUpdateBookmarkApp(GetExtensionService(GetProfile(0)),
446 windowed_observer.Wait();
447 EXPECT_EQ(num_extensions,
448 GetExtensionRegistry(GetProfile(0))->enabled_extensions().size());
451 content::WindowedNotificationObserver windowed_observer(
452 extensions::NOTIFICATION_CRX_INSTALLER_DONE,
453 content::NotificationService::AllSources());
454 extensions::CreateOrUpdateBookmarkApp(GetExtensionService(verifier()),
456 windowed_observer.Wait();
457 EXPECT_EQ(num_extensions,
458 GetExtensionRegistry(verifier())->enabled_extensions().size());
461 // Wait for the synced app to install.
462 content::WindowedNotificationObserver windowed_observer(
463 extensions::NOTIFICATION_CRX_INSTALLER_DONE,
464 base::Bind(&AllProfilesHaveSameAppsAsVerifier));
465 windowed_observer.Wait();
469 // TODO(akalin): Add tests exercising:
470 // - Offline installation/uninstallation behavior
471 // - App-specific properties