OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h" | 5 #include "chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/callback_forward.h" | |
11 #include "base/files/file_path.h" | |
12 #include "base/macros.h" | 10 #include "base/macros.h" |
13 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
14 #include "base/memory/ref_counted.h" | 12 #include "base/memory/ref_counted.h" |
15 #include "base/message_loop/message_loop.h" | |
16 #include "base/run_loop.h" | 13 #include "base/run_loop.h" |
17 #include "base/strings/nullable_string16.h" | 14 #include "base/strings/nullable_string16.h" |
18 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
19 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
20 #include "base/time/time.h" | |
21 #include "chrome/browser/installable/installable_manager.h" | 17 #include "chrome/browser/installable/installable_manager.h" |
22 #include "chrome/common/web_application_info.h" | 18 #include "chrome/common/web_application_info.h" |
23 #include "chrome/test/base/chrome_render_view_host_test_harness.h" | 19 #include "chrome/test/base/chrome_render_view_host_test_harness.h" |
24 #include "chrome/test/base/testing_profile.h" | 20 #include "chrome/test/base/testing_profile.h" |
25 #include "content/browser/service_worker/embedded_worker_test_helper.h" | |
26 #include "content/browser/service_worker/service_worker_context_core.h" | |
27 #include "content/common/service_worker/service_worker_status_code.h" | |
28 #include "content/public/browser/browser_thread.h" | |
29 #include "content/public/browser/site_instance.h" | |
30 #include "content/public/browser/web_contents.h" | 21 #include "content/public/browser/web_contents.h" |
31 #include "content/public/common/manifest.h" | 22 #include "content/public/common/manifest.h" |
32 #include "content/test/test_web_contents.h" | |
33 #include "net/http/http_status_code.h" | |
34 #include "third_party/WebKit/public/platform/WebDisplayMode.h" | 23 #include "third_party/WebKit/public/platform/WebDisplayMode.h" |
35 #include "ui/gfx/image/image_unittest_util.h" | 24 #include "ui/gfx/image/image_unittest_util.h" |
36 #include "url/gurl.h" | 25 #include "url/gurl.h" |
37 | 26 |
38 namespace { | 27 namespace { |
39 | 28 |
40 const char* kWebApplicationInfoTitle = "Meta Title"; | 29 const char* kWebApplicationInfoTitle = "Meta Title"; |
41 const char* kDefaultManifestUrl = "https://www.example.com/manifest.json"; | 30 const char* kDefaultManifestUrl = "https://www.example.com/manifest.json"; |
| 31 const char* kDefaultIconUrl = "https://www.example.com/icon.png"; |
42 const char* kDefaultManifestName = "Default Name"; | 32 const char* kDefaultManifestName = "Default Name"; |
43 const char* kDefaultManifestShortName = "Default Short Name"; | 33 const char* kDefaultManifestShortName = "Default Short Name"; |
44 const char* kDefaultStartUrl = "https://www.example.com/index.html"; | 34 const char* kDefaultStartUrl = "https://www.example.com/index.html"; |
45 const blink::WebDisplayMode kDefaultManifestDisplayMode = | 35 const blink::WebDisplayMode kDefaultManifestDisplayMode = |
46 blink::kWebDisplayModeStandalone; | 36 blink::kWebDisplayModeStandalone; |
| 37 const int kIconSizePx = 144; |
47 | 38 |
48 // WebContents subclass which mocks out image and manifest fetching. | 39 // Tracks which of the AddToHomescreenDataFetcher::Observer methods have been |
49 class MockWebContents : public content::TestWebContents { | |
50 public: | |
51 explicit MockWebContents(content::BrowserContext* browser_context) | |
52 : content::TestWebContents(browser_context), | |
53 should_image_time_out_(false), | |
54 should_manifest_time_out_(false) {} | |
55 | |
56 ~MockWebContents() override {} | |
57 | |
58 void SetManifest(const GURL& manifest_url, | |
59 const content::Manifest& manifest) { | |
60 manifest_url_ = manifest_url; | |
61 manifest_ = manifest; | |
62 } | |
63 | |
64 int DownloadImage(const GURL& url, | |
65 bool is_favicon, | |
66 uint32_t max_bitmap_size, | |
67 bool bypass_cache, | |
68 const ImageDownloadCallback& callback) override { | |
69 if (should_image_time_out_) | |
70 return 0; | |
71 | |
72 const int kIconSizePx = 144; | |
73 SkBitmap icon = gfx::test::CreateBitmap(kIconSizePx, kIconSizePx); | |
74 std::vector<SkBitmap> icons(1u, icon); | |
75 std::vector<gfx::Size> pixel_sizes(1u, gfx::Size(kIconSizePx, kIconSizePx)); | |
76 content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI) | |
77 ->PostTask(FROM_HERE, base::Bind(callback, 0, net::HTTP_OK, url, icons, | |
78 pixel_sizes)); | |
79 return 0; | |
80 } | |
81 | |
82 void GetManifest(const GetManifestCallback& callback) override { | |
83 if (should_manifest_time_out_) | |
84 return; | |
85 | |
86 content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI) | |
87 ->PostTask(FROM_HERE, base::Bind(callback, manifest_url_, manifest_)); | |
88 } | |
89 | |
90 void SetShouldImageTimeOut(bool should_time_out) { | |
91 should_image_time_out_ = should_time_out; | |
92 } | |
93 | |
94 void SetShouldManifestTimeOut(bool should_time_out) { | |
95 should_manifest_time_out_ = should_time_out; | |
96 } | |
97 | |
98 private: | |
99 GURL manifest_url_; | |
100 content::Manifest manifest_; | |
101 bool should_image_time_out_; | |
102 bool should_manifest_time_out_; | |
103 | |
104 DISALLOW_COPY_AND_ASSIGN(MockWebContents); | |
105 }; | |
106 | |
107 // Tracks which of the AddToHomescreenDataFetcher::Observer callbacks have been | |
108 // called. | 40 // called. |
109 class ObserverWaiter : public AddToHomescreenDataFetcher::Observer { | 41 class ObserverWaiter : public AddToHomescreenDataFetcher::Observer { |
110 public: | 42 public: |
111 ObserverWaiter() | 43 ObserverWaiter() |
112 : is_webapk_compatible_(false), | 44 : is_webapk_compatible_(false), |
113 determined_webapk_compatibility_(false), | 45 determined_webapk_compatibility_(false), |
114 title_available_(false), | 46 title_available_(false), |
115 data_available_(false) {} | 47 data_available_(false) {} |
116 ~ObserverWaiter() override {} | 48 ~ObserverWaiter() override {} |
117 | 49 |
118 // Waits till the OnDataAvailable() callback is called. | 50 // Waits till the OnDataAvailable() callback is called. |
119 void WaitForDataAvailable() { | 51 void WaitForDataAvailable() { |
120 if (data_available_) | 52 if (data_available_) |
121 return; | 53 return; |
122 | 54 |
123 base::RunLoop run_loop; | 55 base::RunLoop run_loop; |
124 quit_closure_ = run_loop.QuitClosure(); | 56 quit_closure_ = run_loop.QuitClosure(); |
125 run_loop.Run(); | 57 run_loop.Run(); |
126 } | 58 } |
127 | 59 |
128 void OnDidDetermineWebApkCompatibility(bool is_webapk_compatible) override { | 60 void OnDidDetermineWebApkCompatibility(bool is_webapk_compatible) override { |
| 61 // This should only be called once. |
| 62 EXPECT_FALSE(determined_webapk_compatibility_); |
129 EXPECT_FALSE(title_available_); | 63 EXPECT_FALSE(title_available_); |
130 determined_webapk_compatibility_ = true; | 64 determined_webapk_compatibility_ = true; |
131 is_webapk_compatible_ = is_webapk_compatible; | 65 is_webapk_compatible_ = is_webapk_compatible; |
132 } | 66 } |
133 | 67 |
134 void OnUserTitleAvailable(const base::string16& title) override { | 68 void OnUserTitleAvailable(const base::string16& title) override { |
| 69 // This should only be called once. |
| 70 EXPECT_FALSE(title_available_); |
135 EXPECT_FALSE(data_available_); | 71 EXPECT_FALSE(data_available_); |
136 title_available_ = true; | 72 title_available_ = true; |
137 title_ = title; | 73 title_ = title; |
138 } | 74 } |
139 | 75 |
140 void OnDataAvailable(const ShortcutInfo& info, | 76 void OnDataAvailable(const ShortcutInfo& info, |
141 const SkBitmap& primary_icon, | 77 const SkBitmap& primary_icon, |
142 const SkBitmap& badge_icon) override { | 78 const SkBitmap& badge_icon) override { |
| 79 // This should only be called once. |
| 80 EXPECT_FALSE(data_available_); |
143 EXPECT_TRUE(title_available_); | 81 EXPECT_TRUE(title_available_); |
144 data_available_ = true; | 82 data_available_ = true; |
145 if (!quit_closure_.is_null()) | 83 if (!quit_closure_.is_null()) |
146 quit_closure_.Run(); | 84 quit_closure_.Run(); |
147 } | 85 } |
148 | 86 |
149 base::string16 title() const { return title_; } | 87 base::string16 title() const { return title_; } |
150 bool is_webapk_compatible() const { return is_webapk_compatible_; } | 88 bool is_webapk_compatible() const { return is_webapk_compatible_; } |
151 bool determined_webapk_compatibility() const { | 89 bool determined_webapk_compatibility() const { |
152 return determined_webapk_compatibility_; | 90 return determined_webapk_compatibility_; |
153 } | 91 } |
154 bool title_available() const { return title_available_; } | 92 bool title_available() const { return title_available_; } |
155 | 93 |
156 private: | 94 private: |
157 base::string16 title_; | 95 base::string16 title_; |
158 bool is_webapk_compatible_; | 96 bool is_webapk_compatible_; |
159 bool determined_webapk_compatibility_; | 97 bool determined_webapk_compatibility_; |
160 bool title_available_; | 98 bool title_available_; |
161 bool data_available_; | 99 bool data_available_; |
162 base::Closure quit_closure_; | 100 base::Closure quit_closure_; |
163 | 101 |
164 DISALLOW_COPY_AND_ASSIGN(ObserverWaiter); | 102 DISALLOW_COPY_AND_ASSIGN(ObserverWaiter); |
165 }; | 103 }; |
166 | 104 |
167 // Builds non-null base::NullableString16 from a UTF8 string. | 105 // Builds non-null base::NullableString16 from a UTF8 string. |
168 base::NullableString16 NullableStringFromUTF8(const std::string& value) { | 106 base::NullableString16 NullableStringFromUTF8(const std::string& value) { |
169 return base::NullableString16(base::UTF8ToUTF16(value), false); | 107 return base::NullableString16(base::UTF8ToUTF16(value), false); |
170 } | 108 } |
171 | 109 |
172 content::Manifest BuildEmptyManifest() { | |
173 return content::Manifest(); | |
174 } | |
175 | |
176 // Builds WebAPK compatible content::Manifest. | 110 // Builds WebAPK compatible content::Manifest. |
177 content::Manifest BuildDefaultManifest() { | 111 content::Manifest BuildDefaultManifest() { |
178 content::Manifest manifest; | 112 content::Manifest manifest; |
179 manifest.name = NullableStringFromUTF8(kDefaultManifestName); | 113 manifest.name = NullableStringFromUTF8(kDefaultManifestName); |
180 manifest.short_name = NullableStringFromUTF8(kDefaultManifestShortName); | 114 manifest.short_name = NullableStringFromUTF8(kDefaultManifestShortName); |
181 manifest.start_url = GURL(kDefaultStartUrl); | 115 manifest.start_url = GURL(kDefaultStartUrl); |
182 manifest.display = kDefaultManifestDisplayMode; | 116 manifest.display = kDefaultManifestDisplayMode; |
183 | 117 |
184 content::Manifest::Icon primary_icon; | 118 content::Manifest::Icon primary_icon; |
185 primary_icon.type = base::ASCIIToUTF16("image/png"); | 119 primary_icon.type = base::ASCIIToUTF16("image/png"); |
186 primary_icon.sizes.push_back(gfx::Size(144, 144)); | 120 primary_icon.sizes.push_back(gfx::Size(144, 144)); |
187 primary_icon.purpose.push_back(content::Manifest::Icon::IconPurpose::ANY); | 121 primary_icon.purpose.push_back(content::Manifest::Icon::IconPurpose::ANY); |
188 primary_icon.src = GURL("https://www.google.com/image.png"); | 122 primary_icon.src = GURL(kDefaultIconUrl); |
189 manifest.icons.push_back(primary_icon); | 123 manifest.icons.push_back(primary_icon); |
190 | 124 |
191 return manifest; | 125 return manifest; |
192 } | 126 } |
193 | 127 |
194 } // anonymous namespace | 128 } // anonymous namespace |
195 | 129 |
| 130 class TestInstallableManager : public InstallableManager { |
| 131 public: |
| 132 explicit TestInstallableManager(content::WebContents* web_contents) |
| 133 : InstallableManager(web_contents) {} |
| 134 |
| 135 void GetData(const InstallableParams& params, |
| 136 const InstallableCallback& callback) override { |
| 137 if (should_manifest_time_out_ || |
| 138 (params.check_installable && should_installable_time_out_)) { |
| 139 return; |
| 140 } |
| 141 |
| 142 InstallableStatusCode code = NO_ERROR_DETECTED; |
| 143 bool is_installable = is_installable_; |
| 144 if (params.fetch_valid_primary_icon && !primary_icon_) { |
| 145 code = NO_ACCEPTABLE_ICON; |
| 146 is_installable = false; |
| 147 } else if (params.check_installable) { |
| 148 if (!IsManifestValidForWebApp(manifest_)) { |
| 149 code = valid_manifest_->error; |
| 150 is_installable = false; |
| 151 } else if (!is_installable_) { |
| 152 code = NOT_OFFLINE_CAPABLE; |
| 153 is_installable = false; |
| 154 } |
| 155 } |
| 156 |
| 157 callback.Run( |
| 158 {code, GURL(kDefaultManifestUrl), manifest_, |
| 159 params.fetch_valid_primary_icon ? primary_icon_url_ : GURL(), |
| 160 params.fetch_valid_primary_icon ? primary_icon_.get() : nullptr, |
| 161 params.fetch_valid_badge_icon ? badge_icon_url_ : GURL(), |
| 162 params.fetch_valid_badge_icon ? badge_icon_.get() : nullptr, |
| 163 params.check_installable ? is_installable : false}); |
| 164 } |
| 165 |
| 166 void SetInstallable(bool is_installable) { is_installable_ = is_installable; } |
| 167 |
| 168 void SetManifest(const content::Manifest& manifest) { |
| 169 manifest_ = manifest; |
| 170 |
| 171 if (!manifest.icons.empty()) { |
| 172 primary_icon_url_ = manifest_.icons[0].src; |
| 173 primary_icon_.reset( |
| 174 new SkBitmap(gfx::test::CreateBitmap(kIconSizePx, kIconSizePx))); |
| 175 |
| 176 badge_icon_url_ = manifest_.icons[0].src; |
| 177 badge_icon_.reset( |
| 178 new SkBitmap(gfx::test::CreateBitmap(kIconSizePx, kIconSizePx))); |
| 179 } |
| 180 } |
| 181 |
| 182 void SetShouldManifestTimeOut(bool should_time_out) { |
| 183 should_manifest_time_out_ = should_time_out; |
| 184 } |
| 185 |
| 186 void SetShouldInstallableTimeOut(bool should_time_out) { |
| 187 should_installable_time_out_ = should_time_out; |
| 188 } |
| 189 |
| 190 private: |
| 191 content::Manifest manifest_; |
| 192 GURL primary_icon_url_; |
| 193 GURL badge_icon_url_; |
| 194 std::unique_ptr<SkBitmap> primary_icon_; |
| 195 std::unique_ptr<SkBitmap> badge_icon_; |
| 196 |
| 197 bool is_installable_ = true; |
| 198 |
| 199 bool should_manifest_time_out_ = false; |
| 200 bool should_installable_time_out_ = false; |
| 201 }; |
| 202 |
196 // Tests AddToHomescreenDataFetcher. These tests should be browser tests but | 203 // Tests AddToHomescreenDataFetcher. These tests should be browser tests but |
197 // Android does not support browser tests yet (crbug.com/611756). | 204 // Android does not support browser tests yet (crbug.com/611756). |
198 class AddToHomescreenDataFetcherTest : public ChromeRenderViewHostTestHarness { | 205 class AddToHomescreenDataFetcherTest : public ChromeRenderViewHostTestHarness { |
199 public: | 206 public: |
200 AddToHomescreenDataFetcherTest() {} | 207 AddToHomescreenDataFetcherTest() {} |
201 ~AddToHomescreenDataFetcherTest() override {} | 208 ~AddToHomescreenDataFetcherTest() override {} |
202 | 209 |
203 void SetUp() override { | 210 void SetUp() override { |
204 ChromeRenderViewHostTestHarness::SetUp(); | 211 ChromeRenderViewHostTestHarness::SetUp(); |
205 | 212 |
206 ASSERT_TRUE(profile()->CreateHistoryService(false, true)); | 213 ASSERT_TRUE(profile()->CreateHistoryService(false, true)); |
207 profile()->CreateFaviconService(); | 214 profile()->CreateFaviconService(); |
208 | 215 |
209 embedded_worker_test_helper_.reset( | 216 // Manually inject the TestInstallableManager as a "InstallableManager" |
210 new content::EmbeddedWorkerTestHelper(base::FilePath())); | 217 // WebContentsUserData. We can't directly call ::CreateForWebContents due to |
211 | 218 // typing issues since TestInstallableManager doesn't directly inherit from |
212 scoped_refptr<content::SiteInstance> site_instance = | 219 // WebContentsUserData. |
213 content::SiteInstance::Create(browser_context()); | 220 web_contents()->SetUserData( |
214 site_instance->GetProcess()->Init(); | 221 TestInstallableManager::UserDataKey(), |
215 MockWebContents* mock_web_contents = new MockWebContents(browser_context()); | 222 base::WrapUnique(new TestInstallableManager(web_contents()))); |
216 mock_web_contents->Init(content::WebContents::CreateParams( | 223 installable_manager_ = static_cast<TestInstallableManager*>( |
217 browser_context(), std::move(site_instance))); | 224 web_contents()->GetUserData(TestInstallableManager::UserDataKey())); |
218 InstallableManager::CreateForWebContents(mock_web_contents); | |
219 SetContents(mock_web_contents); | |
220 NavigateAndCommit(GURL(kDefaultStartUrl)); | |
221 } | |
222 | |
223 void TearDown() override { | |
224 embedded_worker_test_helper_.reset(); | |
225 ChromeRenderViewHostTestHarness::TearDown(); | |
226 } | 225 } |
227 | 226 |
228 std::unique_ptr<AddToHomescreenDataFetcher> BuildFetcher( | 227 std::unique_ptr<AddToHomescreenDataFetcher> BuildFetcher( |
229 bool check_webapk_compatible, | 228 bool check_webapk_compatible, |
230 AddToHomescreenDataFetcher::Observer* observer) { | 229 AddToHomescreenDataFetcher::Observer* observer) { |
231 return base::MakeUnique<AddToHomescreenDataFetcher>( | 230 return base::MakeUnique<AddToHomescreenDataFetcher>( |
232 web_contents(), 1, 1, 1, 1, 1, 500, check_webapk_compatible, observer); | 231 web_contents(), 1, 1, 1, 1, 1, 500, check_webapk_compatible, observer); |
233 } | 232 } |
234 | 233 |
235 // Set the manifest to be returned as a result of WebContents::GetManifest(). | 234 void RunFetcher(AddToHomescreenDataFetcher* fetcher, |
236 void SetManifest(const GURL& manifest_url, | 235 ObserverWaiter& waiter, |
237 const content::Manifest& manifest) { | 236 const char* expected_title, |
238 MockWebContents* mock_web_contents = | 237 blink::WebDisplayMode display_mode, |
239 static_cast<MockWebContents*>(web_contents()); | 238 bool is_webapk_compatible) { |
240 mock_web_contents->SetManifest(manifest_url, manifest); | 239 WebApplicationInfo web_application_info; |
| 240 web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle); |
| 241 |
| 242 fetcher->OnDidGetWebApplicationInfo(web_application_info); |
| 243 waiter.WaitForDataAvailable(); |
| 244 |
| 245 EXPECT_EQ(check_webapk_compatibility(), |
| 246 waiter.determined_webapk_compatibility()); |
| 247 EXPECT_EQ(is_webapk_compatible, waiter.is_webapk_compatible()); |
| 248 EXPECT_TRUE(waiter.title_available()); |
| 249 EXPECT_TRUE(base::EqualsASCII(waiter.title(), expected_title)); |
| 250 EXPECT_TRUE( |
| 251 base::EqualsASCII(fetcher->shortcut_info().user_title, expected_title)); |
| 252 EXPECT_EQ(display_mode, fetcher->shortcut_info().display); |
241 } | 253 } |
242 | 254 |
243 void SetShouldImageTimeOut(bool should_time_out) { | 255 void SetManifest(const content::Manifest& manifest) { |
244 MockWebContents* mock_web_contents = | 256 installable_manager_->SetManifest(manifest); |
245 static_cast<MockWebContents*>(web_contents()); | 257 } |
246 mock_web_contents->SetShouldImageTimeOut(should_time_out); | 258 |
| 259 void SetInstallable(bool is_installable) { |
| 260 installable_manager_->SetInstallable(is_installable); |
247 } | 261 } |
248 | 262 |
249 void SetShouldManifestTimeOut(bool should_time_out) { | 263 void SetShouldManifestTimeOut(bool should_time_out) { |
250 MockWebContents* mock_web_contents = | 264 installable_manager_->SetShouldManifestTimeOut(should_time_out); |
251 static_cast<MockWebContents*>(web_contents()); | |
252 mock_web_contents->SetShouldManifestTimeOut(should_time_out); | |
253 } | 265 } |
254 | 266 |
255 // Registers service worker at |url|. Blocks till the service worker is | 267 void SetShouldInstallableTimeOut(bool should_time_out) { |
256 // registered. | 268 installable_manager_->SetShouldInstallableTimeOut(should_time_out); |
257 void RegisterServiceWorker(const GURL& url) { | |
258 base::RunLoop run_loop; | |
259 embedded_worker_test_helper_->context()->RegisterServiceWorker( | |
260 GURL(url.spec() + "/service_worker.js"), | |
261 content::ServiceWorkerRegistrationOptions(url), nullptr, | |
262 base::Bind(&AddToHomescreenDataFetcherTest::OnServiceWorkerRegistered, | |
263 base::Unretained(this), run_loop.QuitClosure())); | |
264 } | 269 } |
265 | 270 |
| 271 virtual bool check_webapk_compatibility() { return true; } |
| 272 |
266 private: | 273 private: |
267 // Callback for RegisterServiceWorker() for when service worker registration | 274 TestInstallableManager* installable_manager_; |
268 // has completed. | |
269 void OnServiceWorkerRegistered(const base::Closure& callback, | |
270 content::ServiceWorkerStatusCode status, | |
271 const std::string& status_message, | |
272 int64_t registration_id) { | |
273 ASSERT_EQ(content::SERVICE_WORKER_OK, status) | |
274 << content::ServiceWorkerStatusToString(status); | |
275 callback.Run(); | |
276 } | |
277 | |
278 std::unique_ptr<content::EmbeddedWorkerTestHelper> | |
279 embedded_worker_test_helper_; | |
280 | 275 |
281 DISALLOW_COPY_AND_ASSIGN(AddToHomescreenDataFetcherTest); | 276 DISALLOW_COPY_AND_ASSIGN(AddToHomescreenDataFetcherTest); |
282 }; | 277 }; |
283 | 278 |
284 // Class for tests which should be run with AddToHomescreenDataFetcher built | 279 // Class for tests which should be run with AddToHomescreenDataFetcher built |
285 // with both true and false values of |check_webapk_compatible|. | 280 // with both true and false values of |check_webapk_compatible|. |
286 class AddToHomescreenDataFetcherTestCommon | 281 class AddToHomescreenDataFetcherTestCommon |
287 : public AddToHomescreenDataFetcherTest, | 282 : public AddToHomescreenDataFetcherTest, |
288 public testing::WithParamInterface<bool> { | 283 public testing::WithParamInterface<bool> { |
289 public: | 284 public: |
290 AddToHomescreenDataFetcherTestCommon() {} | 285 AddToHomescreenDataFetcherTestCommon() {} |
291 ~AddToHomescreenDataFetcherTestCommon() override {} | 286 ~AddToHomescreenDataFetcherTestCommon() override {} |
292 | 287 |
293 std::unique_ptr<AddToHomescreenDataFetcher> BuildFetcher( | 288 std::unique_ptr<AddToHomescreenDataFetcher> BuildFetcher( |
294 AddToHomescreenDataFetcher::Observer* observer) { | 289 AddToHomescreenDataFetcher::Observer* observer) { |
295 return AddToHomescreenDataFetcherTest::BuildFetcher( | 290 return AddToHomescreenDataFetcherTest::BuildFetcher( |
296 check_webapk_compatibility(), observer); | 291 check_webapk_compatibility(), observer); |
297 } | 292 } |
298 | 293 |
299 // The value of |check_webapk_compatible| used when building the | 294 // The value of |check_webapk_compatible| used when building the |
300 // AddToHomescreenDataFetcher. | 295 // AddToHomescreenDataFetcher. |
301 bool check_webapk_compatibility() { return GetParam(); } | 296 bool check_webapk_compatibility() override { return GetParam(); } |
302 | 297 |
303 private: | 298 private: |
304 DISALLOW_COPY_AND_ASSIGN(AddToHomescreenDataFetcherTestCommon); | 299 DISALLOW_COPY_AND_ASSIGN(AddToHomescreenDataFetcherTestCommon); |
305 }; | 300 }; |
306 | 301 |
307 // Checks that AddToHomescreenDataFetcher::Observer::OnUserTitleAvailable() is | |
308 // called when the web manifest returned is empty. The add-to-homescreen dialog | |
309 // makes the dialog's text field editable once OnUserTitleAvailable() is called. | |
310 TEST_P(AddToHomescreenDataFetcherTestCommon, EmptyManifest) { | 302 TEST_P(AddToHomescreenDataFetcherTestCommon, EmptyManifest) { |
311 WebApplicationInfo web_application_info; | 303 // Check that an empty manifest has the appropriate methods run. |
312 web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle); | 304 ObserverWaiter waiter; |
| 305 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); |
| 306 RunFetcher(fetcher.get(), waiter, kWebApplicationInfoTitle, |
| 307 blink::kWebDisplayModeBrowser, false); |
| 308 } |
313 | 309 |
314 SetManifest(GURL(kDefaultManifestUrl), BuildEmptyManifest()); | 310 TEST_P(AddToHomescreenDataFetcherTestCommon, NoIconManifest) { |
| 311 // Test a manifest with no icons. This should use the short name and have |
| 312 // a generated icon (empty icon url). |
| 313 content::Manifest manifest = BuildDefaultManifest(); |
| 314 manifest.icons.clear(); |
| 315 SetManifest(manifest); |
315 | 316 |
316 ObserverWaiter waiter; | 317 ObserverWaiter waiter; |
317 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); | 318 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); |
318 fetcher->OnDidGetWebApplicationInfo(web_application_info); | 319 RunFetcher(fetcher.get(), waiter, kDefaultManifestShortName, |
319 waiter.WaitForDataAvailable(); | 320 blink::kWebDisplayModeStandalone, false); |
320 | 321 |
321 EXPECT_EQ(check_webapk_compatibility(), | 322 EXPECT_TRUE(fetcher->shortcut_info().best_primary_icon_url.is_empty()); |
322 waiter.determined_webapk_compatibility()); | 323 EXPECT_TRUE(fetcher->badge_icon().drawsNothing()); |
323 EXPECT_FALSE(waiter.is_webapk_compatible()); | 324 EXPECT_TRUE(fetcher->shortcut_info().best_badge_icon_url.is_empty()); |
324 EXPECT_TRUE(waiter.title_available()); | |
325 EXPECT_TRUE(base::EqualsASCII(waiter.title(), kWebApplicationInfoTitle)); | |
326 } | 325 } |
327 | 326 |
328 // Test that when the manifest provides Manifest::short_name but not | 327 TEST_P(AddToHomescreenDataFetcherTestCommon, ManifestFetchTimesOut) { |
329 // Manifest::name that Manifest::short_name is used as the name instead of | 328 // Check that the AddToHomescreenDataFetcher::Observer methods are called |
330 // WebApplicationInfo::title. | 329 // if the first call to InstallableManager::GetData() times out. This should |
331 TEST_P(AddToHomescreenDataFetcherTestCommon, | 330 // fall back to the metadata title and have an empty icon. |
332 ManifestShortNameClobbersWebApplicationName) { | 331 SetShouldManifestTimeOut(true); |
333 WebApplicationInfo web_application_info; | 332 SetManifest(BuildDefaultManifest()); |
334 web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle); | |
335 | 333 |
| 334 // Check a site with no offline-capable service worker. |
| 335 SetInstallable(false); |
| 336 ObserverWaiter waiter; |
| 337 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); |
| 338 RunFetcher(fetcher.get(), waiter, kWebApplicationInfoTitle, |
| 339 blink::kWebDisplayModeBrowser, false); |
| 340 |
| 341 EXPECT_TRUE(fetcher->primary_icon().drawsNothing()); |
| 342 EXPECT_TRUE(fetcher->shortcut_info().best_primary_icon_url.is_empty()); |
| 343 } |
| 344 |
| 345 TEST_F(AddToHomescreenDataFetcherTest, ServiceWorkerCheckTimesOut) { |
| 346 // Check that the AddToHomescreenDataFetcher::Observer methods are called if |
| 347 // the service worker check times out on a page that is installable (i.e. it's |
| 348 // taken too long). This should use the short_name and icon from the manifest, |
| 349 // but not be WebAPK-compatible. Only relevant when checking WebAPK |
| 350 // compatibility. |
| 351 SetManifest(BuildDefaultManifest()); |
| 352 SetShouldInstallableTimeOut(true); |
| 353 |
| 354 ObserverWaiter waiter; |
| 355 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = |
| 356 BuildFetcher(true, &waiter); |
| 357 RunFetcher(fetcher.get(), waiter, kDefaultManifestShortName, |
| 358 blink::kWebDisplayModeStandalone, false); |
| 359 |
| 360 EXPECT_FALSE(fetcher->primary_icon().drawsNothing()); |
| 361 EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url, |
| 362 GURL(kDefaultIconUrl)); |
| 363 } |
| 364 |
| 365 TEST_P(AddToHomescreenDataFetcherTestCommon, InstallableManifest) { |
| 366 // Test a site that has an offline-capable service worker. |
336 content::Manifest manifest(BuildDefaultManifest()); | 367 content::Manifest manifest(BuildDefaultManifest()); |
337 manifest.name = base::NullableString16(); | 368 SetManifest(manifest); |
338 | |
339 RegisterServiceWorker(GURL(kDefaultStartUrl)); | |
340 SetManifest(GURL(kDefaultManifestUrl), manifest); | |
341 | 369 |
342 ObserverWaiter waiter; | 370 ObserverWaiter waiter; |
343 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); | 371 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); |
344 fetcher->OnDidGetWebApplicationInfo(web_application_info); | 372 RunFetcher(fetcher.get(), waiter, kDefaultManifestShortName, |
345 waiter.WaitForDataAvailable(); | 373 blink::kWebDisplayModeStandalone, check_webapk_compatibility()); |
346 | 374 |
347 EXPECT_TRUE(base::EqualsASCII(waiter.title(), kDefaultManifestShortName)); | 375 // There should always be a primary icon. |
348 EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().name, | 376 EXPECT_FALSE(fetcher->primary_icon().drawsNothing()); |
349 kDefaultManifestShortName)); | 377 EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url, |
| 378 GURL(kDefaultIconUrl)); |
| 379 |
| 380 // Check that the badge icon is requested only when AddToHomescreenDataFetcher |
| 381 // checks for WebAPK compatibility. |
| 382 if (check_webapk_compatibility()) { |
| 383 EXPECT_FALSE(fetcher->badge_icon().drawsNothing()); |
| 384 EXPECT_EQ(fetcher->shortcut_info().best_badge_icon_url, |
| 385 GURL(kDefaultIconUrl)); |
| 386 } else { |
| 387 EXPECT_TRUE(fetcher->badge_icon().drawsNothing()); |
| 388 EXPECT_TRUE(fetcher->shortcut_info().best_badge_icon_url.is_empty()); |
| 389 } |
350 } | 390 } |
351 | 391 |
352 // Test that when the manifest does not provide either Manifest::short_name nor | 392 TEST_P(AddToHomescreenDataFetcherTestCommon, |
353 // Manifest::name that: | 393 ManifestNameClobbersWebApplicationName) { |
354 // - The page is not WebAPK compatible. | 394 // Test that when the manifest provides Manifest::name but not |
355 // - WebApplicationInfo::title is used as the "name". | 395 // Manifest::short_name that Manifest::name is used as the title. |
| 396 { |
| 397 // Check the case where we have no icons. |
| 398 content::Manifest manifest = BuildDefaultManifest(); |
| 399 manifest.icons.clear(); |
| 400 manifest.short_name = base::NullableString16(); |
| 401 SetManifest(manifest); |
| 402 |
| 403 ObserverWaiter waiter; |
| 404 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); |
| 405 RunFetcher(fetcher.get(), waiter, kDefaultManifestName, |
| 406 blink::kWebDisplayModeStandalone, false); |
| 407 |
| 408 EXPECT_TRUE(fetcher->shortcut_info().best_primary_icon_url.is_empty()); |
| 409 EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().short_name, |
| 410 kDefaultManifestName)); |
| 411 } |
| 412 |
| 413 content::Manifest manifest(BuildDefaultManifest()); |
| 414 manifest.short_name = base::NullableString16(); |
| 415 SetManifest(manifest); |
| 416 |
| 417 { |
| 418 // Check a site with no offline-capable service worker. |
| 419 SetInstallable(false); |
| 420 ObserverWaiter waiter; |
| 421 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); |
| 422 RunFetcher(fetcher.get(), waiter, kDefaultManifestName, |
| 423 blink::kWebDisplayModeStandalone, false); |
| 424 |
| 425 EXPECT_FALSE(fetcher->primary_icon().drawsNothing()); |
| 426 EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url, |
| 427 GURL(kDefaultIconUrl)); |
| 428 EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().short_name, |
| 429 kDefaultManifestName)); |
| 430 } |
| 431 |
| 432 { |
| 433 // Check a site where we time out waiting for the service worker. |
| 434 SetShouldInstallableTimeOut(true); |
| 435 ObserverWaiter waiter; |
| 436 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); |
| 437 RunFetcher(fetcher.get(), waiter, kDefaultManifestName, |
| 438 blink::kWebDisplayModeStandalone, false); |
| 439 |
| 440 EXPECT_FALSE(fetcher->primary_icon().drawsNothing()); |
| 441 EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url, |
| 442 GURL(kDefaultIconUrl)); |
| 443 EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().short_name, |
| 444 kDefaultManifestName)); |
| 445 } |
| 446 |
| 447 { |
| 448 // Check a site with an offline-capaable service worker. |
| 449 SetInstallable(true); |
| 450 SetShouldInstallableTimeOut(false); |
| 451 ObserverWaiter waiter; |
| 452 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); |
| 453 RunFetcher(fetcher.get(), waiter, kDefaultManifestName, |
| 454 blink::kWebDisplayModeStandalone, check_webapk_compatibility()); |
| 455 |
| 456 EXPECT_FALSE(fetcher->primary_icon().drawsNothing()); |
| 457 EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url, |
| 458 GURL(kDefaultIconUrl)); |
| 459 EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().short_name, |
| 460 kDefaultManifestName)); |
| 461 } |
| 462 } |
| 463 |
356 TEST_P(AddToHomescreenDataFetcherTestCommon, ManifestNoNameNoShortName) { | 464 TEST_P(AddToHomescreenDataFetcherTestCommon, ManifestNoNameNoShortName) { |
357 WebApplicationInfo web_application_info; | 465 // Test that when the manifest does not provide either Manifest::short_name |
358 web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle); | 466 // nor Manifest::name that: |
359 | 467 // - The page is not WebAPK compatible. |
| 468 // - WebApplicationInfo::title is used as the "name". |
| 469 // - We still use the icons from the manifest. |
360 content::Manifest manifest(BuildDefaultManifest()); | 470 content::Manifest manifest(BuildDefaultManifest()); |
361 manifest.name = base::NullableString16(); | 471 manifest.name = base::NullableString16(); |
362 manifest.short_name = base::NullableString16(); | 472 manifest.short_name = base::NullableString16(); |
363 | 473 |
364 RegisterServiceWorker(GURL(kDefaultStartUrl)); | 474 // Check the case where we don't time out waiting for the service worker. |
365 SetManifest(GURL(kDefaultManifestUrl), manifest); | 475 SetManifest(manifest); |
366 | |
367 ObserverWaiter waiter; | 476 ObserverWaiter waiter; |
368 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); | 477 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); |
369 fetcher->OnDidGetWebApplicationInfo(web_application_info); | 478 RunFetcher(fetcher.get(), waiter, kWebApplicationInfoTitle, |
370 waiter.WaitForDataAvailable(); | 479 blink::kWebDisplayModeStandalone, false); |
371 | 480 |
372 EXPECT_EQ(check_webapk_compatibility(), | |
373 waiter.determined_webapk_compatibility()); | |
374 EXPECT_FALSE(waiter.is_webapk_compatible()); | |
375 EXPECT_TRUE(base::EqualsASCII(waiter.title(), kWebApplicationInfoTitle)); | |
376 EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().name, | 481 EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().name, |
377 kWebApplicationInfoTitle)); | 482 kWebApplicationInfoTitle)); |
378 } | 483 EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().short_name, |
379 | 484 kWebApplicationInfoTitle)); |
380 // Checks that the AddToHomescreenDataFetcher::Observer callbacks are called | 485 EXPECT_FALSE(fetcher->primary_icon().drawsNothing()); |
381 // when the manifest fetch times out. | 486 EXPECT_EQ(fetcher->shortcut_info().best_primary_icon_url, |
382 TEST_P(AddToHomescreenDataFetcherTestCommon, ManifestFetchTimesOut) { | 487 GURL(kDefaultIconUrl)); |
383 WebApplicationInfo web_application_info; | |
384 web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle); | |
385 | |
386 RegisterServiceWorker(GURL(kDefaultStartUrl)); | |
387 SetManifest(GURL(kDefaultManifestUrl), BuildDefaultManifest()); | |
388 SetShouldManifestTimeOut(true); | |
389 SetShouldImageTimeOut(false); | |
390 | |
391 ObserverWaiter waiter; | |
392 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); | |
393 fetcher->OnDidGetWebApplicationInfo(web_application_info); | |
394 waiter.WaitForDataAvailable(); | |
395 | |
396 EXPECT_EQ(check_webapk_compatibility(), | |
397 waiter.determined_webapk_compatibility()); | |
398 EXPECT_FALSE(waiter.is_webapk_compatible()); | |
399 EXPECT_TRUE(base::EqualsASCII(waiter.title(), kWebApplicationInfoTitle)); | |
400 EXPECT_TRUE(waiter.title_available()); | |
401 } | |
402 | |
403 // Checks that the AddToHomescreenDataFetcher::Observer callbacks are called | |
404 // when the image fetch times out. | |
405 TEST_P(AddToHomescreenDataFetcherTestCommon, ImageFetchTimesOut) { | |
406 WebApplicationInfo web_application_info; | |
407 web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle); | |
408 | |
409 RegisterServiceWorker(GURL(kDefaultStartUrl)); | |
410 SetManifest(GURL(kDefaultManifestUrl), BuildDefaultManifest()); | |
411 SetShouldManifestTimeOut(false); | |
412 SetShouldImageTimeOut(true); | |
413 | |
414 ObserverWaiter waiter; | |
415 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); | |
416 fetcher->OnDidGetWebApplicationInfo(web_application_info); | |
417 waiter.WaitForDataAvailable(); | |
418 | |
419 EXPECT_EQ(check_webapk_compatibility(), | |
420 waiter.determined_webapk_compatibility()); | |
421 EXPECT_FALSE(waiter.is_webapk_compatible()); | |
422 EXPECT_TRUE(waiter.title_available()); | |
423 EXPECT_TRUE(base::EqualsASCII(waiter.title(), kWebApplicationInfoTitle)); | |
424 } | |
425 | |
426 // Checks that the AddToHomescreenDataFetcher::Observer callbacks are called | |
427 // when the service worker check times out. | |
428 TEST_P(AddToHomescreenDataFetcherTestCommon, ServiceWorkerCheckTimesOut) { | |
429 WebApplicationInfo web_application_info; | |
430 web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle); | |
431 | |
432 // Not registering a service worker means we'll wait and time out for the | |
433 // worker. | |
434 SetManifest(GURL(kDefaultManifestUrl), BuildDefaultManifest()); | |
435 SetShouldManifestTimeOut(false); | |
436 SetShouldImageTimeOut(false); | |
437 | |
438 ObserverWaiter waiter; | |
439 std::unique_ptr<AddToHomescreenDataFetcher> fetcher = BuildFetcher(&waiter); | |
440 fetcher->OnDidGetWebApplicationInfo(web_application_info); | |
441 waiter.WaitForDataAvailable(); | |
442 | |
443 EXPECT_EQ(check_webapk_compatibility(), | |
444 waiter.determined_webapk_compatibility()); | |
445 EXPECT_FALSE(waiter.is_webapk_compatible()); | |
446 EXPECT_TRUE(waiter.title_available()); | |
447 EXPECT_TRUE(base::EqualsASCII(waiter.title(), kDefaultManifestShortName)); | |
448 EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().user_title, | |
449 kDefaultManifestShortName)); | |
450 } | 488 } |
451 | 489 |
452 INSTANTIATE_TEST_CASE_P(CheckWebApkCompatibility, | 490 INSTANTIATE_TEST_CASE_P(CheckWebApkCompatibility, |
453 AddToHomescreenDataFetcherTestCommon, | 491 AddToHomescreenDataFetcherTestCommon, |
454 ::testing::Values(false, true)); | 492 ::testing::Values(false, true)); |
OLD | NEW |