1 // Copyright 2018 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/web_applications/components/pending_app_manager.h"
6
7 #include <algorithm>
8 #include <sstream>
9 #include <vector>
10
11 #include "base/callback_helpers.h"
12 #include "base/run_loop.h"
13 #include "base/test/bind.h"
14 #include "base/test/task_environment.h"
15 #include "chrome/browser/web_applications/components/app_registrar.h"
16 #include "chrome/browser/web_applications/components/web_app_constants.h"
17 #include "chrome/browser/web_applications/test/test_pending_app_manager.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace web_app {
21
22 class PendingAppManagerTest : public testing::Test {
23 public:
PendingAppManagerTest()24 PendingAppManagerTest() : pending_app_manager_(®istrar_) {}
25
26 protected:
Sync(std::vector<GURL> urls)27 void Sync(std::vector<GURL> urls) {
28 pending_app_manager_.ResetCounts();
29
30 std::vector<ExternalInstallOptions> install_options_list;
31 for (const auto& url : urls) {
32 install_options_list.emplace_back(
33 url, DisplayMode::kStandalone,
34 ExternalInstallSource::kInternalDefault);
35 }
36
37 base::RunLoop run_loop;
38 pending_app_manager_.SynchronizeInstalledApps(
39 std::move(install_options_list),
40 ExternalInstallSource::kInternalDefault,
41 base::BindLambdaForTesting(
42 [&run_loop, urls](std::map<GURL, InstallResultCode> install_results,
43 std::map<GURL, bool> uninstall_results) {
44 run_loop.Quit();
45 }));
46 // Wait for SynchronizeInstalledApps to finish.
47 run_loop.Run();
48 }
49
Expect(int deduped_install_count,int deduped_uninstall_count,std::vector<GURL> installed_app_urls)50 void Expect(int deduped_install_count,
51 int deduped_uninstall_count,
52 std::vector<GURL> installed_app_urls) {
53 EXPECT_EQ(deduped_install_count,
54 pending_app_manager_.deduped_install_count());
55 EXPECT_EQ(deduped_uninstall_count,
56 pending_app_manager_.deduped_uninstall_count());
57
58 std::map<AppId, GURL> apps = registrar_.GetExternallyInstalledApps(
59 ExternalInstallSource::kInternalDefault);
60 std::vector<GURL> urls;
61 for (auto it : apps)
62 urls.push_back(it.second);
63
64 std::sort(urls.begin(), urls.end());
65 EXPECT_EQ(installed_app_urls, urls);
66 }
67
68 base::test::TaskEnvironment task_environment_;
69 TestAppRegistrar registrar_;
70 TestPendingAppManager pending_app_manager_;
71 };
72
73 // Test that destroying PendingAppManager during a synchronize call that
74 // installs an app doesn't crash.
75 // Regression test for https://crbug.com/962808
TEST_F(PendingAppManagerTest,DestroyDuringInstallInSynchronize)76 TEST_F(PendingAppManagerTest, DestroyDuringInstallInSynchronize) {
77 TestAppRegistrar registrar;
78 auto pending_app_manager =
79 std::make_unique<TestPendingAppManager>(®istrar);
80
81 std::vector<ExternalInstallOptions> install_options_list;
82 install_options_list.emplace_back(GURL("https://foo.example"),
83 DisplayMode::kStandalone,
84 ExternalInstallSource::kInternalDefault);
85 install_options_list.emplace_back(GURL("https://bar.example"),
86 DisplayMode::kStandalone,
87 ExternalInstallSource::kInternalDefault);
88
89 pending_app_manager->SynchronizeInstalledApps(
90 std::move(install_options_list), ExternalInstallSource::kInternalDefault,
91 // PendingAppManager gives no guarantees about whether its pending
92 // callbacks will be run or not when it gets destroyed.
93 base::DoNothing());
94 pending_app_manager.reset();
95 base::RunLoop().RunUntilIdle();
96 }
97
98 // Test that destroying PendingAppManager during a synchronize call that
99 // uninstalls an app doesn't crash.
100 // Regression test for https://crbug.com/962808
TEST_F(PendingAppManagerTest,DestroyDuringUninstallInSynchronize)101 TEST_F(PendingAppManagerTest, DestroyDuringUninstallInSynchronize) {
102 TestAppRegistrar registrar;
103 auto pending_app_manager =
104 std::make_unique<TestPendingAppManager>(®istrar);
105
106 // Install an app that will be uninstalled next.
107 {
108 std::vector<ExternalInstallOptions> install_options_list;
109 install_options_list.emplace_back(GURL("https://foo.example"),
110 DisplayMode::kStandalone,
111 ExternalInstallSource::kInternalDefault);
112 base::RunLoop run_loop;
113 pending_app_manager->SynchronizeInstalledApps(
114 std::move(install_options_list),
115 ExternalInstallSource::kInternalDefault,
116 base::BindLambdaForTesting(
117 [&](std::map<GURL, InstallResultCode> install_results,
118 std::map<GURL, bool> uninstall_results) { run_loop.Quit(); }));
119 run_loop.Run();
120 }
121
122 pending_app_manager->SynchronizeInstalledApps(
123 std::vector<ExternalInstallOptions>(),
124 ExternalInstallSource::kInternalDefault,
125 // PendingAppManager gives no guarantees about whether its pending
126 // callbacks will be run or not when it gets destroyed.
127 base::DoNothing());
128 pending_app_manager.reset();
129 base::RunLoop().RunUntilIdle();
130 }
131
TEST_F(PendingAppManagerTest,SynchronizeInstalledApps)132 TEST_F(PendingAppManagerTest, SynchronizeInstalledApps) {
133 GURL a("https://a.example.com/");
134 GURL b("https://b.example.com/");
135 GURL c("https://c.example.com/");
136 GURL d("https://d.example.com/");
137 GURL e("https://e.example.com/");
138
139 Sync(std::vector<GURL>{a, b, d});
140 Expect(3, 0, std::vector<GURL>{a, b, d});
141
142 Sync(std::vector<GURL>{b, e});
143 Expect(1, 2, std::vector<GURL>{b, e});
144
145 Sync(std::vector<GURL>{e});
146 Expect(0, 1, std::vector<GURL>{e});
147
148 Sync(std::vector<GURL>{c});
149 Expect(1, 1, std::vector<GURL>{c});
150
151 Sync(std::vector<GURL>{e, a, d});
152 Expect(3, 1, std::vector<GURL>{a, d, e});
153
154 Sync(std::vector<GURL>{c, a, b, d, e});
155 Expect(2, 0, std::vector<GURL>{a, b, c, d, e});
156
157 Sync(std::vector<GURL>{});
158 Expect(0, 5, std::vector<GURL>{});
159
160 // The remaining code tests duplicate inputs.
161
162 Sync(std::vector<GURL>{b, a, b, c});
163 Expect(3, 0, std::vector<GURL>{a, b, c});
164
165 Sync(std::vector<GURL>{e, a, e, e, e, a});
166 Expect(1, 2, std::vector<GURL>{a, e});
167
168 Sync(std::vector<GURL>{b, c, d});
169 Expect(3, 2, std::vector<GURL>{b, c, d});
170
171 Sync(std::vector<GURL>{a, a, a, a, a, a});
172 Expect(1, 3, std::vector<GURL>{a});
173
174 Sync(std::vector<GURL>{});
175 Expect(0, 1, std::vector<GURL>{});
176 }
177
178 } // namespace web_app
179