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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/installable/installable_manager.h"
6 
7 #include <tuple>
8 
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/optional.h"
12 #include "base/run_loop.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/test/bind.h"
16 #include "base/test/metrics/histogram_tester.h"
17 #include "base/test/scoped_feature_list.h"
18 #include "base/threading/sequenced_task_runner_handle.h"
19 #include "chrome/browser/banners/app_banner_manager_desktop.h"
20 #include "chrome/browser/installable/installable_logging.h"
21 #include "chrome/browser/installable/installable_manager.h"
22 #include "chrome/browser/installable/installable_metrics.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/ui/browser.h"
25 #include "chrome/browser/ui/tabs/tab_strip_model.h"
26 #include "chrome/browser/web_applications/test/service_worker_registration_waiter.h"
27 #include "chrome/test/base/in_process_browser_test.h"
28 #include "chrome/test/base/ui_test_utils.h"
29 #include "content/public/common/content_features.h"
30 #include "content/public/test/browser_test.h"
31 #include "content/public/test/browser_test_utils.h"
32 #include "net/test/embedded_test_server/embedded_test_server.h"
33 #include "third_party/blink/public/common/features.h"
34 
35 namespace {
36 
37 const char kInsecureOrigin[] = "http://www.google.com";
38 const char kOtherInsecureOrigin[] = "http://maps.google.com";
39 const char kUnsafeSecureOriginFlag[] =
40     "unsafely-treat-insecure-origin-as-secure";
41 
GetManifestParams()42 InstallableParams GetManifestParams() {
43   InstallableParams params;
44   params.check_eligibility = true;
45   params.wait_for_worker = true;
46   return params;
47 }
48 
GetWebAppParams()49 InstallableParams GetWebAppParams() {
50   InstallableParams params = GetManifestParams();
51   params.valid_manifest = true;
52   params.has_worker = true;
53   params.valid_primary_icon = true;
54   params.wait_for_worker = true;
55   return params;
56 }
57 
GetPrimaryIconParams()58 InstallableParams GetPrimaryIconParams() {
59   InstallableParams params = GetManifestParams();
60   params.valid_primary_icon = true;
61   params.wait_for_worker = true;
62   return params;
63 }
64 
GetPrimaryIconAndSplashIconParams()65 InstallableParams GetPrimaryIconAndSplashIconParams() {
66   InstallableParams params = GetManifestParams();
67   params.valid_primary_icon = true;
68   params.valid_splash_icon = true;
69   params.wait_for_worker = true;
70   return params;
71 }
72 
GetPrimaryIconPreferMaskableParams()73 InstallableParams GetPrimaryIconPreferMaskableParams() {
74   InstallableParams params = GetManifestParams();
75   params.valid_primary_icon = true;
76   params.prefer_maskable_icon = true;
77   params.wait_for_worker = true;
78   return params;
79 }
80 
GetPrimaryIconPreferMaskableAndSplashIconParams()81 InstallableParams GetPrimaryIconPreferMaskableAndSplashIconParams() {
82   InstallableParams params = GetManifestParams();
83   params.valid_primary_icon = true;
84   params.prefer_maskable_icon = true;
85   params.valid_splash_icon = true;
86   params.wait_for_worker = true;
87   return params;
88 }
89 
90 }  // anonymous namespace
91 
92 // Used only for testing pages with no service workers. This class will dispatch
93 // a RunLoop::QuitClosure when it begins waiting for a service worker to be
94 // registered.
95 class LazyWorkerInstallableManager : public InstallableManager {
96  public:
LazyWorkerInstallableManager(content::WebContents * web_contents,base::OnceClosure quit_closure)97   LazyWorkerInstallableManager(content::WebContents* web_contents,
98                                base::OnceClosure quit_closure)
99       : InstallableManager(web_contents),
100         quit_closure_(std::move(quit_closure)) {}
101   ~LazyWorkerInstallableManager() override = default;
102 
103  protected:
OnWaitingForServiceWorker()104   void OnWaitingForServiceWorker() override { std::move(quit_closure_).Run(); }
105 
106  private:
107   base::OnceClosure quit_closure_;
108 };
109 
110 // Used only for testing pages where the manifest URL is changed. This class
111 // will dispatch a RunLoop::QuitClosure when internal state is reset.
112 class ResetDataInstallableManager : public InstallableManager {
113  public:
ResetDataInstallableManager(content::WebContents * web_contents)114   explicit ResetDataInstallableManager(content::WebContents* web_contents)
115       : InstallableManager(web_contents) {}
~ResetDataInstallableManager()116   ~ResetDataInstallableManager() override {}
117 
SetQuitClosure(base::RepeatingClosure quit_closure)118   void SetQuitClosure(base::RepeatingClosure quit_closure) {
119     quit_closure_ = quit_closure;
120   }
121 
122  protected:
OnResetData()123   void OnResetData() override {
124     if (quit_closure_)
125       quit_closure_.Run();
126   }
127 
128  private:
129   base::RepeatingClosure quit_closure_;
130 };
131 
132 class CallbackTester {
133  public:
CallbackTester(base::RepeatingClosure quit_closure)134   explicit CallbackTester(base::RepeatingClosure quit_closure)
135       : quit_closure_(quit_closure) {}
136 
OnDidFinishInstallableCheck(const InstallableData & data)137   void OnDidFinishInstallableCheck(const InstallableData& data) {
138     errors_ = data.errors;
139     manifest_url_ = data.manifest_url;
140     if (data.manifest)
141       manifest_ = *data.manifest;
142     primary_icon_url_ = data.primary_icon_url;
143     if (data.primary_icon)
144       primary_icon_.reset(new SkBitmap(*data.primary_icon));
145     has_maskable_primary_icon_ = data.has_maskable_primary_icon;
146     splash_icon_url_ = data.splash_icon_url;
147     if (data.splash_icon)
148       splash_icon_.reset(new SkBitmap(*data.splash_icon));
149     valid_manifest_ = data.valid_manifest;
150     has_worker_ = data.has_worker;
151     base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_);
152   }
153 
errors() const154   const std::vector<InstallableStatusCode>& errors() const { return errors_; }
manifest_url() const155   const GURL& manifest_url() const { return manifest_url_; }
manifest() const156   const blink::Manifest& manifest() const { return manifest_; }
primary_icon_url() const157   const GURL& primary_icon_url() const { return primary_icon_url_; }
primary_icon() const158   const SkBitmap* primary_icon() const { return primary_icon_.get(); }
has_maskable_primary_icon() const159   bool has_maskable_primary_icon() const { return has_maskable_primary_icon_; }
splash_icon_url() const160   const GURL& splash_icon_url() const { return splash_icon_url_; }
splash_icon() const161   const SkBitmap* splash_icon() const { return splash_icon_.get(); }
valid_manifest() const162   bool valid_manifest() const { return valid_manifest_; }
has_worker() const163   bool has_worker() const { return has_worker_; }
164 
165  private:
166   base::RepeatingClosure quit_closure_;
167   std::vector<InstallableStatusCode> errors_;
168   GURL manifest_url_;
169   blink::Manifest manifest_;
170   GURL primary_icon_url_;
171   std::unique_ptr<SkBitmap> primary_icon_;
172   bool has_maskable_primary_icon_;
173   GURL splash_icon_url_;
174   std::unique_ptr<SkBitmap> splash_icon_;
175   bool valid_manifest_;
176   bool has_worker_;
177 };
178 
179 class NestedCallbackTester {
180  public:
NestedCallbackTester(InstallableManager * manager,const InstallableParams & params,base::OnceClosure quit_closure)181   NestedCallbackTester(InstallableManager* manager,
182                        const InstallableParams& params,
183                        base::OnceClosure quit_closure)
184       : manager_(manager),
185         params_(params),
186         quit_closure_(std::move(quit_closure)) {}
187 
Run()188   void Run() {
189     manager_->GetData(
190         params_, base::BindOnce(&NestedCallbackTester::OnDidFinishFirstCheck,
191                                 base::Unretained(this)));
192   }
193 
OnDidFinishFirstCheck(const InstallableData & data)194   void OnDidFinishFirstCheck(const InstallableData& data) {
195     errors_ = data.errors;
196     manifest_url_ = data.manifest_url;
197     manifest_ = *data.manifest;
198     primary_icon_url_ = data.primary_icon_url;
199     if (data.primary_icon)
200       primary_icon_.reset(new SkBitmap(*data.primary_icon));
201     valid_manifest_ = data.valid_manifest;
202     has_worker_ = data.has_worker;
203 
204     manager_->GetData(
205         params_, base::BindOnce(&NestedCallbackTester::OnDidFinishSecondCheck,
206                                 base::Unretained(this)));
207   }
208 
OnDidFinishSecondCheck(const InstallableData & data)209   void OnDidFinishSecondCheck(const InstallableData& data) {
210     EXPECT_EQ(errors_, data.errors);
211     EXPECT_EQ(manifest_url_, data.manifest_url);
212     EXPECT_EQ(primary_icon_url_, data.primary_icon_url);
213     EXPECT_EQ(primary_icon_.get(), data.primary_icon);
214     EXPECT_EQ(valid_manifest_, data.valid_manifest);
215     EXPECT_EQ(has_worker_, data.has_worker);
216     EXPECT_EQ(manifest_.IsEmpty(), data.manifest->IsEmpty());
217     EXPECT_EQ(manifest_.start_url, data.manifest->start_url);
218     EXPECT_EQ(manifest_.display, data.manifest->display);
219     EXPECT_EQ(manifest_.name, data.manifest->name);
220     EXPECT_EQ(manifest_.short_name, data.manifest->short_name);
221     EXPECT_EQ(manifest_.display_override, data.manifest->display_override);
222 
223     std::move(quit_closure_).Run();
224   }
225 
226  private:
227   InstallableManager* manager_;
228   InstallableParams params_;
229   base::OnceClosure quit_closure_;
230   std::vector<InstallableStatusCode> errors_;
231   GURL manifest_url_;
232   blink::Manifest manifest_;
233   GURL primary_icon_url_;
234   std::unique_ptr<SkBitmap> primary_icon_;
235   bool valid_manifest_;
236   bool has_worker_;
237 };
238 
239 class InstallableManagerBrowserTest : public InProcessBrowserTest {
240  public:
SetUpOnMainThread()241   void SetUpOnMainThread() override {
242     ASSERT_TRUE(embedded_test_server()->Start());
243 
244     // Make sure app banners are disabled in the browser so they do not
245     // interfere with the test.
246     banners::AppBannerManagerDesktop::DisableTriggeringForTesting();
247   }
248 
249   // Returns a test server URL to a page controlled by a service worker with
250   // |manifest_url| injected as the manifest tag.
GetURLOfPageWithServiceWorkerAndManifest(const std::string & manifest_url)251   std::string GetURLOfPageWithServiceWorkerAndManifest(
252       const std::string& manifest_url) {
253     return "/banners/manifest_test_page.html?manifest=" +
254            embedded_test_server()->GetURL(manifest_url).spec();
255   }
256 
NavigateAndRunInstallableManager(Browser * browser,CallbackTester * tester,const InstallableParams & params,const std::string & url)257   void NavigateAndRunInstallableManager(Browser* browser,
258                                         CallbackTester* tester,
259                                         const InstallableParams& params,
260                                         const std::string& url) {
261     GURL test_url = embedded_test_server()->GetURL(url);
262     ui_test_utils::NavigateToURL(browser, test_url);
263     RunInstallableManager(browser, tester, params);
264   }
265 
266   std::vector<content::InstallabilityError>
NavigateAndGetAllInstallabilityErrors(Browser * browser,const std::string & url)267   NavigateAndGetAllInstallabilityErrors(Browser* browser,
268                                         const std::string& url) {
269     GURL test_url = embedded_test_server()->GetURL(url);
270     ui_test_utils::NavigateToURL(browser, test_url);
271     InstallableManager* manager = GetManager(browser);
272 
273     base::RunLoop run_loop;
274     std::vector<content::InstallabilityError> result;
275 
276     manager->GetAllErrors(base::BindLambdaForTesting(
277         [&](std::vector<content::InstallabilityError> installability_errors) {
278           result = std::move(installability_errors);
279           run_loop.Quit();
280         }));
281     run_loop.Run();
282     return result;
283   }
284 
RunInstallableManager(Browser * browser,CallbackTester * tester,const InstallableParams & params)285   void RunInstallableManager(Browser* browser,
286                              CallbackTester* tester,
287                              const InstallableParams& params) {
288     InstallableManager* manager = GetManager(browser);
289     manager->GetData(
290         params, base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
291                                base::Unretained(tester)));
292   }
293 
GetManager(Browser * browser)294   InstallableManager* GetManager(Browser* browser) {
295     content::WebContents* web_contents =
296         browser->tab_strip_model()->GetActiveWebContents();
297     InstallableManager::CreateForWebContents(web_contents);
298     InstallableManager* manager =
299         InstallableManager::FromWebContents(web_contents);
300     CHECK(manager);
301 
302     return manager;
303   }
304 };
305 
306 class InstallableManagerAllowlistOriginBrowserTest
307     : public InstallableManagerBrowserTest {
SetUpCommandLine(base::CommandLine * command_line)308   void SetUpCommandLine(base::CommandLine* command_line) override {
309     command_line->AppendSwitchASCII(kUnsafeSecureOriginFlag, kInsecureOrigin);
310   }
311 };
312 
313 class InstallableManagerOfflineCapabilityBrowserTest
314     : public InstallableManagerBrowserTest,
315       public testing::WithParamInterface<std::tuple<bool, bool>> {
316   public:
InstallableManagerOfflineCapabilityBrowserTest()317     InstallableManagerOfflineCapabilityBrowserTest()
318         : is_offline_check_feature_enabled_(std::get<0>(GetParam())),
319           is_service_worker_offline_supported_(std::get<1>(GetParam())) {
320       if (is_offline_check_feature_enabled_) {
321         scoped_feature_list_.InitAndEnableFeatureWithParameters(
322             blink::features::kCheckOfflineCapability,
323             {{"check_mode", "enforce"}});
324       } else {
325         scoped_feature_list_.InitAndDisableFeature(
326             blink::features::kCheckOfflineCapability);
327       }
328     }
329     ~InstallableManagerOfflineCapabilityBrowserTest() override = default;
330 
IsServiceWorkerOfflineSupported()331     bool IsServiceWorkerOfflineSupported() {
332       return is_service_worker_offline_supported_;
333     }
334 
335     // The page supports the offline environment if a service worker has a fetch
336     // event handler that returns a response or the feature flag
337     // |kCheckOfflineCapability| is disabled.
OfflineSupported()338     bool OfflineSupported() {
339       return (!is_offline_check_feature_enabled_)
340           || is_service_worker_offline_supported_;
341     }
342 
343     // Assume that the name of HTML files using a service worker with an empty
344     // fetch event handler includes "_empty_fetch_handler" suffix.
GetPath(std::string base)345     const std::string GetPath(std::string base) {
346       if (is_service_worker_offline_supported_)
347         return base + ".html";
348       return base + "_empty_fetch_handler.html";
349     }
350 
351   private:
352     base::test::ScopedFeatureList scoped_feature_list_;
353 
354     const bool is_offline_check_feature_enabled_;
355     const bool is_service_worker_offline_supported_;
356 };
357 
358 INSTANTIATE_TEST_SUITE_P(All, InstallableManagerOfflineCapabilityBrowserTest,
359                          testing::Combine(testing::Bool(), testing::Bool()));
360 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,ManagerBeginsInEmptyState)361 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
362                        ManagerBeginsInEmptyState) {
363   // Ensure that the InstallableManager starts off with everything null.
364   InstallableManager* manager = GetManager(browser());
365 
366   EXPECT_TRUE(manager->manifest().IsEmpty());
367   EXPECT_TRUE(manager->manifest_url().is_empty());
368   EXPECT_TRUE(manager->icons_.empty());
369   EXPECT_FALSE(manager->valid_manifest());
370   EXPECT_FALSE(manager->has_worker());
371 
372   EXPECT_EQ(NO_ERROR_DETECTED, manager->manifest_error());
373   EXPECT_EQ(NO_ERROR_DETECTED, manager->valid_manifest_error());
374   EXPECT_EQ(NO_ERROR_DETECTED, manager->worker_error());
375   EXPECT_TRUE(!manager->task_queue_.HasCurrent());
376 }
377 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,ManagerInIncognito)378 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, ManagerInIncognito) {
379   // Ensure that the InstallableManager returns an error if called in an
380   // incognito profile.
381   Browser* incognito_browser =
382       OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
383   InstallableManager* manager = GetManager(incognito_browser);
384 
385   base::RunLoop run_loop;
386   std::unique_ptr<CallbackTester> tester(
387       new CallbackTester(run_loop.QuitClosure()));
388 
389   ui_test_utils::NavigateToURL(
390       incognito_browser,
391       embedded_test_server()->GetURL("/banners/manifest_test_page.html"));
392 
393   RunInstallableManager(incognito_browser, tester.get(), GetManifestParams());
394   run_loop.Run();
395 
396   EXPECT_TRUE(manager->manifest().IsEmpty());
397   EXPECT_TRUE(manager->manifest_url().is_empty());
398   EXPECT_TRUE(manager->icons_.empty());
399   EXPECT_FALSE(manager->valid_manifest());
400   EXPECT_FALSE(manager->has_worker());
401 
402   EXPECT_EQ(IN_INCOGNITO, manager->eligibility_error());
403   EXPECT_EQ(NO_ERROR_DETECTED, manager->manifest_error());
404   EXPECT_EQ(NO_ERROR_DETECTED, manager->valid_manifest_error());
405   EXPECT_EQ(NO_ERROR_DETECTED, manager->worker_error());
406   EXPECT_TRUE(!manager->task_queue_.HasCurrent());
407 }
408 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckNoManifest)409 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckNoManifest) {
410   // Ensure that a page with no manifest returns the appropriate error and with
411   // null fields for everything.
412   base::HistogramTester histograms;
413   base::RunLoop run_loop;
414   std::unique_ptr<CallbackTester> tester(
415       new CallbackTester(run_loop.QuitClosure()));
416 
417   // Navigating resets histogram state, so do it before recording a histogram.
418   ui_test_utils::NavigateToURL(
419       browser(),
420       embedded_test_server()->GetURL("/banners/no_manifest_test_page.html"));
421   RunInstallableManager(browser(), tester.get(), GetManifestParams());
422   run_loop.Run();
423 
424   // If there is no manifest, everything should be empty.
425   EXPECT_TRUE(tester->manifest().IsEmpty());
426   EXPECT_TRUE(tester->manifest_url().is_empty());
427   EXPECT_TRUE(tester->primary_icon_url().is_empty());
428   EXPECT_EQ(nullptr, tester->primary_icon());
429   EXPECT_FALSE(tester->has_maskable_primary_icon());
430   EXPECT_FALSE(tester->valid_manifest());
431   EXPECT_FALSE(tester->has_worker());
432   EXPECT_TRUE(tester->splash_icon_url().is_empty());
433   EXPECT_EQ(nullptr, tester->splash_icon());
434   EXPECT_EQ(std::vector<InstallableStatusCode>{NO_MANIFEST}, tester->errors());
435 }
436 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckManifest404)437 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckManifest404) {
438   base::RunLoop run_loop;
439   std::unique_ptr<CallbackTester> tester(
440       new CallbackTester(run_loop.QuitClosure()));
441 
442   NavigateAndRunInstallableManager(browser(), tester.get(), GetManifestParams(),
443                                    GetURLOfPageWithServiceWorkerAndManifest(
444                                        "/banners/manifest_missing.json"));
445   run_loop.Run();
446 
447   // The installable manager should return a manifest URL even if it 404s.
448   // However, the check should fail with a ManifestEmpty error.
449   EXPECT_TRUE(tester->manifest().IsEmpty());
450 
451   EXPECT_FALSE(tester->manifest_url().is_empty());
452   EXPECT_TRUE(tester->primary_icon_url().is_empty());
453   EXPECT_EQ(nullptr, tester->primary_icon());
454   EXPECT_FALSE(tester->has_maskable_primary_icon());
455   EXPECT_FALSE(tester->valid_manifest());
456   EXPECT_FALSE(tester->has_worker());
457   EXPECT_TRUE(tester->splash_icon_url().is_empty());
458   EXPECT_EQ(nullptr, tester->splash_icon());
459   EXPECT_EQ(std::vector<InstallableStatusCode>{MANIFEST_EMPTY},
460             tester->errors());
461 }
462 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckManifestOnly)463 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckManifestOnly) {
464   // Verify that asking for just the manifest works as expected.
465   base::RunLoop run_loop;
466   std::unique_ptr<CallbackTester> tester(
467       new CallbackTester(run_loop.QuitClosure()));
468 
469   NavigateAndRunInstallableManager(browser(), tester.get(), GetManifestParams(),
470                                    "/banners/manifest_test_page.html");
471   run_loop.Run();
472 
473   EXPECT_FALSE(tester->manifest().IsEmpty());
474   EXPECT_FALSE(tester->manifest_url().is_empty());
475 
476   EXPECT_TRUE(tester->primary_icon_url().is_empty());
477   EXPECT_EQ(nullptr, tester->primary_icon());
478   EXPECT_FALSE(tester->has_maskable_primary_icon());
479   EXPECT_FALSE(tester->valid_manifest());
480   EXPECT_FALSE(tester->has_worker());
481   EXPECT_TRUE(tester->splash_icon_url().is_empty());
482   EXPECT_EQ(nullptr, tester->splash_icon());
483   EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
484 }
485 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckInstallableParamsDefaultConstructor)486 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
487                        CheckInstallableParamsDefaultConstructor) {
488   // Verify that using InstallableParams' default constructor is equivalent to
489   // just asking for the manifest alone.
490   base::RunLoop run_loop;
491   std::unique_ptr<CallbackTester> tester(
492       new CallbackTester(run_loop.QuitClosure()));
493 
494   InstallableParams params;
495   NavigateAndRunInstallableManager(browser(), tester.get(), params,
496                                    "/banners/manifest_test_page.html");
497   run_loop.Run();
498 
499   EXPECT_FALSE(tester->manifest().IsEmpty());
500   EXPECT_FALSE(tester->manifest_url().is_empty());
501 
502   EXPECT_TRUE(tester->primary_icon_url().is_empty());
503   EXPECT_EQ(nullptr, tester->primary_icon());
504   EXPECT_FALSE(tester->has_maskable_primary_icon());
505   EXPECT_FALSE(tester->valid_manifest());
506   EXPECT_FALSE(tester->has_worker());
507   EXPECT_TRUE(tester->splash_icon_url().is_empty());
508   EXPECT_EQ(nullptr, tester->splash_icon());
509   EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
510 }
511 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckManifestWithIconThatIsTooSmall)512 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
513                        CheckManifestWithIconThatIsTooSmall) {
514   // This page has a manifest with only a 48x48 icon which is too small to be
515   // installable. Asking for a primary icon should fail with NO_ACCEPTABLE_ICON.
516   {
517     base::RunLoop run_loop;
518     std::unique_ptr<CallbackTester> tester(
519         new CallbackTester(run_loop.QuitClosure()));
520 
521     NavigateAndRunInstallableManager(
522         browser(), tester.get(), GetPrimaryIconParams(),
523         GetURLOfPageWithServiceWorkerAndManifest(
524             "/banners/manifest_too_small_icon.json"));
525     run_loop.Run();
526 
527     EXPECT_FALSE(tester->manifest().IsEmpty());
528     EXPECT_FALSE(tester->manifest_url().is_empty());
529 
530     EXPECT_TRUE(tester->primary_icon_url().is_empty());
531     EXPECT_EQ(nullptr, tester->primary_icon());
532     EXPECT_FALSE(tester->valid_manifest());
533     EXPECT_FALSE(tester->has_worker());
534     EXPECT_TRUE(tester->splash_icon_url().is_empty());
535     EXPECT_EQ(nullptr, tester->splash_icon());
536     EXPECT_EQ(std::vector<InstallableStatusCode>{NO_ACCEPTABLE_ICON},
537               tester->errors());
538   }
539 
540   // Ask for everything except splash icon. This should fail with
541   // NO_ACCEPTABLE_ICON - the primary icon fetch has already failed, so that
542   // cached error stops the installable check from being performed.
543   {
544     base::RunLoop run_loop;
545     std::unique_ptr<CallbackTester> tester(
546         new CallbackTester(run_loop.QuitClosure()));
547 
548     RunInstallableManager(browser(), tester.get(), GetWebAppParams());
549     run_loop.Run();
550 
551     EXPECT_FALSE(tester->manifest().IsEmpty());
552     EXPECT_FALSE(tester->manifest_url().is_empty());
553 
554     EXPECT_TRUE(tester->primary_icon_url().is_empty());
555     EXPECT_EQ(nullptr, tester->primary_icon());
556     EXPECT_FALSE(tester->valid_manifest());
557     EXPECT_FALSE(tester->has_worker());
558     EXPECT_TRUE(tester->splash_icon_url().is_empty());
559     EXPECT_EQ(nullptr, tester->splash_icon());
560     EXPECT_EQ(std::vector<InstallableStatusCode>{NO_ACCEPTABLE_ICON},
561               tester->errors());
562   }
563 
564   // Ask for a splash icon. This should fail to get a splash icon but not record
565   // an error.
566   {
567     base::RunLoop run_loop;
568     std::unique_ptr<CallbackTester> tester(
569         new CallbackTester(run_loop.QuitClosure()));
570 
571     InstallableParams params = GetPrimaryIconAndSplashIconParams();
572     params.valid_primary_icon = false;
573     RunInstallableManager(browser(), tester.get(), params);
574     run_loop.Run();
575 
576     EXPECT_FALSE(tester->manifest().IsEmpty());
577     EXPECT_FALSE(tester->manifest_url().is_empty());
578 
579     EXPECT_TRUE(tester->primary_icon_url().is_empty());
580     EXPECT_EQ(nullptr, tester->primary_icon());
581     EXPECT_TRUE(tester->splash_icon_url().is_empty());
582     EXPECT_EQ(nullptr, tester->splash_icon());
583     EXPECT_FALSE(tester->valid_manifest());
584     EXPECT_FALSE(tester->has_worker());
585     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
586   }
587 }
588 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckManifestWithOnlyRelatedApplications)589 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
590                        CheckManifestWithOnlyRelatedApplications) {
591   // This page has a manifest with only related applications specified. Asking
592   // for just the manifest should succeed.
593   {
594     base::RunLoop run_loop;
595     std::unique_ptr<CallbackTester> tester(
596         new CallbackTester(run_loop.QuitClosure()));
597 
598     NavigateAndRunInstallableManager(browser(), tester.get(),
599                                      GetManifestParams(),
600                                      GetURLOfPageWithServiceWorkerAndManifest(
601                                          "/banners/play_app_manifest.json"));
602     run_loop.Run();
603 
604     EXPECT_FALSE(tester->manifest().IsEmpty());
605     EXPECT_FALSE(tester->manifest_url().is_empty());
606     EXPECT_TRUE(tester->manifest().prefer_related_applications);
607 
608     EXPECT_TRUE(tester->primary_icon_url().is_empty());
609     EXPECT_EQ(nullptr, tester->primary_icon());
610     EXPECT_FALSE(tester->valid_manifest());
611     EXPECT_FALSE(tester->has_worker());
612     EXPECT_TRUE(tester->splash_icon_url().is_empty());
613     EXPECT_EQ(nullptr, tester->splash_icon());
614     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
615   }
616 
617   // Ask for a primary icon (but don't navigate). This should fail with
618   // NO_ACCEPTABLE_ICON.
619   {
620     base::RunLoop run_loop;
621     std::unique_ptr<CallbackTester> tester(
622         new CallbackTester(run_loop.QuitClosure()));
623 
624     RunInstallableManager(browser(), tester.get(), GetPrimaryIconParams());
625     run_loop.Run();
626 
627     EXPECT_FALSE(tester->manifest().IsEmpty());
628     EXPECT_FALSE(tester->manifest_url().is_empty());
629     EXPECT_TRUE(tester->manifest().prefer_related_applications);
630 
631     EXPECT_TRUE(tester->primary_icon_url().is_empty());
632     EXPECT_EQ(nullptr, tester->primary_icon());
633     EXPECT_FALSE(tester->valid_manifest());
634     EXPECT_FALSE(tester->has_worker());
635     EXPECT_TRUE(tester->splash_icon_url().is_empty());
636     EXPECT_EQ(nullptr, tester->splash_icon());
637     EXPECT_EQ(std::vector<InstallableStatusCode>{NO_ACCEPTABLE_ICON},
638               tester->errors());
639   }
640 
641   // Ask for everything except splash icon. This should fail with
642   // NO_ACCEPTABLE_ICON - the primary icon fetch has already failed, so that
643   // cached error stops the installable check from being performed.
644   {
645     base::RunLoop run_loop;
646     std::unique_ptr<CallbackTester> tester(
647         new CallbackTester(run_loop.QuitClosure()));
648 
649     RunInstallableManager(browser(), tester.get(), GetWebAppParams());
650     run_loop.Run();
651 
652     EXPECT_FALSE(tester->manifest().IsEmpty());
653     EXPECT_FALSE(tester->manifest_url().is_empty());
654     EXPECT_TRUE(tester->manifest().prefer_related_applications);
655 
656     EXPECT_TRUE(tester->primary_icon_url().is_empty());
657     EXPECT_EQ(nullptr, tester->primary_icon());
658     EXPECT_FALSE(tester->valid_manifest());
659     EXPECT_FALSE(tester->has_worker());
660     EXPECT_TRUE(tester->splash_icon_url().is_empty());
661     EXPECT_EQ(nullptr, tester->splash_icon());
662     EXPECT_EQ(std::vector<InstallableStatusCode>{NO_ACCEPTABLE_ICON},
663               tester->errors());
664   }
665 
666   // Do not ask for primary icon. This should fail with several validity
667   // errors.
668   {
669     base::RunLoop run_loop;
670     std::unique_ptr<CallbackTester> tester(
671         new CallbackTester(run_loop.QuitClosure()));
672 
673     InstallableParams params = GetWebAppParams();
674     params.valid_primary_icon = false;
675     RunInstallableManager(browser(), tester.get(), params);
676     run_loop.Run();
677 
678     EXPECT_FALSE(tester->manifest().IsEmpty());
679     EXPECT_FALSE(tester->manifest_url().is_empty());
680     EXPECT_TRUE(tester->manifest().prefer_related_applications);
681 
682     EXPECT_TRUE(tester->primary_icon_url().is_empty());
683     EXPECT_EQ(nullptr, tester->primary_icon());
684     EXPECT_TRUE(tester->splash_icon_url().is_empty());
685     EXPECT_EQ(nullptr, tester->splash_icon());
686     EXPECT_FALSE(tester->valid_manifest());
687     EXPECT_FALSE(tester->has_worker());
688     EXPECT_EQ(
689         std::vector<InstallableStatusCode>(
690             {START_URL_NOT_VALID, MANIFEST_MISSING_NAME_OR_SHORT_NAME,
691              MANIFEST_DISPLAY_NOT_SUPPORTED, MANIFEST_MISSING_SUITABLE_ICON}),
692         tester->errors());
693   }
694 }
695 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckManifestAndIcon)696 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckManifestAndIcon) {
697   // Add to homescreen checks for manifest + primary icon.
698   {
699     base::RunLoop run_loop;
700     std::unique_ptr<CallbackTester> tester(
701         new CallbackTester(run_loop.QuitClosure()));
702 
703     NavigateAndRunInstallableManager(browser(), tester.get(),
704                                      GetPrimaryIconParams(),
705                                      "/banners/manifest_test_page.html");
706     run_loop.Run();
707 
708     EXPECT_FALSE(tester->manifest().IsEmpty());
709     EXPECT_FALSE(tester->manifest_url().is_empty());
710 
711     EXPECT_FALSE(tester->primary_icon_url().is_empty());
712     EXPECT_NE(nullptr, tester->primary_icon());
713     EXPECT_FALSE(tester->valid_manifest());
714     EXPECT_FALSE(tester->has_worker());
715     EXPECT_TRUE(tester->splash_icon_url().is_empty());
716     EXPECT_EQ(nullptr, tester->splash_icon());
717     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
718   }
719 
720   // Add to homescreen checks for manifest + primary icon + splash icon.
721   {
722     base::RunLoop run_loop;
723     std::unique_ptr<CallbackTester> tester(
724         new CallbackTester(run_loop.QuitClosure()));
725 
726     RunInstallableManager(browser(), tester.get(),
727                           GetPrimaryIconAndSplashIconParams());
728     run_loop.Run();
729 
730     EXPECT_FALSE(tester->manifest().IsEmpty());
731     EXPECT_FALSE(tester->manifest_url().is_empty());
732 
733     EXPECT_FALSE(tester->primary_icon_url().is_empty());
734     EXPECT_NE(nullptr, tester->primary_icon());
735     EXPECT_FALSE(tester->valid_manifest());
736     EXPECT_FALSE(tester->has_worker());
737     EXPECT_FALSE(tester->splash_icon_url().is_empty());
738     EXPECT_NE(nullptr, tester->splash_icon());
739     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
740   }
741 
742   // Navigate to a page with a good maskable icon for primary icon and a bad any
743   // icon for splash icon. This should fail with NO_ICON_AVAILABLE, but still
744   // have the manifest and primary icon.
745   {
746     base::RunLoop run_loop;
747     std::unique_ptr<CallbackTester> tester(
748         new CallbackTester(run_loop.QuitClosure()));
749     NavigateAndRunInstallableManager(
750         browser(), tester.get(),
751         GetPrimaryIconPreferMaskableAndSplashIconParams(),
752         GetURLOfPageWithServiceWorkerAndManifest(
753             "/banners/manifest_bad_non_maskable_icon.json"));
754     run_loop.Run();
755     EXPECT_FALSE(tester->manifest().IsEmpty());
756     EXPECT_FALSE(tester->manifest_url().is_empty());
757     EXPECT_FALSE(tester->primary_icon_url().is_empty());
758     EXPECT_NE(nullptr, tester->primary_icon());
759     EXPECT_TRUE(tester->splash_icon_url().is_empty());
760     EXPECT_EQ(nullptr, tester->splash_icon());
761     EXPECT_FALSE(tester->valid_manifest());
762     EXPECT_FALSE(tester->has_worker());
763     EXPECT_EQ(std::vector<InstallableStatusCode>{NO_ICON_AVAILABLE},
764               tester->errors());
765   }
766 }
767 
IN_PROC_BROWSER_TEST_P(InstallableManagerOfflineCapabilityBrowserTest,CheckWebapp)768 IN_PROC_BROWSER_TEST_P(InstallableManagerOfflineCapabilityBrowserTest,
769                        CheckWebapp) {
770   // Request everything except splash icon.
771   {
772     base::HistogramTester histograms;
773     base::RunLoop run_loop;
774     std::unique_ptr<CallbackTester> tester(
775         new CallbackTester(run_loop.QuitClosure()));
776 
777     // Navigating resets histogram state, so do it before recording a histogram.
778     ui_test_utils::NavigateToURL(
779         browser(),
780         embedded_test_server()->GetURL(
781             GetPath("/banners/manifest_test_page")));
782     RunInstallableManager(browser(), tester.get(), GetWebAppParams());
783     run_loop.Run();
784 
785     EXPECT_FALSE(tester->manifest().IsEmpty());
786     EXPECT_FALSE(tester->manifest_url().is_empty());
787     EXPECT_FALSE(tester->primary_icon_url().is_empty());
788     EXPECT_NE(nullptr, tester->primary_icon());
789     EXPECT_TRUE(tester->valid_manifest());
790     if (OfflineSupported()) {
791       EXPECT_TRUE(tester->has_worker());
792       EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
793     } else {
794       EXPECT_FALSE(tester->has_worker());
795       EXPECT_EQ(std::vector<InstallableStatusCode>{NOT_OFFLINE_CAPABLE},
796                 tester->errors());
797     }
798     EXPECT_TRUE(tester->splash_icon_url().is_empty());
799     EXPECT_EQ(nullptr, tester->splash_icon());
800 
801     // Verify that the returned state matches manager internal state.
802     InstallableManager* manager = GetManager(browser());
803 
804     EXPECT_FALSE(manager->manifest().IsEmpty());
805     EXPECT_FALSE(manager->manifest_url().is_empty());
806     EXPECT_TRUE(manager->valid_manifest());
807     if (OfflineSupported()) {
808       EXPECT_TRUE(manager->has_worker());
809       EXPECT_EQ(NO_ERROR_DETECTED, manager->worker_error());
810     } else {
811       EXPECT_FALSE(manager->has_worker());
812       EXPECT_EQ(NOT_OFFLINE_CAPABLE, manager->worker_error());
813     }
814     EXPECT_EQ(1u, manager->icons_.size());
815     EXPECT_FALSE((
816         manager->icon_url(InstallableManager::IconUsage::kPrimary).is_empty()));
817     EXPECT_NE(nullptr,
818               (manager->icon(InstallableManager::IconUsage::kPrimary)));
819     EXPECT_EQ(NO_ERROR_DETECTED, manager->manifest_error());
820     EXPECT_EQ(NO_ERROR_DETECTED, manager->valid_manifest_error());
821     EXPECT_EQ(NO_ERROR_DETECTED,
822               (manager->icon_error(InstallableManager::IconUsage::kPrimary)));
823     EXPECT_TRUE(!manager->task_queue_.HasCurrent());
824   }
825 
826   // Request everything except splash icon again without navigating away. This
827   // should work fine.
828   {
829     base::RunLoop run_loop;
830     std::unique_ptr<CallbackTester> tester(
831         new CallbackTester(run_loop.QuitClosure()));
832 
833     RunInstallableManager(browser(), tester.get(), GetWebAppParams());
834     run_loop.Run();
835 
836     EXPECT_FALSE(tester->manifest().IsEmpty());
837     EXPECT_FALSE(tester->manifest_url().is_empty());
838     EXPECT_FALSE(tester->primary_icon_url().is_empty());
839     EXPECT_NE(nullptr, tester->primary_icon());
840     EXPECT_TRUE(tester->valid_manifest());
841     if (OfflineSupported()) {
842       EXPECT_TRUE(tester->has_worker());
843       EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
844     } else {
845       EXPECT_FALSE(tester->has_worker());
846       EXPECT_EQ(std::vector<InstallableStatusCode>{NOT_OFFLINE_CAPABLE},
847                 tester->errors());
848     }
849     EXPECT_TRUE(tester->splash_icon_url().is_empty());
850     EXPECT_EQ(nullptr, tester->splash_icon());
851 
852     // Verify that the returned state matches manager internal state.
853     InstallableManager* manager = GetManager(browser());
854 
855     EXPECT_FALSE(manager->manifest().IsEmpty());
856     EXPECT_FALSE(manager->manifest_url().is_empty());
857     EXPECT_TRUE(manager->valid_manifest());
858     if (OfflineSupported()) {
859       EXPECT_TRUE(manager->has_worker());
860       EXPECT_EQ(NO_ERROR_DETECTED, manager->worker_error());
861     } else {
862       EXPECT_FALSE(manager->has_worker());
863       EXPECT_EQ(NOT_OFFLINE_CAPABLE, manager->worker_error());
864     }
865     EXPECT_EQ(1u, manager->icons_.size());
866     EXPECT_FALSE((
867         manager->icon_url(InstallableManager::IconUsage::kPrimary).is_empty()));
868     EXPECT_NE(nullptr,
869               (manager->icon(InstallableManager::IconUsage::kPrimary)));
870     EXPECT_EQ(NO_ERROR_DETECTED, manager->manifest_error());
871     EXPECT_EQ(NO_ERROR_DETECTED, manager->valid_manifest_error());
872     EXPECT_EQ(NO_ERROR_DETECTED,
873               (manager->icon_error(InstallableManager::IconUsage::kPrimary)));
874     EXPECT_TRUE(!manager->task_queue_.HasCurrent());
875   }
876 
877   {
878     // Check that a subsequent navigation resets state.
879     ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
880     InstallableManager* manager = GetManager(browser());
881 
882     EXPECT_TRUE(manager->manifest().IsEmpty());
883     EXPECT_TRUE(manager->manifest_url().is_empty());
884     EXPECT_FALSE(manager->valid_manifest());
885     EXPECT_FALSE(manager->has_worker());
886     EXPECT_TRUE(manager->icons_.empty());
887     EXPECT_EQ(NO_ERROR_DETECTED, manager->manifest_error());
888     EXPECT_EQ(NO_ERROR_DETECTED, manager->valid_manifest_error());
889     EXPECT_EQ(NO_ERROR_DETECTED, manager->worker_error());
890     EXPECT_TRUE(!manager->task_queue_.HasCurrent());
891   }
892 }
893 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckMaskableIcon)894 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckMaskableIcon) {
895   // Checks that InstallableManager chooses the correct primary icon when the
896   // manifest contains maskable icons.
897 
898   // Checks that if a MASKABLE icon is specified, it is used as primary icon.
899   {
900     base::RunLoop run_loop;
901     std::unique_ptr<CallbackTester> tester(
902         new CallbackTester(run_loop.QuitClosure()));
903 
904     NavigateAndRunInstallableManager(browser(), tester.get(),
905                                      GetPrimaryIconPreferMaskableParams(),
906                                      GetURLOfPageWithServiceWorkerAndManifest(
907                                          "/banners/manifest_maskable.json"));
908 
909     run_loop.Run();
910 
911     EXPECT_FALSE(tester->manifest().IsEmpty());
912     EXPECT_FALSE(tester->manifest_url().is_empty());
913 
914     EXPECT_FALSE(tester->primary_icon_url().is_empty());
915     EXPECT_NE(nullptr, tester->primary_icon());
916     EXPECT_TRUE(tester->has_maskable_primary_icon());
917 
918     EXPECT_FALSE(tester->valid_manifest());
919     EXPECT_FALSE(tester->has_worker());
920     EXPECT_TRUE(tester->splash_icon_url().is_empty());
921     EXPECT_EQ(nullptr, tester->splash_icon());
922     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
923   }
924 
925   // Checks that we don't pick a MASKABLE icon if it was not requested.
926   {
927     base::RunLoop run_loop;
928     std::unique_ptr<CallbackTester> tester(
929         new CallbackTester(run_loop.QuitClosure()));
930 
931     NavigateAndRunInstallableManager(browser(), tester.get(),
932                                      GetPrimaryIconParams(),
933                                      GetURLOfPageWithServiceWorkerAndManifest(
934                                          "/banners/manifest_maskable.json"));
935 
936     run_loop.Run();
937 
938     EXPECT_FALSE(tester->manifest().IsEmpty());
939     EXPECT_FALSE(tester->manifest_url().is_empty());
940 
941     EXPECT_FALSE(tester->primary_icon_url().is_empty());
942     EXPECT_NE(nullptr, tester->primary_icon());
943     EXPECT_FALSE(tester->has_maskable_primary_icon());
944 
945     EXPECT_FALSE(tester->valid_manifest());
946     EXPECT_FALSE(tester->has_worker());
947     EXPECT_TRUE(tester->splash_icon_url().is_empty());
948     EXPECT_EQ(nullptr, tester->splash_icon());
949     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
950   }
951 
952   // Checks that we fall back to using an ANY icon if a MASKABLE icon is
953   // requested but not in the manifest.
954   {
955     base::RunLoop run_loop;
956     std::unique_ptr<CallbackTester> tester(
957         new CallbackTester(run_loop.QuitClosure()));
958 
959     NavigateAndRunInstallableManager(browser(), tester.get(),
960                                      GetPrimaryIconPreferMaskableParams(),
961                                      "/banners/manifest_test_page.html");
962 
963     run_loop.Run();
964 
965     EXPECT_FALSE(tester->manifest().IsEmpty());
966     EXPECT_FALSE(tester->manifest_url().is_empty());
967 
968     EXPECT_FALSE(tester->primary_icon_url().is_empty());
969     EXPECT_NE(nullptr, tester->primary_icon());
970     EXPECT_FALSE(tester->has_maskable_primary_icon());
971 
972     EXPECT_FALSE(tester->valid_manifest());
973     EXPECT_FALSE(tester->has_worker());
974     EXPECT_TRUE(tester->splash_icon_url().is_empty());
975     EXPECT_EQ(nullptr, tester->splash_icon());
976     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
977   }
978 
979   // Checks that we fall back to using an ANY icon if a MASKABLE icon is
980   // requested but the maskable icon is bad.
981   {
982     base::RunLoop run_loop;
983     std::unique_ptr<CallbackTester> tester(
984         new CallbackTester(run_loop.QuitClosure()));
985 
986     NavigateAndRunInstallableManager(
987         browser(), tester.get(), GetPrimaryIconPreferMaskableParams(),
988         GetURLOfPageWithServiceWorkerAndManifest(
989             "/banners/manifest_bad_maskable.json"));
990 
991     run_loop.Run();
992 
993     EXPECT_FALSE(tester->manifest().IsEmpty());
994     EXPECT_FALSE(tester->manifest_url().is_empty());
995 
996     EXPECT_FALSE(tester->primary_icon_url().is_empty());
997     EXPECT_NE(nullptr, tester->primary_icon());
998     EXPECT_FALSE(tester->has_maskable_primary_icon());
999 
1000     EXPECT_FALSE(tester->valid_manifest());
1001     EXPECT_FALSE(tester->has_worker());
1002     EXPECT_TRUE(tester->splash_icon_url().is_empty());
1003     EXPECT_EQ(nullptr, tester->splash_icon());
1004     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1005   }
1006 }
1007 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckNavigationWithoutRunning)1008 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1009                        CheckNavigationWithoutRunning) {
1010   {
1011     // Expect the call to ManifestAndIconTimeout to kick off an installable
1012     // check and fail it on a not installable page.
1013     base::HistogramTester histograms;
1014     ui_test_utils::NavigateToURL(
1015         browser(),
1016         embedded_test_server()->GetURL("/banners/no_manifest_test_page.html"));
1017 
1018     InstallableManager* manager = GetManager(browser());
1019 
1020     base::RunLoop run_loop;
1021     std::unique_ptr<CallbackTester> tester(
1022         new CallbackTester(run_loop.QuitClosure()));
1023 
1024     // Set up a GetData call which will not record an installable metric to
1025     // ensure we wait until the previous check has finished.
1026     manager->GetData(
1027         GetManifestParams(),
1028         base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
1029                        base::Unretained(tester.get())));
1030     run_loop.Run();
1031 
1032     ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
1033   }
1034 
1035   {
1036     // Expect the call to ManifestAndIconTimeout to kick off an installable
1037     // check and pass it on an installable page.
1038     base::HistogramTester histograms;
1039     ui_test_utils::NavigateToURL(
1040         browser(),
1041         embedded_test_server()->GetURL("/banners/manifest_test_page.html"));
1042 
1043     InstallableManager* manager = GetManager(browser());
1044 
1045     base::RunLoop run_loop;
1046     std::unique_ptr<CallbackTester> tester(
1047         new CallbackTester(run_loop.QuitClosure()));
1048 
1049     // Set up a GetData call which will not record an installable metric to
1050     // ensure we wait until the previous check has finished.
1051     manager->GetData(
1052         GetManifestParams(),
1053         base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
1054                        base::Unretained(tester.get())));
1055     run_loop.Run();
1056 
1057     ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
1058   }
1059 }
1060 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckWebappInIframe)1061 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckWebappInIframe) {
1062   base::RunLoop run_loop;
1063   std::unique_ptr<CallbackTester> tester(
1064       new CallbackTester(run_loop.QuitClosure()));
1065 
1066   NavigateAndRunInstallableManager(browser(), tester.get(), GetWebAppParams(),
1067                                    "/banners/iframe_test_page.html");
1068   run_loop.Run();
1069 
1070   // The installable manager should only retrieve items in the main frame;
1071   // everything should be empty here.
1072   EXPECT_TRUE(tester->manifest().IsEmpty());
1073   EXPECT_TRUE(tester->manifest_url().is_empty());
1074   EXPECT_TRUE(tester->primary_icon_url().is_empty());
1075   EXPECT_EQ(nullptr, tester->primary_icon());
1076   EXPECT_FALSE(tester->valid_manifest());
1077   EXPECT_FALSE(tester->has_worker());
1078   EXPECT_TRUE(tester->splash_icon_url().is_empty());
1079   EXPECT_EQ(nullptr, tester->splash_icon());
1080   EXPECT_EQ(std::vector<InstallableStatusCode>{NO_MANIFEST}, tester->errors());
1081 }
1082 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckPageWithManifestAndNoServiceWorker)1083 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1084                        CheckPageWithManifestAndNoServiceWorker) {
1085   // Just fetch the manifest. This should have no error.
1086   {
1087     base::RunLoop run_loop;
1088     std::unique_ptr<CallbackTester> tester(
1089         new CallbackTester(run_loop.QuitClosure()));
1090 
1091     NavigateAndRunInstallableManager(
1092         browser(), tester.get(), GetManifestParams(),
1093         "/banners/manifest_no_service_worker.html");
1094     run_loop.Run();
1095 
1096     EXPECT_FALSE(tester->manifest().IsEmpty());
1097     EXPECT_FALSE(tester->manifest_url().is_empty());
1098 
1099     EXPECT_TRUE(tester->primary_icon_url().is_empty());
1100     EXPECT_EQ(nullptr, tester->primary_icon());
1101     EXPECT_FALSE(tester->valid_manifest());
1102     EXPECT_FALSE(tester->has_worker());
1103     EXPECT_TRUE(tester->splash_icon_url().is_empty());
1104     EXPECT_EQ(nullptr, tester->splash_icon());
1105     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1106   }
1107 
1108   // Fetching the full criteria should fail if we don't wait for the worker.
1109   {
1110     base::RunLoop run_loop;
1111     std::unique_ptr<CallbackTester> tester(
1112         new CallbackTester(run_loop.QuitClosure()));
1113 
1114     InstallableParams params = GetWebAppParams();
1115     params.wait_for_worker = false;
1116     RunInstallableManager(browser(), tester.get(), params);
1117     run_loop.Run();
1118 
1119     EXPECT_FALSE(tester->manifest().IsEmpty());
1120     EXPECT_FALSE(tester->manifest_url().is_empty());
1121 
1122     EXPECT_FALSE(tester->primary_icon_url().is_empty());
1123     EXPECT_NE(nullptr, tester->primary_icon());
1124     EXPECT_TRUE(tester->valid_manifest());
1125     EXPECT_FALSE(tester->has_worker());
1126     EXPECT_TRUE(tester->splash_icon_url().is_empty());
1127     EXPECT_EQ(nullptr, tester->splash_icon());
1128     EXPECT_EQ(std::vector<InstallableStatusCode>{NO_MATCHING_SERVICE_WORKER},
1129               tester->errors());
1130   }
1131 }
1132 
IN_PROC_BROWSER_TEST_P(InstallableManagerOfflineCapabilityBrowserTest,CheckLazyServiceWorkerPassesWhenWaiting)1133 IN_PROC_BROWSER_TEST_P(InstallableManagerOfflineCapabilityBrowserTest,
1134                        CheckLazyServiceWorkerPassesWhenWaiting) {
1135   base::RunLoop tester_run_loop, sw_run_loop;
1136   std::unique_ptr<CallbackTester> tester(
1137       new CallbackTester(tester_run_loop.QuitClosure()));
1138 
1139   content::WebContents* web_contents =
1140       browser()->tab_strip_model()->GetActiveWebContents();
1141   auto manager = std::make_unique<LazyWorkerInstallableManager>(
1142       web_contents, sw_run_loop.QuitClosure());
1143 
1144   {
1145     // Load a URL with no service worker.
1146     GURL test_url = embedded_test_server()->GetURL(
1147         "/banners/manifest_no_service_worker.html");
1148     ui_test_utils::NavigateToURL(browser(), test_url);
1149 
1150     // Kick off fetching the data. This should block on waiting for a worker.
1151     manager->GetData(
1152         GetWebAppParams(),
1153         base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
1154                        base::Unretained(tester.get())));
1155     sw_run_loop.Run();
1156   }
1157 
1158   // We should now be waiting for the service worker.
1159   EXPECT_TRUE(tester->manifest().IsEmpty());
1160   EXPECT_FALSE(manager->manifest().IsEmpty());
1161   EXPECT_FALSE(manager->manifest_url().is_empty());
1162   EXPECT_TRUE(manager->valid_manifest());
1163   EXPECT_FALSE(manager->has_worker());
1164   EXPECT_EQ(1u, manager->icons_.size());
1165   EXPECT_FALSE(
1166       (manager->icon_url(InstallableManager::IconUsage::kPrimary).is_empty()));
1167   EXPECT_NE(nullptr, (manager->icon(InstallableManager::IconUsage::kPrimary)));
1168   EXPECT_EQ(NO_ERROR_DETECTED, manager->manifest_error());
1169   EXPECT_EQ(NO_ERROR_DETECTED, manager->valid_manifest_error());
1170   EXPECT_EQ(NO_ERROR_DETECTED, manager->worker_error());
1171   EXPECT_EQ(NO_ERROR_DETECTED,
1172             (manager->icon_error(InstallableManager::IconUsage::kPrimary)));
1173   EXPECT_TRUE(!manager->task_queue_.HasCurrent());
1174   EXPECT_TRUE(!manager->task_queue_.paused_tasks_.empty());
1175 
1176   {
1177     // Fetching just the manifest and icons should not hang while the other call
1178     // is waiting for a worker.
1179     base::RunLoop run_loop;
1180     std::unique_ptr<CallbackTester> nested_tester(
1181         new CallbackTester(run_loop.QuitClosure()));
1182     manager->GetData(
1183         GetPrimaryIconParams(),
1184         base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
1185                        base::Unretained(nested_tester.get())));
1186     run_loop.Run();
1187 
1188     EXPECT_FALSE(nested_tester->manifest().IsEmpty());
1189     EXPECT_FALSE(nested_tester->manifest_url().is_empty());
1190     EXPECT_FALSE(nested_tester->primary_icon_url().is_empty());
1191     EXPECT_NE(nullptr, nested_tester->primary_icon());
1192     EXPECT_TRUE(nested_tester->valid_manifest());
1193     EXPECT_FALSE(nested_tester->has_worker());
1194     EXPECT_TRUE(nested_tester->splash_icon_url().is_empty());
1195     EXPECT_EQ(nullptr, nested_tester->splash_icon());
1196     EXPECT_EQ(std::vector<InstallableStatusCode>{}, nested_tester->errors());
1197   }
1198 
1199   // Load the service worker.
1200   if (IsServiceWorkerOfflineSupported()) {
1201     EXPECT_TRUE(content::ExecuteScript(
1202         web_contents,
1203         "navigator.serviceWorker.register('service_worker.js');"
1204     ));
1205   } else {
1206     EXPECT_TRUE(content::ExecuteScript(
1207         web_contents,
1208         "navigator.serviceWorker.register("
1209           "'service_worker_empty_fetch_handler.js');"));
1210   }
1211   tester_run_loop.Run();
1212 
1213   // We should have passed now.
1214   EXPECT_FALSE(tester->manifest().IsEmpty());
1215   EXPECT_FALSE(tester->manifest_url().is_empty());
1216   EXPECT_FALSE(tester->primary_icon_url().is_empty());
1217   EXPECT_NE(nullptr, tester->primary_icon());
1218   EXPECT_TRUE(tester->valid_manifest());
1219   if (OfflineSupported()) {
1220     EXPECT_TRUE(tester->has_worker());
1221     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1222   } else {
1223     EXPECT_FALSE(tester->has_worker());
1224     EXPECT_EQ(std::vector<InstallableStatusCode>{NOT_OFFLINE_CAPABLE},
1225               tester->errors());
1226   }
1227   EXPECT_TRUE(tester->splash_icon_url().is_empty());
1228   EXPECT_EQ(nullptr, tester->splash_icon());
1229 
1230   // Verify internal state.
1231   EXPECT_FALSE(manager->manifest().IsEmpty());
1232   EXPECT_FALSE(manager->manifest_url().is_empty());
1233   EXPECT_TRUE(manager->valid_manifest());
1234   if (OfflineSupported()) {
1235     EXPECT_TRUE(manager->has_worker());
1236     EXPECT_EQ(NO_ERROR_DETECTED, manager->worker_error());
1237   } else {
1238     EXPECT_FALSE(manager->has_worker());
1239     EXPECT_EQ(NOT_OFFLINE_CAPABLE, manager->worker_error());
1240   }
1241   EXPECT_EQ(1u, manager->icons_.size());
1242   EXPECT_FALSE(
1243       (manager->icon_url(InstallableManager::IconUsage::kPrimary).is_empty()));
1244   EXPECT_NE(nullptr, (manager->icon(InstallableManager::IconUsage::kPrimary)));
1245   EXPECT_EQ(NO_ERROR_DETECTED, manager->manifest_error());
1246   EXPECT_EQ(NO_ERROR_DETECTED, manager->valid_manifest_error());
1247   EXPECT_EQ(NO_ERROR_DETECTED,
1248             (manager->icon_error(InstallableManager::IconUsage::kPrimary)));
1249   EXPECT_TRUE(!manager->task_queue_.HasCurrent());
1250   EXPECT_FALSE(!manager->task_queue_.paused_tasks_.empty());
1251 }
1252 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckLazyServiceWorkerNoFetchHandlerFails)1253 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1254                        CheckLazyServiceWorkerNoFetchHandlerFails) {
1255   base::RunLoop tester_run_loop, sw_run_loop;
1256   std::unique_ptr<CallbackTester> tester(
1257       new CallbackTester(tester_run_loop.QuitClosure()));
1258 
1259   content::WebContents* web_contents =
1260       browser()->tab_strip_model()->GetActiveWebContents();
1261   auto manager = std::make_unique<LazyWorkerInstallableManager>(
1262       web_contents, sw_run_loop.QuitClosure());
1263 
1264   // Load a URL with no service worker.
1265   GURL test_url = embedded_test_server()->GetURL(
1266       "/banners/manifest_no_service_worker.html");
1267   ui_test_utils::NavigateToURL(browser(), test_url);
1268 
1269   // Kick off fetching the data. This should block on waiting for a worker.
1270   manager->GetData(GetWebAppParams(),
1271                    base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
1272                                   base::Unretained(tester.get())));
1273   sw_run_loop.Run();
1274 
1275   // We should now be waiting for the service worker.
1276   EXPECT_TRUE(!manager->task_queue_.HasCurrent());
1277   EXPECT_TRUE(!manager->task_queue_.paused_tasks_.empty());
1278 
1279   // Load the service worker with no fetch handler.
1280   EXPECT_TRUE(content::ExecuteScript(web_contents,
1281                                      "navigator.serviceWorker.register('"
1282                                      "service_worker_no_fetch_handler.js');"));
1283   tester_run_loop.Run();
1284 
1285   // We should fail the check.
1286   EXPECT_FALSE(tester->manifest().IsEmpty());
1287   EXPECT_FALSE(tester->manifest_url().is_empty());
1288   EXPECT_FALSE(tester->primary_icon_url().is_empty());
1289   EXPECT_NE(nullptr, tester->primary_icon());
1290   EXPECT_TRUE(tester->valid_manifest());
1291   EXPECT_FALSE(tester->has_worker());
1292   EXPECT_TRUE(tester->splash_icon_url().is_empty());
1293   EXPECT_EQ(nullptr, tester->splash_icon());
1294   EXPECT_EQ(std::vector<InstallableStatusCode>{NOT_OFFLINE_CAPABLE},
1295             tester->errors());
1296 }
1297 
IN_PROC_BROWSER_TEST_P(InstallableManagerOfflineCapabilityBrowserTest,CheckServiceWorkerErrorIsNotCached)1298 IN_PROC_BROWSER_TEST_P(InstallableManagerOfflineCapabilityBrowserTest,
1299                        CheckServiceWorkerErrorIsNotCached) {
1300   content::WebContents* web_contents =
1301       browser()->tab_strip_model()->GetActiveWebContents();
1302   base::RunLoop sw_run_loop;
1303   auto manager = std::make_unique<LazyWorkerInstallableManager>(
1304       web_contents, sw_run_loop.QuitClosure());
1305 
1306   // Load a URL with no service worker.
1307   GURL test_url = embedded_test_server()->GetURL(
1308       "/banners/manifest_no_service_worker.html");
1309   ui_test_utils::NavigateToURL(browser(), test_url);
1310 
1311   {
1312     base::RunLoop tester_run_loop;
1313     std::unique_ptr<CallbackTester> tester(
1314         new CallbackTester(tester_run_loop.QuitClosure()));
1315 
1316     InstallableParams params = GetWebAppParams();
1317     params.wait_for_worker = false;
1318     manager->GetData(
1319         params, base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
1320                                base::Unretained(tester.get())));
1321     tester_run_loop.Run();
1322 
1323     // We should have returned with an error.
1324     EXPECT_FALSE(tester->manifest().IsEmpty());
1325     EXPECT_TRUE(tester->valid_manifest());
1326     EXPECT_FALSE(tester->has_worker());
1327     EXPECT_EQ(std::vector<InstallableStatusCode>{NO_MATCHING_SERVICE_WORKER},
1328               tester->errors());
1329   }
1330 
1331   {
1332     base::RunLoop tester_run_loop;
1333     std::unique_ptr<CallbackTester> tester(
1334         new CallbackTester(tester_run_loop.QuitClosure()));
1335 
1336     InstallableParams params = GetWebAppParams();
1337     manager->GetData(
1338         params, base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
1339                                base::Unretained(tester.get())));
1340     sw_run_loop.Run();
1341 
1342     if (IsServiceWorkerOfflineSupported()) {
1343       EXPECT_TRUE(content::ExecuteScript(
1344           web_contents,
1345           "navigator.serviceWorker.register('service_worker.js');"));
1346     } else {
1347       EXPECT_TRUE(content::ExecuteScript(
1348           web_contents,
1349           "navigator.serviceWorker.register("
1350             "'service_worker_empty_fetch_handler.js');"));
1351     }
1352     tester_run_loop.Run();
1353 
1354     // The callback result will depend on the state of offline support.
1355     EXPECT_FALSE(tester->manifest().IsEmpty());
1356     EXPECT_TRUE(tester->valid_manifest());
1357     if (OfflineSupported()) {
1358       EXPECT_TRUE(tester->has_worker());
1359       EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1360     } else {
1361       EXPECT_FALSE(tester->has_worker());
1362       EXPECT_EQ(std::vector<InstallableStatusCode>{NOT_OFFLINE_CAPABLE},
1363                 tester->errors());
1364     }
1365   }
1366 }
1367 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckPageWithNoServiceWorkerFetchHandler)1368 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1369                        CheckPageWithNoServiceWorkerFetchHandler) {
1370   base::RunLoop run_loop;
1371   std::unique_ptr<CallbackTester> tester(
1372       new CallbackTester(run_loop.QuitClosure()));
1373 
1374   NavigateAndRunInstallableManager(
1375       browser(), tester.get(), GetWebAppParams(),
1376       "/banners/no_sw_fetch_handler_test_page.html");
1377 
1378   RunInstallableManager(browser(), tester.get(), GetWebAppParams());
1379   run_loop.Run();
1380 
1381   EXPECT_FALSE(tester->manifest().IsEmpty());
1382   EXPECT_FALSE(tester->manifest_url().is_empty());
1383 
1384   EXPECT_FALSE(tester->primary_icon_url().is_empty());
1385   EXPECT_NE(nullptr, tester->primary_icon());
1386   EXPECT_TRUE(tester->valid_manifest());
1387   EXPECT_FALSE(tester->has_worker());
1388   EXPECT_TRUE(tester->splash_icon_url().is_empty());
1389   EXPECT_EQ(nullptr, tester->splash_icon());
1390   EXPECT_EQ(std::vector<InstallableStatusCode>{NOT_OFFLINE_CAPABLE},
1391             tester->errors());
1392 }
1393 
IN_PROC_BROWSER_TEST_P(InstallableManagerOfflineCapabilityBrowserTest,CheckPageWithNestedServiceWorkerCanBeInstalled)1394 IN_PROC_BROWSER_TEST_P(InstallableManagerOfflineCapabilityBrowserTest,
1395                        CheckPageWithNestedServiceWorkerCanBeInstalled) {
1396   base::RunLoop run_loop;
1397   std::unique_ptr<CallbackTester> tester(
1398       new CallbackTester(run_loop.QuitClosure()));
1399 
1400   NavigateAndRunInstallableManager(browser(), tester.get(), GetWebAppParams(),
1401                                    GetPath("/banners/nested_sw_test_page"));
1402 
1403   RunInstallableManager(browser(), tester.get(), GetWebAppParams());
1404   run_loop.Run();
1405 
1406   EXPECT_FALSE(tester->manifest().IsEmpty());
1407   EXPECT_FALSE(tester->manifest_url().is_empty());
1408 
1409   EXPECT_FALSE(tester->primary_icon_url().is_empty());
1410   EXPECT_NE(nullptr, tester->primary_icon());
1411   EXPECT_TRUE(tester->valid_manifest());
1412   if (OfflineSupported()) {
1413     EXPECT_TRUE(tester->has_worker());
1414     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1415   } else {
1416     EXPECT_FALSE(tester->has_worker());
1417     EXPECT_EQ(std::vector<InstallableStatusCode>{NOT_OFFLINE_CAPABLE},
1418               tester->errors());
1419   }
1420   EXPECT_TRUE(tester->splash_icon_url().is_empty());
1421   EXPECT_EQ(nullptr, tester->splash_icon());
1422 }
1423 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckDataUrlIcon)1424 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckDataUrlIcon) {
1425   // Verify that InstallableManager can handle data URL icons.
1426   base::RunLoop run_loop;
1427   std::unique_ptr<CallbackTester> tester(
1428       new CallbackTester(run_loop.QuitClosure()));
1429 
1430   NavigateAndRunInstallableManager(browser(), tester.get(), GetWebAppParams(),
1431                                    GetURLOfPageWithServiceWorkerAndManifest(
1432                                        "/banners/manifest_data_url_icon.json"));
1433   run_loop.Run();
1434 
1435 
1436   EXPECT_FALSE(tester->manifest().IsEmpty());
1437   EXPECT_FALSE(tester->manifest_url().is_empty());
1438 
1439   EXPECT_FALSE(tester->primary_icon_url().is_empty());
1440   EXPECT_NE(nullptr, tester->primary_icon());
1441   EXPECT_EQ(144, tester->primary_icon()->width());
1442   EXPECT_TRUE(tester->valid_manifest());
1443   EXPECT_TRUE(tester->has_worker());
1444   EXPECT_TRUE(tester->splash_icon_url().is_empty());
1445   EXPECT_EQ(nullptr, tester->splash_icon());
1446   EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1447 }
1448 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckManifestCorruptedIcon)1449 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1450                        CheckManifestCorruptedIcon) {
1451   // Verify that the returned InstallableData::primary_icon is null if the web
1452   // manifest points to a corrupt primary icon.
1453   base::RunLoop run_loop;
1454   std::unique_ptr<CallbackTester> tester(
1455       new CallbackTester(run_loop.QuitClosure()));
1456 
1457   NavigateAndRunInstallableManager(browser(), tester.get(),
1458                                    GetPrimaryIconParams(),
1459                                    GetURLOfPageWithServiceWorkerAndManifest(
1460                                        "/banners/manifest_bad_icon.json"));
1461   run_loop.Run();
1462 
1463   EXPECT_FALSE(tester->manifest().IsEmpty());
1464   EXPECT_FALSE(tester->manifest_url().is_empty());
1465   EXPECT_TRUE(tester->primary_icon_url().is_empty());
1466   EXPECT_EQ(nullptr, tester->primary_icon());
1467   EXPECT_FALSE(tester->valid_manifest());
1468   EXPECT_FALSE(tester->has_worker());
1469   EXPECT_TRUE(tester->splash_icon_url().is_empty());
1470   EXPECT_EQ(nullptr, tester->splash_icon());
1471   EXPECT_EQ(std::vector<InstallableStatusCode>{NO_ICON_AVAILABLE},
1472             tester->errors());
1473 }
1474 
IN_PROC_BROWSER_TEST_P(InstallableManagerOfflineCapabilityBrowserTest,CheckChangeInIconDimensions)1475 IN_PROC_BROWSER_TEST_P(InstallableManagerOfflineCapabilityBrowserTest,
1476                        CheckChangeInIconDimensions) {
1477   // Verify that a follow-up request for a primary icon with a different size
1478   // works.
1479   {
1480     base::RunLoop run_loop;
1481     std::unique_ptr<CallbackTester> tester(
1482         new CallbackTester(run_loop.QuitClosure()));
1483 
1484     NavigateAndRunInstallableManager(browser(), tester.get(), GetWebAppParams(),
1485                                      GetPath("/banners/manifest_test_page"));
1486     run_loop.Run();
1487 
1488     EXPECT_FALSE(tester->manifest_url().is_empty());
1489     EXPECT_FALSE(tester->manifest().IsEmpty());
1490     EXPECT_FALSE(tester->primary_icon_url().is_empty());
1491     EXPECT_NE(nullptr, tester->primary_icon());
1492     EXPECT_TRUE(tester->valid_manifest());
1493     if (OfflineSupported()) {
1494       EXPECT_TRUE(tester->has_worker());
1495       EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1496     } else {
1497       EXPECT_FALSE(tester->has_worker());
1498       EXPECT_EQ(std::vector<InstallableStatusCode>{NOT_OFFLINE_CAPABLE},
1499                 tester->errors());
1500     }
1501     EXPECT_TRUE(tester->splash_icon_url().is_empty());
1502     EXPECT_EQ(nullptr, tester->splash_icon());
1503   }
1504 
1505   {
1506     base::RunLoop run_loop;
1507     std::unique_ptr<CallbackTester> tester(
1508         new CallbackTester(run_loop.QuitClosure()));
1509     RunInstallableManager(browser(), tester.get(), GetWebAppParams());
1510 
1511     run_loop.Run();
1512 
1513     // The smaller primary icon requirements should allow this to pass.
1514     EXPECT_FALSE(tester->manifest_url().is_empty());
1515     EXPECT_FALSE(tester->manifest().IsEmpty());
1516     EXPECT_FALSE(tester->primary_icon_url().is_empty());
1517     EXPECT_NE(nullptr, tester->primary_icon());
1518     EXPECT_TRUE(tester->valid_manifest());
1519     if (OfflineSupported()) {
1520       EXPECT_TRUE(tester->has_worker());
1521       EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1522     } else {
1523       EXPECT_FALSE(tester->has_worker());
1524       EXPECT_EQ(std::vector<InstallableStatusCode>{NOT_OFFLINE_CAPABLE},
1525                 tester->errors());
1526     }
1527     EXPECT_TRUE(tester->splash_icon_url().is_empty());
1528     EXPECT_EQ(nullptr, tester->splash_icon());
1529   }
1530 }
1531 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckNestedCallsToGetData)1532 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1533                        CheckNestedCallsToGetData) {
1534   // Verify that we can call GetData while in a callback from GetData.
1535   base::RunLoop run_loop;
1536   InstallableParams params = GetWebAppParams();
1537   std::unique_ptr<NestedCallbackTester> tester(new NestedCallbackTester(
1538       GetManager(browser()), params, run_loop.QuitClosure()));
1539 
1540   tester->Run();
1541   run_loop.Run();
1542 }
1543 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,ManifestUrlChangeFlushesState)1544 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1545                        ManifestUrlChangeFlushesState) {
1546   content::WebContents* web_contents =
1547       browser()->tab_strip_model()->GetActiveWebContents();
1548   auto manager = std::make_unique<ResetDataInstallableManager>(web_contents);
1549 
1550   // Start on a page with no manifest.
1551   ui_test_utils::NavigateToURL(
1552       browser(),
1553       embedded_test_server()->GetURL("/banners/no_manifest_test_page.html"));
1554 
1555   {
1556     // Fetch the data. This should return an empty manifest.
1557     base::RunLoop run_loop;
1558     std::unique_ptr<CallbackTester> tester(
1559         new CallbackTester(run_loop.QuitClosure()));
1560 
1561     manager->GetData(
1562         GetWebAppParams(),
1563         base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
1564                        base::Unretained(tester.get())));
1565     run_loop.Run();
1566 
1567     EXPECT_TRUE(tester->manifest().IsEmpty());
1568     EXPECT_EQ(NO_MANIFEST, manager->manifest_error());
1569     EXPECT_EQ(std::vector<InstallableStatusCode>{NO_MANIFEST},
1570               tester->errors());
1571   }
1572 
1573   {
1574     // Injecting a manifest URL but not navigating should flush the state.
1575     base::RunLoop run_loop;
1576     manager->SetQuitClosure(run_loop.QuitClosure());
1577     EXPECT_TRUE(content::ExecuteScript(web_contents, "addManifestLinkTag()"));
1578     run_loop.Run();
1579 
1580     EXPECT_TRUE(manager->manifest().IsEmpty());
1581     EXPECT_EQ(NO_ERROR_DETECTED, manager->manifest_error());
1582   }
1583 
1584   {
1585     // Fetch the data again. This should succeed.
1586     base::RunLoop run_loop;
1587     std::unique_ptr<CallbackTester> tester(
1588         new CallbackTester(run_loop.QuitClosure()));
1589 
1590     manager->GetData(
1591         GetWebAppParams(),
1592         base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
1593                        base::Unretained(tester.get())));
1594     run_loop.Run();
1595 
1596     EXPECT_FALSE(tester->manifest().IsEmpty());
1597     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1598     EXPECT_EQ(base::ASCIIToUTF16("Manifest test app"), tester->manifest().name);
1599     EXPECT_EQ(base::string16(),
1600               tester->manifest().short_name.value_or(base::string16()));
1601   }
1602 
1603   {
1604     // Flush the state again by changing the manifest URL.
1605     base::RunLoop run_loop;
1606     manager->SetQuitClosure(run_loop.QuitClosure());
1607 
1608     GURL manifest_url = embedded_test_server()->GetURL(
1609         "/banners/manifest_short_name_only.json");
1610     EXPECT_TRUE(content::ExecuteScript(
1611         web_contents, "changeManifestUrl('" + manifest_url.spec() + "');"));
1612     run_loop.Run();
1613 
1614     EXPECT_TRUE(manager->manifest().IsEmpty());
1615   }
1616 
1617   {
1618     // Fetch again. This should return the data from the new manifest.
1619     base::RunLoop run_loop;
1620     std::unique_ptr<CallbackTester> tester(
1621         new CallbackTester(run_loop.QuitClosure()));
1622 
1623     manager->GetData(
1624         GetWebAppParams(),
1625         base::BindOnce(&CallbackTester::OnDidFinishInstallableCheck,
1626                        base::Unretained(tester.get())));
1627     run_loop.Run();
1628 
1629     EXPECT_FALSE(tester->manifest().IsEmpty());
1630     EXPECT_EQ(base::string16(),
1631               tester->manifest().name.value_or(base::string16()));
1632     EXPECT_EQ(base::ASCIIToUTF16("Manifest"), tester->manifest().short_name);
1633     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1634   }
1635 }
1636 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,DebugModeWithNoManifest)1637 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, DebugModeWithNoManifest) {
1638   // Ensure that a page with no manifest stops with NO_MANIFEST in debug mode.
1639   base::RunLoop run_loop;
1640   std::unique_ptr<CallbackTester> tester(
1641       new CallbackTester(run_loop.QuitClosure()));
1642 
1643   InstallableParams params = GetWebAppParams();
1644   params.is_debug_mode = true;
1645   ui_test_utils::NavigateToURL(
1646       browser(),
1647       embedded_test_server()->GetURL("/banners/no_manifest_test_page.html"));
1648   RunInstallableManager(browser(), tester.get(), params);
1649   run_loop.Run();
1650 
1651   EXPECT_EQ(std::vector<InstallableStatusCode>({NO_MANIFEST}),
1652             tester->errors());
1653 }
1654 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,DebugModeAccumulatesErrorsWithManifest)1655 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1656                        DebugModeAccumulatesErrorsWithManifest) {
1657   base::RunLoop run_loop;
1658   std::unique_ptr<CallbackTester> tester(
1659       new CallbackTester(run_loop.QuitClosure()));
1660 
1661   InstallableParams params = GetWebAppParams();
1662   params.is_debug_mode = true;
1663   NavigateAndRunInstallableManager(browser(), tester.get(), params,
1664                                    GetURLOfPageWithServiceWorkerAndManifest(
1665                                        "/banners/play_app_manifest.json"));
1666   run_loop.Run();
1667 
1668   EXPECT_EQ(std::vector<InstallableStatusCode>(
1669                 {START_URL_NOT_VALID, MANIFEST_MISSING_NAME_OR_SHORT_NAME,
1670                  MANIFEST_DISPLAY_NOT_SUPPORTED, MANIFEST_MISSING_SUITABLE_ICON,
1671                  NO_ACCEPTABLE_ICON}),
1672             tester->errors());
1673 }
1674 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,DebugModeBadFallbackMaskable)1675 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1676                        DebugModeBadFallbackMaskable) {
1677   base::RunLoop run_loop;
1678   std::unique_ptr<CallbackTester> tester(
1679       new CallbackTester(run_loop.QuitClosure()));
1680 
1681   InstallableParams params = GetPrimaryIconPreferMaskableParams();
1682   params.is_debug_mode = true;
1683 
1684   NavigateAndRunInstallableManager(
1685       browser(), tester.get(), params,
1686       GetURLOfPageWithServiceWorkerAndManifest(
1687           "/banners/manifest_one_bad_maskable.json"));
1688 
1689   run_loop.Run();
1690 
1691   EXPECT_FALSE(tester->manifest().IsEmpty());
1692   EXPECT_FALSE(tester->manifest_url().is_empty());
1693 
1694   EXPECT_TRUE(tester->primary_icon_url().is_empty());
1695   EXPECT_EQ(nullptr, tester->primary_icon());
1696   EXPECT_FALSE(tester->has_maskable_primary_icon());
1697 
1698   EXPECT_FALSE(tester->valid_manifest());
1699   EXPECT_FALSE(tester->has_worker());
1700   EXPECT_TRUE(tester->splash_icon_url().is_empty());
1701   EXPECT_EQ(nullptr, tester->splash_icon());
1702   EXPECT_EQ(std::vector<InstallableStatusCode>{NO_ACCEPTABLE_ICON},
1703             tester->errors());
1704 }
1705 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,GetAllInatallabilityErrorsNoErrors)1706 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1707                        GetAllInatallabilityErrorsNoErrors) {
1708   EXPECT_EQ(std::vector<content::InstallabilityError>{},
1709             NavigateAndGetAllInstallabilityErrors(
1710                 browser(), "/banners/manifest_test_page.html"));
1711 }
1712 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,GetAllInatallabilityErrorsWithNoManifest)1713 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1714                        GetAllInatallabilityErrorsWithNoManifest) {
1715   EXPECT_EQ(std::vector<content::InstallabilityError>{GetInstallabilityError(
1716                 NO_MANIFEST)},
1717             NavigateAndGetAllInstallabilityErrors(
1718                 browser(), "/banners/no_manifest_test_page.html"));
1719 }
1720 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,GetAllInatallabilityErrorsWithPlayAppManifest)1721 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1722                        GetAllInatallabilityErrorsWithPlayAppManifest) {
1723   EXPECT_EQ(std::vector<content::InstallabilityError>(
1724                 {GetInstallabilityError(START_URL_NOT_VALID),
1725                  GetInstallabilityError(MANIFEST_MISSING_NAME_OR_SHORT_NAME),
1726                  GetInstallabilityError(MANIFEST_DISPLAY_NOT_SUPPORTED),
1727                  GetInstallabilityError(MANIFEST_MISSING_SUITABLE_ICON),
1728                  GetInstallabilityError(NO_ACCEPTABLE_ICON)}),
1729             NavigateAndGetAllInstallabilityErrors(
1730                 browser(), GetURLOfPageWithServiceWorkerAndManifest(
1731                                "/banners/play_app_manifest.json")));
1732 }
1733 
IN_PROC_BROWSER_TEST_F(InstallableManagerAllowlistOriginBrowserTest,SecureOriginCheckRespectsUnsafeFlag)1734 IN_PROC_BROWSER_TEST_F(InstallableManagerAllowlistOriginBrowserTest,
1735                        SecureOriginCheckRespectsUnsafeFlag) {
1736   // The allowlisted origin should be regarded as secure.
1737   ui_test_utils::NavigateToURL(browser(), GURL(kInsecureOrigin));
1738   content::WebContents* contents =
1739       browser()->tab_strip_model()->GetActiveWebContents();
1740   EXPECT_TRUE(InstallableManager::IsContentSecure(contents));
1741 
1742   // While a non-allowlisted origin should not.
1743   ui_test_utils::NavigateToURL(browser(), GURL(kOtherInsecureOrigin));
1744   EXPECT_FALSE(InstallableManager::IsContentSecure(contents));
1745 }
1746 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,NarrowServiceWorker)1747 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, NarrowServiceWorker) {
1748   const GURL url =
1749       embedded_test_server()->GetURL("/banners/scope_c/scope_c.html");
1750   {
1751     web_app::ServiceWorkerRegistrationWaiter registration_waiter(
1752         browser()->profile(), url);
1753     ui_test_utils::NavigateToURL(browser(), url);
1754     registration_waiter.AwaitRegistration();
1755   }
1756   base::RunLoop run_loop;
1757   std::unique_ptr<CallbackTester> tester(
1758       new CallbackTester(run_loop.QuitClosure()));
1759 
1760   InstallableParams params = GetWebAppParams();
1761   params.wait_for_worker = false;
1762 
1763   RunInstallableManager(browser(), tester.get(), params);
1764   run_loop.Run();
1765 
1766   EXPECT_EQ(std::vector<InstallableStatusCode>({NO_MATCHING_SERVICE_WORKER}),
1767             tester->errors());
1768 }
1769 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,CheckSplashIcon)1770 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckSplashIcon) {
1771   // Checks that InstallableManager chooses the correct splash icon.
1772 
1773   // Test page has a manifest with only one icon, primary icon and splash icon
1774   // should be the same one.
1775   {
1776     base::RunLoop run_loop;
1777     std::unique_ptr<CallbackTester> tester(
1778         new CallbackTester(run_loop.QuitClosure()));
1779 
1780     NavigateAndRunInstallableManager(browser(), tester.get(),
1781                                      GetPrimaryIconAndSplashIconParams(),
1782                                      GetURLOfPageWithServiceWorkerAndManifest(
1783                                          "/banners/manifest_one_icon.json"));
1784 
1785     run_loop.Run();
1786 
1787     EXPECT_FALSE(tester->manifest().IsEmpty());
1788     EXPECT_FALSE(tester->manifest_url().is_empty());
1789 
1790     EXPECT_FALSE(tester->primary_icon_url().is_empty());
1791     EXPECT_NE(nullptr, tester->primary_icon());
1792     EXPECT_FALSE(tester->valid_manifest());
1793     EXPECT_FALSE(tester->has_worker());
1794     EXPECT_FALSE(tester->splash_icon_url().is_empty());
1795     EXPECT_NE(nullptr, tester->splash_icon());
1796     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1797 
1798     EXPECT_EQ(tester->primary_icon_url(), tester->splash_icon_url());
1799   }
1800 
1801   // Test page has a manifest with only one maskable icon. This should fail to
1802   // get a splash icon but not record an error.
1803   {
1804     base::RunLoop run_loop;
1805     std::unique_ptr<CallbackTester> tester(
1806         new CallbackTester(run_loop.QuitClosure()));
1807 
1808     NavigateAndRunInstallableManager(
1809         browser(), tester.get(),
1810         GetPrimaryIconPreferMaskableAndSplashIconParams(),
1811         GetURLOfPageWithServiceWorkerAndManifest(
1812             "/banners/manifest_one_maskable.json"));
1813 
1814     run_loop.Run();
1815 
1816     EXPECT_FALSE(tester->manifest().IsEmpty());
1817     EXPECT_FALSE(tester->manifest_url().is_empty());
1818 
1819     EXPECT_FALSE(tester->primary_icon_url().is_empty());
1820     EXPECT_NE(nullptr, tester->primary_icon());
1821     EXPECT_TRUE(tester->has_maskable_primary_icon());
1822     EXPECT_FALSE(tester->valid_manifest());
1823     EXPECT_FALSE(tester->has_worker());
1824     EXPECT_TRUE(tester->splash_icon_url().is_empty());
1825     EXPECT_EQ(nullptr, tester->splash_icon());
1826     EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1827   }
1828 }
1829 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,ManifestLinkChangeReportsError)1830 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
1831                        ManifestLinkChangeReportsError) {
1832   InstallableManager* manager = GetManager(browser());
1833 
1834   base::RunLoop run_loop;
1835   std::unique_ptr<CallbackTester> tester(
1836       new CallbackTester(run_loop.QuitClosure()));
1837 
1838   NavigateAndRunInstallableManager(browser(), tester.get(), GetManifestParams(),
1839                                    "/banners/manifest_test_page.html");
1840   // Simulate a manifest URL update by just calling the observer function.
1841   static_cast<content::WebContentsObserver*>(manager)->DidUpdateWebManifestURL(
1842       nullptr, base::nullopt);
1843   run_loop.Run();
1844 
1845   ASSERT_EQ(tester->errors().size(), 1u);
1846   EXPECT_EQ(tester->errors()[0], MANIFEST_URL_CHANGED);
1847 }
1848 
1849 // A dedicated test fixture for DisplayOverride, which is supported
1850 // only for the new web apps mode, and requires a command line switch
1851 // to enable manifest parsing.
1852 class InstallableManagerBrowserTest_DisplayOverride
1853     : public InstallableManagerBrowserTest {
1854  public:
InstallableManagerBrowserTest_DisplayOverride()1855   InstallableManagerBrowserTest_DisplayOverride() {
1856     scoped_feature_list_.InitAndEnableFeature(
1857         features::kWebAppManifestDisplayOverride);
1858   }
1859 
1860  private:
1861   base::test::ScopedFeatureList scoped_feature_list_;
1862 };
1863 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest_DisplayOverride,CheckManifestOnly)1864 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest_DisplayOverride,
1865                        CheckManifestOnly) {
1866   base::RunLoop run_loop;
1867   std::unique_ptr<CallbackTester> tester(
1868       new CallbackTester(run_loop.QuitClosure()));
1869 
1870   NavigateAndRunInstallableManager(
1871       browser(), tester.get(), GetManifestParams(),
1872       GetURLOfPageWithServiceWorkerAndManifest(
1873           "/banners/manifest_display_override.json"));
1874   run_loop.Run();
1875 
1876   EXPECT_FALSE(tester->manifest().IsEmpty());
1877   EXPECT_FALSE(tester->manifest_url().is_empty());
1878   ASSERT_EQ(2u, tester->manifest().display_override.size());
1879   EXPECT_EQ(blink::mojom::DisplayMode::kMinimalUi,
1880             tester->manifest().display_override[0]);
1881   EXPECT_EQ(blink::mojom::DisplayMode::kStandalone,
1882             tester->manifest().display_override[1]);
1883 
1884   EXPECT_TRUE(tester->primary_icon_url().is_empty());
1885   EXPECT_EQ(nullptr, tester->primary_icon());
1886   EXPECT_FALSE(tester->has_maskable_primary_icon());
1887   EXPECT_FALSE(tester->valid_manifest());
1888   EXPECT_FALSE(tester->has_worker());
1889   EXPECT_TRUE(tester->splash_icon_url().is_empty());
1890   EXPECT_EQ(nullptr, tester->splash_icon());
1891   EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1892 }
1893 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest_DisplayOverride,ManifestDisplayOverrideReportsError)1894 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest_DisplayOverride,
1895                        ManifestDisplayOverrideReportsError) {
1896   base::RunLoop run_loop;
1897   std::unique_ptr<CallbackTester> tester(
1898       new CallbackTester(run_loop.QuitClosure()));
1899 
1900   NavigateAndRunInstallableManager(
1901       browser(), tester.get(), GetWebAppParams(),
1902       GetURLOfPageWithServiceWorkerAndManifest(
1903           "/banners/manifest_display_override_contains_browser.json"));
1904   run_loop.Run();
1905 
1906   EXPECT_FALSE(tester->manifest().IsEmpty());
1907   EXPECT_FALSE(tester->manifest_url().is_empty());
1908   ASSERT_EQ(3u, tester->manifest().display_override.size());
1909   EXPECT_EQ(blink::mojom::DisplayMode::kBrowser,
1910             tester->manifest().display_override[0]);
1911   EXPECT_EQ(blink::mojom::DisplayMode::kMinimalUi,
1912             tester->manifest().display_override[1]);
1913   EXPECT_EQ(blink::mojom::DisplayMode::kStandalone,
1914             tester->manifest().display_override[2]);
1915   EXPECT_EQ(
1916       std::vector<InstallableStatusCode>{
1917           MANIFEST_DISPLAY_OVERRIDE_NOT_SUPPORTED},
1918       tester->errors());
1919 }
1920 
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest_DisplayOverride,FallbackToDisplayBrowser)1921 IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest_DisplayOverride,
1922                        FallbackToDisplayBrowser) {
1923   base::RunLoop run_loop;
1924   std::unique_ptr<CallbackTester> tester(
1925       new CallbackTester(run_loop.QuitClosure()));
1926 
1927   NavigateAndRunInstallableManager(
1928       browser(), tester.get(), GetWebAppParams(),
1929       GetURLOfPageWithServiceWorkerAndManifest(
1930           "/banners/manifest_display_override_display_is_browser.json"));
1931   run_loop.Run();
1932 
1933   EXPECT_FALSE(tester->manifest().IsEmpty());
1934   EXPECT_FALSE(tester->manifest_url().is_empty());
1935   ASSERT_EQ(1u, tester->manifest().display_override.size());
1936   EXPECT_EQ(blink::mojom::DisplayMode::kStandalone,
1937             tester->manifest().display_override[0]);
1938 
1939   EXPECT_FALSE(tester->primary_icon_url().is_empty());
1940   EXPECT_NE(nullptr, tester->primary_icon());
1941   EXPECT_EQ(144, tester->primary_icon()->width());
1942   EXPECT_TRUE(tester->valid_manifest());
1943   EXPECT_TRUE(tester->has_worker());
1944   EXPECT_TRUE(tester->splash_icon_url().is_empty());
1945   EXPECT_EQ(nullptr, tester->splash_icon());
1946   EXPECT_EQ(std::vector<InstallableStatusCode>{}, tester->errors());
1947 }
1948