two_client_apps_sync_test.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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/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"
27
28using apps_helper::AllProfilesHaveSameAppsAsVerifier;
29using apps_helper::CopyNTPOrdinals;
30using apps_helper::DisableApp;
31using apps_helper::EnableApp;
32using apps_helper::FixNTPOrdinalCollisions;
33using apps_helper::GetAppLaunchOrdinalForApp;
34using apps_helper::HasSameAppsAsVerifier;
35using apps_helper::IncognitoDisableApp;
36using apps_helper::IncognitoEnableApp;
37using apps_helper::InstallApp;
38using apps_helper::InstallPlatformApp;
39using apps_helper::SetAppLaunchOrdinalForApp;
40using apps_helper::SetPageOrdinalForApp;
41using apps_helper::UninstallApp;
42using apps_helper::AwaitAllProfilesHaveSameAppsAsVerifier;
43
44namespace {
45
46extensions::ExtensionRegistry* GetExtensionRegistry(Profile* profile) {
47  return extensions::ExtensionRegistry::Get(profile);
48}
49
50ExtensionService* GetExtensionService(Profile* profile) {
51  return extensions::ExtensionSystem::Get(profile)->extension_service();
52}
53
54}  // namespace
55
56class TwoClientAppsSyncTest : public SyncTest {
57 public:
58  TwoClientAppsSyncTest() : SyncTest(TWO_CLIENT) {}
59
60  virtual ~TwoClientAppsSyncTest() {}
61
62  virtual bool TestUsesSelfNotifications() OVERRIDE { return false; }
63
64 private:
65  DISALLOW_COPY_AND_ASSIGN(TwoClientAppsSyncTest);
66};
67
68IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, StartWithNoApps) {
69  ASSERT_TRUE(SetupSync());
70
71  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
72}
73
74IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, StartWithSameApps) {
75  ASSERT_TRUE(SetupClients());
76
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);
82  }
83
84  ASSERT_TRUE(SetupSync());
85
86  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
87}
88
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.
92IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, StartWithDifferentApps) {
93  ASSERT_TRUE(SetupClients());
94
95  int i = 0;
96
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);
102  }
103
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);
109  }
110
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);
116  }
117
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);
123  }
124
125  FixNTPOrdinalCollisions(verifier());
126
127  ASSERT_TRUE(SetupSync());
128
129  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
130}
131
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.
135IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, InstallDifferentApps) {
136  ASSERT_TRUE(SetupClients());
137
138  int i = 0;
139
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);
145  }
146
147  ASSERT_TRUE(SetupSync());
148
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);
154  }
155
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);
161  }
162
163  FixNTPOrdinalCollisions(verifier());
164
165  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
166}
167
168// TCM ID - 3711279.
169IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, Add) {
170  ASSERT_TRUE(SetupSync());
171  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
172
173  InstallApp(GetProfile(0), 0);
174  InstallApp(verifier(), 0);
175
176  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
177}
178
179// TCM ID - 3706267.
180IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, Uninstall) {
181  ASSERT_TRUE(SetupSync());
182  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
183
184  InstallApp(GetProfile(0), 0);
185  InstallApp(verifier(), 0);
186  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
187
188  UninstallApp(GetProfile(0), 0);
189  UninstallApp(verifier(), 0);
190  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
191}
192
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
196// ordinals.
197IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UninstallThenInstall) {
198  ASSERT_TRUE(SetupSync());
199
200  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
201
202  InstallApp(GetProfile(0), 0);
203  InstallApp(verifier(), 0);
204  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
205
206  UninstallApp(GetProfile(0), 0);
207  UninstallApp(verifier(), 0);
208  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
209
210  InstallApp(GetProfile(0), 1);
211  InstallApp(verifier(), 1);
212  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
213}
214
215// TCM ID - 3699295.
216IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, Merge) {
217  ASSERT_TRUE(SetupSync());
218  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
219
220  InstallApp(GetProfile(0), 0);
221  InstallApp(verifier(), 0);
222  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
223
224  UninstallApp(GetProfile(0), 0);
225  UninstallApp(verifier(), 0);
226
227  InstallApp(GetProfile(0), 1);
228  InstallApp(verifier(), 1);
229
230  InstallApp(GetProfile(0), 2);
231  InstallApp(GetProfile(1), 2);
232  InstallApp(verifier(), 2);
233
234  InstallApp(GetProfile(1), 3);
235  InstallApp(verifier(), 3);
236
237  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
238}
239
240// TCM ID - 7723126.
241IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateEnableDisableApp) {
242  ASSERT_TRUE(SetupSync());
243  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
244
245  InstallApp(GetProfile(0), 0);
246  InstallApp(verifier(), 0);
247  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
248
249  DisableApp(GetProfile(0), 0);
250  DisableApp(verifier(), 0);
251  ASSERT_TRUE(HasSameAppsAsVerifier(0));
252  ASSERT_FALSE(HasSameAppsAsVerifier(1));
253
254  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
255
256  EnableApp(GetProfile(1), 0);
257  EnableApp(verifier(), 0);
258  ASSERT_TRUE(HasSameAppsAsVerifier(1));
259  ASSERT_FALSE(HasSameAppsAsVerifier(0));
260
261  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
262}
263
264// TCM ID - 7706637.
265IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateIncognitoEnableDisable) {
266  ASSERT_TRUE(SetupSync());
267  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
268
269  InstallApp(GetProfile(0), 0);
270  InstallApp(verifier(), 0);
271  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
272
273  IncognitoEnableApp(GetProfile(0), 0);
274  IncognitoEnableApp(verifier(), 0);
275  ASSERT_TRUE(HasSameAppsAsVerifier(0));
276  ASSERT_FALSE(HasSameAppsAsVerifier(1));
277
278  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
279
280  IncognitoDisableApp(GetProfile(1), 0);
281  IncognitoDisableApp(verifier(), 0);
282  ASSERT_TRUE(HasSameAppsAsVerifier(1));
283  ASSERT_FALSE(HasSameAppsAsVerifier(0));
284
285  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
286}
287
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
290// the app.
291IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdatePageOrdinal) {
292  ASSERT_TRUE(SetupSync());
293  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
294
295  syncer::StringOrdinal initial_page =
296      syncer::StringOrdinal::CreateInitialOrdinal();
297  InstallApp(GetProfile(0), 0);
298  InstallApp(verifier(), 0);
299  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
300
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());
305}
306
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.
310IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateAppLaunchOrdinal) {
311  ASSERT_TRUE(SetupSync());
312  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
313
314  InstallApp(GetProfile(0), 0);
315  InstallApp(verifier(), 0);
316  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
317
318  syncer::StringOrdinal initial_position =
319      GetAppLaunchOrdinalForApp(GetProfile(0), 0);
320
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());
325}
326
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.
330IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateCWSOrdinals) {
331  ASSERT_TRUE(SetupSync());
332  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
333
334  // Change the app launch ordinal.
335  syncer::StringOrdinal cws_app_launch_ordinal =
336      extensions::ExtensionPrefs::Get(GetProfile(0))
337          ->app_sorting()
338          ->GetAppLaunchOrdinal(extension_misc::kWebStoreAppId);
339  extensions::ExtensionPrefs::Get(GetProfile(0))
340      ->app_sorting()
341      ->SetAppLaunchOrdinal(extension_misc::kWebStoreAppId,
342                            cws_app_launch_ordinal.CreateAfter());
343  extensions::ExtensionPrefs::Get(verifier())
344      ->app_sorting()
345      ->SetAppLaunchOrdinal(extension_misc::kWebStoreAppId,
346                            cws_app_launch_ordinal.CreateAfter());
347  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
348
349  // Change the page ordinal.
350  syncer::StringOrdinal cws_page_ordinal =
351      extensions::ExtensionPrefs::Get(GetProfile(1))
352          ->app_sorting()
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());
359}
360
361// Adjust the launch type on the first client and sync. Both clients should
362// have the same launch type values for the CWS.
363IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UpdateLaunchType) {
364  ASSERT_TRUE(SetupSync());
365  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
366
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());
375
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());
385}
386
387IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, UnexpectedLaunchType) {
388  ASSERT_TRUE(SetupSync());
389  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
390
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());
398
399  const extensions::Extension* extension =
400      GetExtensionRegistry(GetProfile(1))->GetExtensionById(
401          extension_misc::kWebStoreAppId,
402          extensions::ExtensionRegistry::EVERYTHING);
403  ASSERT_TRUE(extension);
404
405  ExtensionSyncService* extension_sync_service =
406      ExtensionSyncService::Get(GetProfile(1));
407
408  extensions::AppSyncData original_data(
409      extension_sync_service->GetAppSyncData(*extension));
410
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(
415      *extension,
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);
423
424  // The launch type should remain the same.
425  ASSERT_TRUE(AwaitAllProfilesHaveSameAppsAsVerifier());
426}
427
428IN_PROC_BROWSER_TEST_F(TwoClientAppsSyncTest, BookmarkApp) {
429  ASSERT_TRUE(SetupSync());
430  ASSERT_TRUE(AllProfilesHaveSameAppsAsVerifier());
431
432  size_t num_extensions =
433      GetExtensionRegistry(GetProfile(0))->enabled_extensions().size();
434
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");
439  ++num_extensions;
440  {
441    content::WindowedNotificationObserver windowed_observer(
442        extensions::NOTIFICATION_CRX_INSTALLER_DONE,
443        content::NotificationService::AllSources());
444    extensions::CreateOrUpdateBookmarkApp(GetExtensionService(GetProfile(0)),
445                                          web_app_info);
446    windowed_observer.Wait();
447    EXPECT_EQ(num_extensions,
448              GetExtensionRegistry(GetProfile(0))->enabled_extensions().size());
449  }
450  {
451    content::WindowedNotificationObserver windowed_observer(
452        extensions::NOTIFICATION_CRX_INSTALLER_DONE,
453        content::NotificationService::AllSources());
454    extensions::CreateOrUpdateBookmarkApp(GetExtensionService(verifier()),
455                                          web_app_info);
456    windowed_observer.Wait();
457    EXPECT_EQ(num_extensions,
458              GetExtensionRegistry(verifier())->enabled_extensions().size());
459  }
460  {
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();
466  }
467}
468
469// TODO(akalin): Add tests exercising:
470//   - Offline installation/uninstallation behavior
471//   - App-specific properties
472