1 // Copyright 2019 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/macros.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "base/test/bind.h"
9 #include "build/build_config.h"
10 #include "chrome/app/chrome_command_ids.h"
11 #include "chrome/browser/installable/installable_metrics.h"
12 #include "chrome/browser/sync/test/integration/sync_test.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_commands.h"
15 #include "chrome/browser/ui/browser_dialogs.h"
16 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
17 #include "chrome/browser/web_applications/components/app_registry_controller.h"
18 #include "chrome/browser/web_applications/components/app_shortcut_manager.h"
19 #include "chrome/browser/web_applications/components/install_finalizer.h"
20 #include "chrome/browser/web_applications/components/install_manager.h"
21 #include "chrome/browser/web_applications/components/os_integration_manager.h"
22 #include "chrome/browser/web_applications/components/web_application_info.h"
23 #include "chrome/browser/web_applications/test/test_os_integration_manager.h"
24 #include "chrome/browser/web_applications/test/test_web_app_provider.h"
25 #include "chrome/browser/web_applications/test/web_app_install_observer.h"
26 #include "chrome/browser/web_applications/test/web_app_test.h"
27 #include "chrome/browser/web_applications/web_app.h"
28 #include "chrome/browser/web_applications/web_app_provider.h"
29 #include "chrome/browser/web_applications/web_app_registrar.h"
30 #include "chrome/test/base/ui_test_utils.h"
31 #include "content/public/test/browser_test.h"
32 #include "content/public/test/test_utils.h"
33 #include "extensions/browser/app_sorting.h"
34 #include "extensions/browser/extension_system.h"
35
36 namespace web_app {
37 namespace {
38
CreateTestWebAppProvider(Profile * profile)39 std::unique_ptr<KeyedService> CreateTestWebAppProvider(Profile* profile) {
40 auto provider = std::make_unique<TestWebAppProvider>(profile);
41 provider->SetOsIntegrationManager(
42 std::make_unique<TestOsIntegrationManager>(profile, nullptr, nullptr));
43 provider->Start();
44 DCHECK(provider);
45 return provider;
46 }
47
48 class TwoClientWebAppsBMOSyncTest : public SyncTest {
49 public:
TwoClientWebAppsBMOSyncTest()50 TwoClientWebAppsBMOSyncTest()
51 : SyncTest(TWO_CLIENT),
52 test_web_app_provider_creator_(
53 base::BindRepeating(&CreateTestWebAppProvider)) {}
54 ~TwoClientWebAppsBMOSyncTest() override = default;
55
SetupClients()56 bool SetupClients() override {
57 bool result = SyncTest::SetupClients();
58 if (!result)
59 return result;
60 for (Profile* profile : GetAllProfiles()) {
61 auto* web_app_provider = WebAppProvider::Get(profile);
62 web_app_provider->install_finalizer()
63 .RemoveLegacyInstallFinalizerForTesting();
64 base::RunLoop loop;
65 web_app_provider->on_registry_ready().Post(FROM_HERE, loop.QuitClosure());
66 loop.Run();
67 }
68 return true;
69 }
70
71 // Installs a dummy app with the given |url| on |profile1| and waits for it to
72 // sync to |profile2|. This ensures that the sync system has fully flushed any
73 // pending changes from |profile1| to |profile2|.
InstallDummyAppAndWaitForSync(const GURL & url,Profile * profile1,Profile * profile2)74 AppId InstallDummyAppAndWaitForSync(const GURL& url,
75 Profile* profile1,
76 Profile* profile2) {
77 WebApplicationInfo info = WebApplicationInfo();
78 info.title = base::UTF8ToUTF16(url.spec());
79 info.start_url = url;
80 AppId dummy_app_id = InstallApp(info, profile1);
81 EXPECT_EQ(
82 WebAppInstallObserver::CreateInstallListener(profile2, {dummy_app_id})
83 ->AwaitNextInstall(),
84 dummy_app_id);
85 return dummy_app_id;
86 }
87
GetUserInitiatedAppURL() const88 GURL GetUserInitiatedAppURL() const {
89 return embedded_test_server()->GetURL("/web_apps/basic.html");
90 }
91
GetUserInitiatedAppURL2() const92 GURL GetUserInitiatedAppURL2() const {
93 return embedded_test_server()->GetURL("/web_apps/no_service_worker.html");
94 }
95
InstallAppAsUserInitiated(Profile * profile,WebappInstallSource source=WebappInstallSource::OMNIBOX_INSTALL_ICON,GURL start_url=GURL ())96 AppId InstallAppAsUserInitiated(
97 Profile* profile,
98 WebappInstallSource source = WebappInstallSource::OMNIBOX_INSTALL_ICON,
99 GURL start_url = GURL()) {
100 Browser* browser = CreateBrowser(profile);
101 if (!start_url.is_valid())
102 start_url = GetUserInitiatedAppURL();
103 ui_test_utils::NavigateToURL(browser, start_url);
104
105 AppId app_id;
106 base::RunLoop run_loop;
107 WebAppProvider::Get(profile)
108 ->install_manager()
109 .InstallWebAppFromManifestWithFallback(
110 browser->tab_strip_model()->GetActiveWebContents(),
111 /*force_shortcut_app=*/false, source,
112 base::BindOnce(TestAcceptDialogCallback),
113 base::BindLambdaForTesting(
114 [&](const AppId& new_app_id, InstallResultCode code) {
115 EXPECT_EQ(code, InstallResultCode::kSuccessNewInstall);
116 app_id = new_app_id;
117 run_loop.Quit();
118 }));
119 run_loop.Run();
120 return app_id;
121 }
122
InstallApp(const WebApplicationInfo & info,Profile * profile)123 AppId InstallApp(const WebApplicationInfo& info, Profile* profile) {
124 return InstallApp(info, profile, WebappInstallSource::OMNIBOX_INSTALL_ICON);
125 }
126
InstallApp(const WebApplicationInfo & info,Profile * profile,WebappInstallSource source)127 AppId InstallApp(const WebApplicationInfo& info,
128 Profile* profile,
129 WebappInstallSource source) {
130 DCHECK(info.start_url.is_valid());
131
132 base::RunLoop run_loop;
133 AppId app_id;
134
135 WebAppProvider::Get(profile)->install_manager().InstallWebAppFromInfo(
136 std::make_unique<WebApplicationInfo>(info), ForInstallableSite::kYes,
137 source,
138 base::BindLambdaForTesting(
139 [&run_loop, &app_id](const AppId& new_app_id,
140 InstallResultCode code) {
141 DCHECK_EQ(code, InstallResultCode::kSuccessNewInstall);
142 app_id = new_app_id;
143 run_loop.Quit();
144 }));
145 run_loop.Run();
146
147 const AppRegistrar& registrar = GetRegistrar(profile);
148 EXPECT_EQ(base::UTF8ToUTF16(registrar.GetAppShortName(app_id)), info.title);
149 EXPECT_EQ(registrar.GetAppStartUrl(app_id), info.start_url);
150
151 return app_id;
152 }
153
GetRegistrar(Profile * profile)154 const WebAppRegistrar& GetRegistrar(Profile* profile) {
155 auto* web_app_registrar =
156 WebAppProvider::Get(profile)->registrar().AsWebAppRegistrar();
157 EXPECT_TRUE(web_app_registrar);
158 return *web_app_registrar;
159 }
160
GetOsIntegrationManager(Profile * profile)161 TestOsIntegrationManager& GetOsIntegrationManager(Profile* profile) {
162 return reinterpret_cast<TestOsIntegrationManager&>(
163 WebAppProvider::Get(profile)->os_integration_manager());
164 }
165
GetAppSorting(Profile * profile)166 extensions::AppSorting* GetAppSorting(Profile* profile) {
167 return extensions::ExtensionSystem::Get(profile)->app_sorting();
168 }
169
AllProfilesHaveSameWebAppIds()170 bool AllProfilesHaveSameWebAppIds() {
171 base::Optional<base::flat_set<AppId>> app_ids;
172 for (Profile* profile : GetAllProfiles()) {
173 base::flat_set<AppId> profile_app_ids(GetRegistrar(profile).GetAppIds());
174 if (!app_ids) {
175 app_ids = profile_app_ids;
176 } else {
177 if (app_ids != profile_app_ids)
178 return false;
179 }
180 }
181 return true;
182 }
183
184 private:
185 TestWebAppProviderCreator test_web_app_provider_creator_;
186
187 DISALLOW_COPY_AND_ASSIGN(TwoClientWebAppsBMOSyncTest);
188 };
189
190 // Test is flaky (crbug.com/1097050)
IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,DISABLED_SyncDoubleInstallation)191 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,
192 DISABLED_SyncDoubleInstallation) {
193 ASSERT_TRUE(SetupSync());
194 ASSERT_TRUE(embedded_test_server()->Start());
195 ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
196
197 // Install web app to both profiles.
198 AppId app_id = InstallAppAsUserInitiated(GetProfile(0));
199 AppId app_id2 = InstallAppAsUserInitiated(GetProfile(1));
200
201 EXPECT_EQ(app_id, app_id2);
202
203 // Install a 'dummy' app & wait for installation to ensure sync has processed
204 // the initial apps.
205 InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(0),
206 GetProfile(1));
207
208 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
209 }
210
IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,SyncDoubleInstallationDifferentNames)211 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,
212 SyncDoubleInstallationDifferentNames) {
213 ASSERT_TRUE(SetupClients());
214 WebApplicationInfo info;
215 info.title = base::UTF8ToUTF16("Test name");
216 info.start_url = GURL("http://www.chromium.org/path");
217
218 // Install web app to both profiles.
219 AppId app_id = InstallApp(info, GetProfile(0));
220 // The web app has a different title on the second profile.
221 info.title = base::UTF8ToUTF16("Test name 2");
222 AppId app_id2 = InstallApp(info, GetProfile(1));
223
224 EXPECT_EQ(app_id, app_id2);
225
226 ASSERT_TRUE(SetupSync());
227
228 // Install a 'dummy' app & wait for installation to ensure sync has processed
229 // the initial apps.
230 InstallDummyAppAndWaitForSync(GURL("http://www.dummy1.org/"), GetProfile(0),
231 GetProfile(1));
232 InstallDummyAppAndWaitForSync(GURL("http://www.dummy2.org/"), GetProfile(1),
233 GetProfile(0));
234
235 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
236 // The titles should respect the installation, even though the sync system
237 // would only have one name.
238 EXPECT_EQ(GetRegistrar(GetProfile(0)).GetAppShortName(app_id), "Test name");
239 EXPECT_EQ(GetRegistrar(GetProfile(1)).GetAppShortName(app_id), "Test name 2");
240 }
241
242 // Flaky, see crbug.com/1126404.
243 #if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS)
244 #define MAYBE_SyncDoubleInstallationDifferentUserDisplayMode \
245 DISABLED_SyncDoubleInstallationDifferentUserDisplayMode
246 #else
247 #define MAYBE_SyncDoubleInstallationDifferentUserDisplayMode \
248 SyncDoubleInstallationDifferentUserDisplayMode
249 #endif
IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,MAYBE_SyncDoubleInstallationDifferentUserDisplayMode)250 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,
251 MAYBE_SyncDoubleInstallationDifferentUserDisplayMode) {
252 ASSERT_TRUE(SetupSync());
253 ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
254
255 WebApplicationInfo info;
256 info.title = base::UTF8ToUTF16("Test name");
257 info.start_url = GURL("http://www.chromium.org/path");
258 info.open_as_window = true;
259
260 // Install web app to both profiles.
261 AppId app_id = InstallApp(info, GetProfile(0));
262 // The web app has a different open on the second profile.
263 info.open_as_window = false;
264 AppId app_id2 = InstallApp(info, GetProfile(1));
265
266 EXPECT_EQ(app_id, app_id2);
267
268 // Install a 'dummy' app & wait for installation to ensure sync has processed
269 // the initial apps.
270 InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(0),
271 GetProfile(1));
272
273 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
274
275 // The user display setting is syned, so these should match. However, the
276 // actual value here is racy.
277 EXPECT_EQ(GetRegistrar(GetProfile(0)).GetAppUserDisplayMode(app_id),
278 GetRegistrar(GetProfile(1)).GetAppUserDisplayMode(app_id));
279 }
280
IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,DisplayMode)281 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, DisplayMode) {
282 ASSERT_TRUE(SetupSync());
283 ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
284 ASSERT_TRUE(embedded_test_server()->Start());
285
286 // Install web app to profile 0 and wait for it to sync to profile 1.
287 AppId app_id = InstallAppAsUserInitiated(GetProfile(0));
288 EXPECT_EQ(WebAppInstallObserver(GetProfile(1)).AwaitNextInstall(), app_id);
289
290 WebAppProvider::Get(GetProfile(1))
291 ->registry_controller()
292 .SetAppUserDisplayMode(app_id, web_app::DisplayMode::kBrowser,
293 /*is_user_action=*/false);
294
295 // Install a 'dummy' app & wait for installation to ensure sync has processed
296 // the initial apps.
297 InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(1),
298 GetProfile(0));
299
300 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
301
302 // The change should have synced to profile 0.
303 EXPECT_EQ(GetRegistrar(GetProfile(0)).GetAppUserDisplayMode(app_id),
304 web_app::DisplayMode::kBrowser);
305 // The user display settings is synced, so it should match.
306 EXPECT_EQ(GetRegistrar(GetProfile(0)).GetAppUserDisplayMode(app_id),
307 GetRegistrar(GetProfile(1)).GetAppUserDisplayMode(app_id));
308 }
309
310 // Although the logic is allowed to be racy, the profiles should still end up
311 // with the same web app ids.
312 #if defined(OS_WIN)
313 // Flaky on windows, https://crbug.com/1111533
314 #define MAYBE_DoubleInstallWithUninstall DISABLED_DoubleInstallWithUninstall
315 #else
316 #define MAYBE_DoubleInstallWithUninstall DoubleInstallWithUninstall
317 #endif
IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,MAYBE_DoubleInstallWithUninstall)318 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,
319 MAYBE_DoubleInstallWithUninstall) {
320 ASSERT_TRUE(SetupSync());
321 ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
322 ASSERT_TRUE(embedded_test_server()->Start());
323
324 // Install web app to both profiles.
325 AppId app_id = InstallAppAsUserInitiated(GetProfile(0));
326 AppId app_id2 = InstallAppAsUserInitiated(GetProfile(1));
327 EXPECT_EQ(app_id, app_id2);
328
329 // Uninstall the app from one of the profiles.
330 UninstallWebApp(GetProfile(0), app_id);
331
332 // Install a 'dummy' app & wait for installation to ensure sync has processed
333 // the initial apps.
334 InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(0),
335 GetProfile(1));
336
337 // The apps should either be installed on both or uninstalled on both. This
338 // fails, hence disabled test.
339 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
340 }
341
IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,NotSynced)342 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, NotSynced) {
343 ASSERT_TRUE(SetupSync());
344 ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
345 ASSERT_TRUE(embedded_test_server()->Start());
346
347 // Install a non-syncing web app.
348 AppId app_id = InstallAppAsUserInitiated(
349 GetProfile(0), WebappInstallSource::EXTERNAL_DEFAULT);
350
351 // Install a 'dummy' app & wait for installation to ensure sync has processed
352 // the initial apps.
353 InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(0),
354 GetProfile(1));
355
356 // Profile 0 should have an extra unsynced app, and it should not be in
357 // profile 1.
358 EXPECT_FALSE(AllProfilesHaveSameWebAppIds());
359 EXPECT_FALSE(GetRegistrar(GetProfile(1)).IsInstalled(app_id));
360 }
361
IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,NotSyncedThenSynced)362 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, NotSyncedThenSynced) {
363 ASSERT_TRUE(SetupSync());
364 ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
365 ASSERT_TRUE(embedded_test_server()->Start());
366
367 // Install a non-syncing web app.
368 AppId app_id = InstallAppAsUserInitiated(
369 GetProfile(0), WebappInstallSource::EXTERNAL_DEFAULT);
370
371 // Install the same app as a syncing app on profile 1.
372 AppId app_id2 = InstallAppAsUserInitiated(GetProfile(1));
373 EXPECT_EQ(app_id, app_id2);
374
375 // Install a 'dummy' app & wait for installation to ensure sync has processed
376 // the initial apps.
377 InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(0),
378 GetProfile(1));
379
380 // The app is in both profiles.
381 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
382
383 // The app should have synced from profile 0 to profile 1, which enables sync
384 // on profile 0. So changes should propagate from profile 0 to profile 1 now.
385 WebAppProvider::Get(GetProfile(0))
386 ->registry_controller()
387 .SetAppUserDisplayMode(app_id, web_app::DisplayMode::kBrowser,
388 /*is_user_action=*/false);
389
390 // Install a 'dummy' app & wait for installation to ensure sync has processed
391 // the initial apps.
392 InstallDummyAppAndWaitForSync(GURL("http://www.seconddummy.org/"),
393 GetProfile(0), GetProfile(1));
394
395 // Check that profile 1 has the display mode change.
396 EXPECT_EQ(GetRegistrar(GetProfile(1)).GetAppUserDisplayMode(app_id),
397 web_app::DisplayMode::kBrowser);
398
399 // The user display settings is syned, so it should match.
400 EXPECT_EQ(GetRegistrar(GetProfile(0)).GetAppUserDisplayMode(app_id),
401 GetRegistrar(GetProfile(1)).GetAppUserDisplayMode(app_id));
402 }
403
IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,PolicyAppPersistsUninstalledOnSync)404 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,
405 PolicyAppPersistsUninstalledOnSync) {
406 ASSERT_TRUE(SetupSync());
407 ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
408 ASSERT_TRUE(embedded_test_server()->Start());
409
410 // Install a non-syncing web app.
411 AppId app_id = InstallAppAsUserInitiated(
412 GetProfile(0), WebappInstallSource::EXTERNAL_POLICY);
413
414 // Install the same app as a syncing app on profile 1.
415 AppId app_id2 = InstallAppAsUserInitiated(GetProfile(1));
416 EXPECT_EQ(app_id, app_id2);
417
418 // Install a 'dummy' app & wait for installation to ensure sync has processed
419 // the initial apps.
420 InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(1),
421 GetProfile(0));
422
423 // The app is in both profiles.
424 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
425 const WebApp* app = GetRegistrar(GetProfile(0)).GetAppById(app_id);
426 ASSERT_TRUE(app);
427 EXPECT_TRUE(app->IsPolicyInstalledApp());
428 EXPECT_TRUE(app->IsSynced());
429
430 // Uninstall the web app on the sync profile.
431 UninstallWebApp(GetProfile(1), app_id);
432
433 // Install a 'dummy' app & wait for installation to ensure sync has processed
434 // the initial apps.
435 InstallDummyAppAndWaitForSync(GURL("http://www.seconddummy.org/"),
436 GetProfile(1), GetProfile(0));
437
438 // The policy app should remain on profile 0.
439 EXPECT_FALSE(AllProfilesHaveSameWebAppIds());
440 app = GetRegistrar(GetProfile(0)).GetAppById(app_id);
441 ASSERT_TRUE(app);
442 EXPECT_TRUE(app->IsPolicyInstalledApp());
443 EXPECT_FALSE(app->IsSynced());
444 }
445
IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,AppSortingSynced)446 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, AppSortingSynced) {
447 ASSERT_TRUE(SetupSync());
448 ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
449 ASSERT_TRUE(embedded_test_server()->Start());
450
451 AppId app_id = InstallAppAsUserInitiated(GetProfile(0));
452
453 syncer::StringOrdinal page_ordinal =
454 GetAppSorting(GetProfile(0))->GetNaturalAppPageOrdinal();
455 syncer::StringOrdinal launch_ordinal =
456 GetAppSorting(GetProfile(0))->CreateNextAppLaunchOrdinal(page_ordinal);
457 GetAppSorting(GetProfile(0))->SetPageOrdinal(app_id, page_ordinal);
458 GetAppSorting(GetProfile(0))->SetAppLaunchOrdinal(app_id, launch_ordinal);
459
460 // Install a 'dummy' app & wait for installation to ensure sync has processed
461 // the initial apps.
462 InstallDummyAppAndWaitForSync(GURL("http://www.dummy.org/"), GetProfile(0),
463 GetProfile(1));
464
465 // The app is in both profiles.
466 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
467 EXPECT_EQ(page_ordinal, GetAppSorting(GetProfile(1))->GetPageOrdinal(app_id));
468 EXPECT_EQ(launch_ordinal,
469 GetAppSorting(GetProfile(1))->GetAppLaunchOrdinal(app_id));
470 }
471
IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,AppSortingFixCollisions)472 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, AppSortingFixCollisions) {
473 ASSERT_TRUE(SetupSync());
474 ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
475 ASSERT_TRUE(embedded_test_server()->Start());
476
477 // Install two different apps.
478 AppId app_id1 = InstallAppAsUserInitiated(GetProfile(0));
479 AppId app_id2 = InstallAppAsUserInitiated(
480 GetProfile(0), WebappInstallSource::OMNIBOX_INSTALL_ICON,
481 GetUserInitiatedAppURL2());
482
483 ASSERT_NE(app_id1, app_id2);
484
485 // Wait for both of the webapps to be installed on profile 1.
486 WebAppInstallObserver::CreateInstallListener(GetProfile(1),
487 {app_id1, app_id2})
488 ->AwaitNextInstall();
489 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
490
491 syncer::StringOrdinal page_ordinal =
492 GetAppSorting(GetProfile(0))->CreateFirstAppPageOrdinal();
493 syncer::StringOrdinal launch_ordinal =
494 GetAppSorting(GetProfile(0))->CreateNextAppLaunchOrdinal(page_ordinal);
495
496 GetAppSorting(GetProfile(0))->SetPageOrdinal(app_id1, page_ordinal);
497 GetAppSorting(GetProfile(0))->SetAppLaunchOrdinal(app_id1, launch_ordinal);
498 GetAppSorting(GetProfile(1))->SetPageOrdinal(app_id2, page_ordinal);
499 GetAppSorting(GetProfile(1))->SetAppLaunchOrdinal(app_id2, launch_ordinal);
500
501 // Install 'dummy' apps & wait for installation to ensure sync has processed
502 // the ordinals both ways.
503 InstallDummyAppAndWaitForSync(GURL("http://www.dummy1.org/"), GetProfile(0),
504 GetProfile(1));
505 InstallDummyAppAndWaitForSync(GURL("http://www.dummy2.org/"), GetProfile(1),
506 GetProfile(0));
507
508 // Page & launch ordinals should be synced.
509 EXPECT_EQ(GetAppSorting(GetProfile(0))->GetPageOrdinal(app_id1),
510 GetAppSorting(GetProfile(1))->GetPageOrdinal(app_id1));
511 EXPECT_EQ(GetAppSorting(GetProfile(0))->GetAppLaunchOrdinal(app_id1),
512 GetAppSorting(GetProfile(1))->GetAppLaunchOrdinal(app_id1));
513 EXPECT_EQ(GetAppSorting(GetProfile(0))->GetPageOrdinal(app_id2),
514 GetAppSorting(GetProfile(1))->GetPageOrdinal(app_id2));
515 EXPECT_EQ(GetAppSorting(GetProfile(0))->GetAppLaunchOrdinal(app_id2),
516 GetAppSorting(GetProfile(1))->GetAppLaunchOrdinal(app_id2));
517
518 // The page of app1 and app2 should be the same.
519 EXPECT_EQ(GetAppSorting(GetProfile(0))->GetPageOrdinal(app_id1),
520 GetAppSorting(GetProfile(0))->GetPageOrdinal(app_id2));
521 // But the launch ordinal must be different.
522 EXPECT_NE(GetAppSorting(GetProfile(0))->GetAppLaunchOrdinal(app_id1),
523 GetAppSorting(GetProfile(0))->GetAppLaunchOrdinal(app_id2));
524 }
525
IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,UninstallSynced)526 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, UninstallSynced) {
527 ASSERT_TRUE(SetupSync());
528 ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
529 ASSERT_TRUE(embedded_test_server()->Start());
530
531 AppId app_id;
532 // Install & uninstall on profile 0, and validate profile 1 sees it.
533 {
534 base::RunLoop loop;
535 WebAppInstallObserver app_listener(GetProfile(1));
536 app_listener.SetWebAppInstalledDelegate(
537 base::BindLambdaForTesting([&](const AppId& installed_app_id) {
538 app_id = installed_app_id;
539 loop.Quit();
540 }));
541 app_id = InstallAppAsUserInitiated(GetProfile(0));
542 loop.Run();
543 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
544 }
545
546 // Uninstall the webapp on profile 0, and validate profile 1 gets the change.
547 {
548 base::RunLoop loop;
549 WebAppInstallObserver app_listener(GetProfile(1));
550 app_listener.SetWebAppUninstalledDelegate(
551 base::BindLambdaForTesting([&](const AppId& uninstalled_app_id) {
552 app_id = uninstalled_app_id;
553 loop.Quit();
554 }));
555 UninstallWebApp(GetProfile(0), app_id);
556 loop.Run();
557 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
558 }
559
560 // Next, install on profile 1, uninstall on profile 0, and validate that
561 // profile 1 sees it.
562 {
563 base::RunLoop loop;
564 WebAppInstallObserver app_listener(GetProfile(0));
565 app_listener.SetWebAppInstalledDelegate(
566 base::BindLambdaForTesting([&](const AppId& installed_app_id) {
567 app_id = installed_app_id;
568 loop.Quit();
569 }));
570 app_id = InstallAppAsUserInitiated(GetProfile(1));
571 loop.Run();
572 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
573 }
574 {
575 base::RunLoop loop;
576 WebAppInstallObserver app_listener(GetProfile(1));
577 app_listener.SetWebAppUninstalledDelegate(
578 base::BindLambdaForTesting([&](const AppId& uninstalled_app_id) {
579 app_id = uninstalled_app_id;
580 loop.Quit();
581 }));
582 UninstallWebApp(GetProfile(0), app_id);
583 loop.Run();
584 }
585
586 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
587 }
588
IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest,NoShortcutsCreatedOnSync)589 IN_PROC_BROWSER_TEST_F(TwoClientWebAppsBMOSyncTest, NoShortcutsCreatedOnSync) {
590 ASSERT_TRUE(SetupSync());
591 ASSERT_TRUE(AllProfilesHaveSameWebAppIds());
592 ASSERT_TRUE(embedded_test_server()->Start());
593
594 // Install & uninstall on profile 0, and validate profile 1 sees it.
595 {
596 base::RunLoop loop;
597 base::RepeatingCallback<void(const AppId&)> on_installed_closure;
598 base::RepeatingCallback<void(const AppId&)> on_hooks_closure;
599 #if defined(OS_CHROMEOS)
600 on_installed_closure = base::DoNothing();
601 on_hooks_closure = base::BindLambdaForTesting(
602 [&](const AppId& installed_app_id) { loop.Quit(); });
603 #else
604 on_installed_closure = base::BindLambdaForTesting(
605 [&](const AppId& installed_app_id) { loop.Quit(); });
606 on_hooks_closure = base::BindLambdaForTesting(
607 [](const AppId& installed_app_id) { FAIL(); });
608 #endif
609 WebAppInstallObserver app_listener(GetProfile(1));
610 app_listener.SetWebAppInstalledDelegate(on_installed_closure);
611 app_listener.SetWebAppInstalledWithOsHooksDelegate(on_hooks_closure);
612 InstallAppAsUserInitiated(GetProfile(0));
613 loop.Run();
614 EXPECT_TRUE(AllProfilesHaveSameWebAppIds());
615 }
616 EXPECT_EQ(
617 1u, GetOsIntegrationManager(GetProfile(0)).num_create_shortcuts_calls());
618 #if defined(OS_CHROMEOS)
619 auto last_options =
620 GetOsIntegrationManager(GetProfile(1)).get_last_install_options();
621 EXPECT_TRUE(last_options.has_value());
622 OsHooksResults expected_os_hook_requests;
623 expected_os_hook_requests[OsHookType::kShortcuts] = true;
624 expected_os_hook_requests[OsHookType::kRunOnOsLogin] = false;
625 expected_os_hook_requests[OsHookType::kShortcutsMenu] = true;
626 expected_os_hook_requests[OsHookType::kFileHandlers] = true;
627 EXPECT_EQ(expected_os_hook_requests, last_options->os_hooks);
628 EXPECT_TRUE(last_options->add_to_desktop);
629 EXPECT_FALSE(last_options->add_to_quick_launch_bar);
630 EXPECT_EQ(
631 1u, GetOsIntegrationManager(GetProfile(1)).num_create_shortcuts_calls());
632 #else
633 EXPECT_FALSE(GetOsIntegrationManager(GetProfile(1))
634 .get_last_install_options()
635 .has_value());
636 #endif
637 }
638
639 } // namespace
640 } // namespace web_app
641