Settings reset prompt: Add a unit test for the default settings fetcher.

The test ensures that DefaultSettingsFetcher never returns null even when fetching default settings fails.

BUG=716372

Review-Url: https://codereview.chromium.org/2850103002
Cr-Commit-Position: refs/heads/master@{#468424}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 8d66725c..9cfc638 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1787,6 +1787,8 @@
       "renderer_host/chrome_extension_message_filter.h",
       "safe_browsing/chrome_cleaner_dialog_controller.cc",
       "safe_browsing/chrome_cleaner_dialog_controller.h",
+      "safe_browsing/settings_reset_prompt/default_settings_fetcher.cc",
+      "safe_browsing/settings_reset_prompt/default_settings_fetcher.h",
       "safe_browsing/settings_reset_prompt/extension_info.cc",
       "safe_browsing/settings_reset_prompt/extension_info.h",
       "safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc",
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.cc b/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.cc
new file mode 100644
index 0000000..ea8490e
--- /dev/null
+++ b/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.cc
@@ -0,0 +1,95 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.h"
+
+#include <string>
+#include <utility>
+
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/google/google_brand.h"
+#include "chrome/browser/profile_resetter/brandcode_config_fetcher.h"
+#include "chrome/browser/profile_resetter/brandcoded_default_settings.h"
+#include "content/public/browser/browser_thread.h"
+#include "url/gurl.h"
+
+namespace safe_browsing {
+
+namespace {
+
+#if defined(GOOGLE_CHROME_BUILD)
+constexpr char kOmahaUrl[] = "https://tools.google.com/service/update2";
+#endif  // defined(GOOGLE_CHROME_BUILD)
+
+}  // namespace
+
+// static
+void DefaultSettingsFetcher::FetchDefaultSettings(SettingsCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  // |settings_fetcher| will delete itself when default settings have been
+  // fetched after the call to |Start()|.
+  DefaultSettingsFetcher* settings_fetcher =
+      new DefaultSettingsFetcher(std::move(callback));
+  settings_fetcher->Start();
+}
+
+// static
+void DefaultSettingsFetcher::FetchDefaultSettingsForTesting(
+    SettingsCallback callback,
+    std::unique_ptr<BrandcodedDefaultSettings> fetched_settings) {
+  DefaultSettingsFetcher* settings_fetcher =
+      new DefaultSettingsFetcher(std::move(callback));
+  // Inject the given settings directly by passing them to
+  // |PostCallbackAndDeleteSelf()|.
+  settings_fetcher->PostCallbackAndDeleteSelf(std::move(fetched_settings));
+}
+
+DefaultSettingsFetcher::DefaultSettingsFetcher(SettingsCallback callback)
+    : callback_(std::move(callback)) {}
+
+DefaultSettingsFetcher::~DefaultSettingsFetcher() {}
+
+void DefaultSettingsFetcher::Start() {
+  DCHECK(!config_fetcher_);
+
+#if defined(GOOGLE_CHROME_BUILD)
+  std::string brandcode;
+  if (google_brand::GetBrand(&brandcode) && !brandcode.empty()) {
+    config_fetcher_.reset(new BrandcodeConfigFetcher(
+        base::Bind(&DefaultSettingsFetcher::OnSettingsFetched,
+                   base::Unretained(this)),
+        GURL(kOmahaUrl), brandcode));
+    return;
+  }
+#endif  // defined(GOOGLE_CHROME_BUILD)
+
+  // For non Google Chrome builds and cases with an empty |brandcode|, we create
+  // a default-constructed |BrandcodedDefaultSettings| object and post the
+  // callback immediately.
+  PostCallbackAndDeleteSelf(base::MakeUnique<BrandcodedDefaultSettings>());
+}
+
+void DefaultSettingsFetcher::OnSettingsFetched() {
+  DCHECK(config_fetcher_);
+  DCHECK(!config_fetcher_->IsActive());
+
+  PostCallbackAndDeleteSelf(config_fetcher_->GetSettings());
+}
+
+void DefaultSettingsFetcher::PostCallbackAndDeleteSelf(
+    std::unique_ptr<BrandcodedDefaultSettings> default_settings) {
+  // Use default settings if fetching of BrandcodedDefaultSettings failed.
+  if (!default_settings)
+    default_settings.reset(new BrandcodedDefaultSettings());
+
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::BindOnce(std::move(callback_), base::Passed(&default_settings)));
+  delete this;
+}
+
+}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.h b/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.h
new file mode 100644
index 0000000..ffd5e9eaa
--- /dev/null
+++ b/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.h
@@ -0,0 +1,64 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SAFE_BROWSING_SETTINGS_RESET_PROMPT_DEFAULT_SETTINGS_FETCHER_H_
+#define CHROME_BROWSER_SAFE_BROWSING_SETTINGS_RESET_PROMPT_DEFAULT_SETTINGS_FETCHER_H_
+
+#include <memory>
+
+#include "base/callback.h"
+
+class BrandcodedDefaultSettings;
+class BrandcodeConfigFetcher;
+
+namespace safe_browsing {
+
+// Class that fetches default settings to be used for the settings reset
+// prompt. The static |FetchDefaultSettings()| function will create and manage
+// the lifetime of |DefaultSettingsFetcher| instances.
+class DefaultSettingsFetcher {
+ public:
+  using SettingsCallback =
+      base::Callback<void(std::unique_ptr<BrandcodedDefaultSettings>)>;
+
+  // Fetches default settings and passes the corresponding
+  // |BrandcodedDefaultSettings| object to |callback| on the UI thread. This
+  // function must be called on the UI thread as well.
+  static void FetchDefaultSettings(SettingsCallback callback);
+  // Allows tests to specify the default settings that were fetched in
+  // |fetched_settings|. Passing nullptr as |fetched_settings| corresponds to
+  // the case when fetching default settings over the network fails.
+  static void FetchDefaultSettingsForTesting(
+      SettingsCallback callback,
+      std::unique_ptr<BrandcodedDefaultSettings> fetched_settings);
+
+ private:
+  // Instances of |DefaultSettingsFetcher| own themselves and will delete
+  // themselves once default settings have been fetched and |callback| has been
+  // posted on the UI thread.
+  //
+  // The main reason for this design is that |BrandcodeConfigFetcher| takes a
+  // callback and initiates the fetching process in its constructor, and we need
+  // to hold on to the instance of the fetcher until settings have been
+  // fetched. This design saves us from having to explicitly manage global
+  // |BrandcodeConfigFetcher| instances.
+  explicit DefaultSettingsFetcher(SettingsCallback callback);
+  ~DefaultSettingsFetcher();
+
+  // Starts the process of fetching default settings and will ensure that
+  // |PostCallbackAndDeleteSelf| is called once settings have been fetched.
+  void Start();
+  void OnSettingsFetched();
+  // Posts a call to |callback_| on the UI thread, passing to it
+  // |default_settings|, and deletes |this|.
+  void PostCallbackAndDeleteSelf(
+      std::unique_ptr<BrandcodedDefaultSettings> default_settings);
+
+  std::unique_ptr<BrandcodeConfigFetcher> config_fetcher_;
+  SettingsCallback callback_;
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_SAFE_BROWSING_SETTINGS_RESET_PROMPT_DEFAULT_SETTINGS_FETCHER_H_
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher_browsertest.cc b/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher_browsertest.cc
new file mode 100644
index 0000000..4b39921
--- /dev/null
+++ b/chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher_browsertest.cc
@@ -0,0 +1,69 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "chrome/browser/profile_resetter/brandcoded_default_settings.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace safe_browsing {
+namespace {
+
+class DefaultSettingsFetcherTest : public InProcessBrowserTest {
+ public:
+  void FetchedSettings(std::unique_ptr<BrandcodedDefaultSettings> settings) {
+    EXPECT_FALSE(settings_);
+    EXPECT_FALSE(fetched_settings_called);
+
+    fetched_settings_called = true;
+    settings_ = std::move(settings);
+  }
+
+ protected:
+  bool fetched_settings_called = false;
+  std::unique_ptr<BrandcodedDefaultSettings> settings_;
+};
+
+IN_PROC_BROWSER_TEST_F(DefaultSettingsFetcherTest, FetchingSettingsSucceeded) {
+  // The default settings that we will pretend were fetched. Keep the raw
+  // pointer here so that we can compare it to what was passed to the callback.
+  BrandcodedDefaultSettings* default_settings = new BrandcodedDefaultSettings();
+
+  DefaultSettingsFetcher::FetchDefaultSettingsForTesting(
+      base::Bind(&DefaultSettingsFetcherTest::FetchedSettings,
+                 base::Unretained(this)),
+      base::WrapUnique(default_settings));
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(fetched_settings_called);
+  EXPECT_EQ(default_settings, settings_.get());
+}
+
+IN_PROC_BROWSER_TEST_F(DefaultSettingsFetcherTest, FetchingSettingsFailed) {
+  // Pretend that fetching default settings failed by passing in a nullptr to
+  // |FetchDefaultSettingsForTesting()|. The callback should still receive
+  // default-constructed default settings.
+  DefaultSettingsFetcher::FetchDefaultSettingsForTesting(
+      base::Bind(&DefaultSettingsFetcherTest::FetchedSettings,
+                 base::Unretained(this)),
+      nullptr);
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(fetched_settings_called);
+  EXPECT_TRUE(settings_);
+}
+
+}  // namespace
+}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_model.cc b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_model.cc
index f93e81e6..3a8daef 100644
--- a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_model.cc
+++ b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_model.cc
@@ -10,12 +10,11 @@
 #include "base/callback.h"
 #include "base/metrics/histogram_macros.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/google/google_brand.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
-#include "chrome/browser/profile_resetter/brandcode_config_fetcher.h"
 #include "chrome/browser/profile_resetter/brandcoded_default_settings.h"
 #include "chrome/browser/profile_resetter/resettable_settings_snapshot.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/safe_browsing/settings_reset_prompt/default_settings_fetcher.h"
 #include "chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
@@ -34,10 +33,6 @@
 
 namespace {
 
-#if defined(GOOGLE_CHROME_BUILD)
-constexpr char kOmahaUrl[] = "https://tools.google.com/service/update2";
-#endif  // defined(GOOGLE_CHROME_BUILD)
-
 // These values are used for UMA metrics reporting. New enum values can be
 // added, but existing enums must never be renumbered or deleted and reused.
 enum SettingsReset {
@@ -57,103 +52,6 @@
                       SETTINGS_TYPE_STARTUP_URLS,
 };
 
-// A helper class that fetches default settings to be used for the settings
-// reset prompt. The static |FetchDefaultSettings()| function will create and
-// manage the lifetime of |DefaultSettingsFetcher| instances.
-class DefaultSettingsFetcher {
- public:
-  using SettingsCallback =
-      base::Callback<void(std::unique_ptr<BrandcodedDefaultSettings>)>;
-
-  // Fetches default settings and passes the corresponding
-  // |BrandcodedDefaultSettings| object to |callback| on the UI thread. The
-  // function should be called on the UI thread as well.
-  static void FetchDefaultSettings(SettingsCallback callback);
-
- private:
-  // Instances of |DefaultSettingsFetcher| own themselves and will delete
-  // themselves once default settings have been fetched and |callback| has been
-  // posted on the UI thread.
-  //
-  // The main reason for this design is that |BrandcodeConfigFetcher| takes a
-  // callback and initiates the fetching process in its constructor, and we need
-  // to hold on to the instance of the fetcher until settings have been
-  // fetched. This design saves us from having to explicitly manage global
-  // |BrandcodeConfigFetcher| instances.
-  explicit DefaultSettingsFetcher(SettingsCallback callback);
-  ~DefaultSettingsFetcher();
-
-  // Starts the process of fetching default settings and will ensure that
-  // |PostCallbackAndDeleteSelf| is called once settings have been fetched.
-  void Start();
-  void OnSettingsFetched();
-  // Posts a call to |callback_| on the UI thread, passing to it
-  // |default_settings|, and deletes |this|.
-  void PostCallbackAndDeleteSelf(
-      std::unique_ptr<BrandcodedDefaultSettings> default_settings);
-
-  std::unique_ptr<BrandcodeConfigFetcher> config_fetcher_;
-  SettingsCallback callback_;
-};
-
-// static
-void DefaultSettingsFetcher::FetchDefaultSettings(SettingsCallback callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-  // |settings_fetcher| will delete itself when default settings have been
-  // fetched after the call to |Start()|.
-  DefaultSettingsFetcher* settings_fetcher =
-      new DefaultSettingsFetcher(std::move(callback));
-  settings_fetcher->Start();
-}
-
-DefaultSettingsFetcher::DefaultSettingsFetcher(SettingsCallback callback)
-    : callback_(std::move(callback)) {}
-
-DefaultSettingsFetcher::~DefaultSettingsFetcher() {}
-
-void DefaultSettingsFetcher::Start() {
-  DCHECK(!config_fetcher_);
-
-#if defined(GOOGLE_CHROME_BUILD)
-  std::string brandcode;
-  if (google_brand::GetBrand(&brandcode) && !brandcode.empty()) {
-    config_fetcher_.reset(new BrandcodeConfigFetcher(
-        base::Bind(&DefaultSettingsFetcher::OnSettingsFetched,
-                   base::Unretained(this)),
-        GURL(kOmahaUrl), brandcode));
-    return;
-  }
-#endif  // defined(GOOGLE_CHROME_BUILD)
-
-  // For non Google Chrome builds and cases with an empty |brandcode|, we create
-  // a default-constructed |BrandcodedDefaultSettings| object and post the
-  // callback immediately.
-  PostCallbackAndDeleteSelf(base::MakeUnique<BrandcodedDefaultSettings>());
-}
-
-void DefaultSettingsFetcher::OnSettingsFetched() {
-  DCHECK(config_fetcher_);
-  DCHECK(!config_fetcher_->IsActive());
-
-  std::unique_ptr<BrandcodedDefaultSettings> settings(
-      config_fetcher_->GetSettings());
-  // Use default settings if fetching of BrandcodedDefaultSettings fails.
-  if (!settings)
-    settings.reset(new BrandcodedDefaultSettings());
-
-  PostCallbackAndDeleteSelf(std::move(settings));
-}
-
-void DefaultSettingsFetcher::PostCallbackAndDeleteSelf(
-    std::unique_ptr<BrandcodedDefaultSettings> default_settings) {
-  DCHECK(default_settings);
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::BindOnce(std::move(callback_), base::Passed(&default_settings)));
-  delete this;
-}
-
 const extensions::Extension* GetExtension(
     Profile* profile,
     const extensions::ExtensionId& extension_id) {