// Copyright (c) 2011 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.
//
// This test creates a safebrowsing service using test safebrowsing database
// and a test protocol manager. It is used to test logics in safebrowsing
// service.

#include "base/command_line.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram.h"
#include "crypto/sha2.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/safe_browsing/safe_browsing_database.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/safe_browsing/safe_browsing_util.h"
#include "chrome/browser/safe_browsing/protocol_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "content/browser/browser_thread.h"
#include "content/browser/renderer_host/resource_dispatcher_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/tab_contents/tab_contents_view.h"

using base::Histogram;
using base::StatisticsRecorder;

// A SafeBrowingDatabase class that allows us to inject the malicious URLs.
class TestSafeBrowsingDatabase :  public SafeBrowsingDatabase {
 public:
  TestSafeBrowsingDatabase() {}

  virtual ~TestSafeBrowsingDatabase() {}

  // Initializes the database with the given filename.
  virtual void Init(const FilePath& filename) {}

  // Deletes the current database and creates a new one.
  virtual bool ResetDatabase() {
    badurls_.clear();
    return true;
  }

  // Called on the IO thread to check if the given URL is safe or not.  If we
  // can synchronously determine that the URL is safe, CheckUrl returns true,
  // otherwise it returns false.
  virtual bool ContainsBrowseUrl(const GURL& url,
                                 std::string* matching_list,
                                 std::vector<SBPrefix>* prefix_hits,
                                 std::vector<SBFullHashResult>* full_hits,
                                 base::Time last_update) {
    std::vector<GURL> urls(1, url);
    return ContainsUrl(safe_browsing_util::kMalwareList,
                       safe_browsing_util::kPhishingList,
                       urls, prefix_hits, full_hits);
  }
  virtual bool ContainsDownloadUrl(const std::vector<GURL>& urls,
                                   std::vector<SBPrefix>* prefix_hits) {
    std::vector<SBFullHashResult> full_hits;
    bool found = ContainsUrl(safe_browsing_util::kBinUrlList,
                             safe_browsing_util::kBinHashList,
                             urls, prefix_hits, &full_hits);
    if (!found)
      return false;
    DCHECK_LE(1U, prefix_hits->size());
    return true;
  }
  virtual bool ContainsDownloadHashPrefix(const SBPrefix& prefix) {
    return download_digest_prefix_.count(prefix) > 0;
  }
  virtual bool ContainsCsdWhitelistedUrl(const GURL& url) {
    return true;
  }
  virtual bool UpdateStarted(std::vector<SBListChunkRanges>* lists) {
    ADD_FAILURE() << "Not implemented.";
    return false;
  }
  virtual void InsertChunks(const std::string& list_name,
                            const SBChunkList& chunks) {
    ADD_FAILURE() << "Not implemented.";
  }
  virtual void DeleteChunks(const std::vector<SBChunkDelete>& chunk_deletes) {
    ADD_FAILURE() << "Not implemented.";
  }
  virtual void UpdateFinished(bool update_succeeded) {
    ADD_FAILURE() << "Not implemented.";
  }
  virtual void CacheHashResults(const std::vector<SBPrefix>& prefixes,
      const std::vector<SBFullHashResult>& full_hits) {
    // Do nothing for the cache.
    return;
  }

  // Fill up the database with test URL.
  void AddUrl(const GURL& url,
              const std::string& list_name,
              const std::vector<SBPrefix>& prefix_hits,
              const std::vector<SBFullHashResult>& full_hits) {
    badurls_[url.spec()].list_name = list_name;
    badurls_[url.spec()].prefix_hits = prefix_hits;
    badurls_[url.spec()].full_hits = full_hits;
  }

  // Fill up the database with test hash digest.
  void AddDownloadPrefix(SBPrefix prefix) {
    download_digest_prefix_.insert(prefix);
  }

 private:
  struct Hits {
    std::string list_name;
    std::vector<SBPrefix> prefix_hits;
    std::vector<SBFullHashResult> full_hits;
  };

  bool ContainsUrl(const std::string& list_name0,
                   const std::string& list_name1,
                   const std::vector<GURL>& urls,
                   std::vector<SBPrefix>* prefix_hits,
                   std::vector<SBFullHashResult>* full_hits) {
    bool hit = false;
    for (size_t i = 0; i < urls.size(); ++i) {
      const GURL& url = urls[i];
      base::hash_map<std::string, Hits>::const_iterator
          badurls_it = badurls_.find(url.spec());

      if (badurls_it == badurls_.end())
        continue;

      if (badurls_it->second.list_name == list_name0 ||
          badurls_it->second.list_name == list_name1) {
        prefix_hits->insert(prefix_hits->end(),
                            badurls_it->second.prefix_hits.begin(),
                            badurls_it->second.prefix_hits.end());
        full_hits->insert(full_hits->end(),
                          badurls_it->second.full_hits.begin(),
                          badurls_it->second.full_hits.end());
        hit = true;
      }

    }
    return hit;
  }

  base::hash_map<std::string, Hits> badurls_;
  base::hash_set<SBPrefix> download_digest_prefix_;
};

// Factory that creates TestSafeBrowsingDatabase instances.
class TestSafeBrowsingDatabaseFactory : public SafeBrowsingDatabaseFactory {
 public:
  TestSafeBrowsingDatabaseFactory() : db_(NULL) {}
  virtual ~TestSafeBrowsingDatabaseFactory() {}

  virtual SafeBrowsingDatabase* CreateSafeBrowsingDatabase(
      bool enable_download_protection,
      bool enable_client_side_whitelist) {
    db_ = new TestSafeBrowsingDatabase();
    return db_;
  }
  TestSafeBrowsingDatabase* GetDb() {
    return db_;
  }
 private:
  // Owned by the SafebrowsingService.
  TestSafeBrowsingDatabase* db_;
};

// A TestProtocolManager that could return fixed responses from
// safebrowsing server for testing purpose.
class TestProtocolManager :  public SafeBrowsingProtocolManager {
 public:
  TestProtocolManager(SafeBrowsingService* sb_service,
                      const std::string& client_name,
                      const std::string& client_key,
                      const std::string& wrapped_key,
                      net::URLRequestContextGetter* request_context_getter,
                      const std::string& info_url_prefix,
                      const std::string& mackey_url_prefix,
                      bool disable_auto_update)
      : SafeBrowsingProtocolManager(sb_service, client_name, client_key,
                                    wrapped_key, request_context_getter,
                                    info_url_prefix, mackey_url_prefix,
                                    disable_auto_update),
        sb_service_(sb_service),
        delay_ms_(0) {
  }

  // This function is called when there is a prefix hit in local safebrowsing
  // database and safebrowsing service issues a get hash request to backends.
  // We return a result from the prefilled full_hashes_ hash_map to simulate
  // server's response. At the same time, latency is added to simulate real
  // life network issues.
  virtual void GetFullHash(SafeBrowsingService::SafeBrowsingCheck* check,
                           const std::vector<SBPrefix>& prefixes) {
    // When we get a valid response, always cache the result.
    bool cancache = true;
    BrowserThread::PostDelayedTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableMethod(
            sb_service_, &SafeBrowsingService::HandleGetHashResults,
            check, full_hashes_, cancache),
        delay_ms_);
  }

  // Prepare the GetFullHash results for the next request.
  void SetGetFullHashResponse(const SBFullHashResult& full_hash_result) {
    full_hashes_.clear();
    full_hashes_.push_back(full_hash_result);
  }

  void IntroduceDelay(int64 ms) {
    delay_ms_ = ms;
  }

 private:
  std::vector<SBFullHashResult> full_hashes_;
  SafeBrowsingService* sb_service_;
  int64 delay_ms_;
};

// Factory that creates TestProtocolManager instances.
class TestSBProtocolManagerFactory : public SBProtocolManagerFactory {
 public:
  TestSBProtocolManagerFactory() : pm_(NULL) {}
  virtual ~TestSBProtocolManagerFactory() {}

  virtual SafeBrowsingProtocolManager* CreateProtocolManager(
      SafeBrowsingService* sb_service,
      const std::string& client_name,
      const std::string& client_key,
      const std::string& wrapped_key,
      net::URLRequestContextGetter* request_context_getter,
      const std::string& info_url_prefix,
      const std::string& mackey_url_prefix,
      bool disable_auto_update) {
    pm_ = new TestProtocolManager(
        sb_service, client_name, client_key, wrapped_key,
        request_context_getter, info_url_prefix, mackey_url_prefix,
        disable_auto_update);
    return pm_;
  }
  TestProtocolManager* GetProtocolManager() {
    return pm_;
  }
 private:
  // Owned by the SafebrowsingService.
  TestProtocolManager* pm_;
};

// Tests the safe browsing blocking page in a browser.
class SafeBrowsingServiceTest : public InProcessBrowserTest {
 public:
  SafeBrowsingServiceTest() {
  }

  static void GenUrlFullhashResult(const GURL& url,
                                   const std::string& list_name,
                                   int add_chunk_id,
                                   SBFullHashResult* full_hash) {
    std::string host;
    std::string path;
    safe_browsing_util::CanonicalizeUrl(url, &host, &path, NULL);
    crypto::SHA256HashString(host + path, &full_hash->hash,
                             sizeof(SBFullHash));
    full_hash->list_name = list_name;
    full_hash->add_chunk_id = add_chunk_id;
  }

  static void GenDigestFullhashResult(const std::string& full_digest,
                                      const std::string& list_name,
                                      int add_chunk_id,
                                      SBFullHashResult* full_hash) {
    safe_browsing_util::StringToSBFullHash(full_digest, &full_hash->hash);
    full_hash->list_name = list_name;
    full_hash->add_chunk_id = add_chunk_id;
  }

  virtual void SetUp() {
    // InProcessBrowserTest::SetUp() intantiates SafebrowsingService and
    // RegisterFactory has to be called before SafeBrowsingService is created.
    SafeBrowsingDatabase::RegisterFactory(&db_factory_);
    SafeBrowsingProtocolManager::RegisterFactory(&pm_factory_);
    InProcessBrowserTest::SetUp();
  }

  virtual void TearDown() {
    InProcessBrowserTest::TearDown();

    // Unregister test factories after InProcessBrowserTest::TearDown
    // (which destructs SafeBrowsingService).
    SafeBrowsingDatabase::RegisterFactory(NULL);
    SafeBrowsingProtocolManager::RegisterFactory(NULL);
  }

  virtual void SetUpCommandLine(CommandLine* command_line) {
    // Makes sure the auto update is not triggered during the test.
    // This test will fill up the database using testing prefixes
    // and urls.
    command_line->AppendSwitch(switches::kSbDisableAutoUpdate);
  }

  virtual void SetUpInProcessBrowserTestFixture() {
    ASSERT_TRUE(test_server()->Start());
  }

  // This will setup the "url" prefix in database and prepare protocol manager
  // to response with |full_hash| for get full hash request.
  void SetupResponseForUrl(const GURL& url, const SBFullHashResult& full_hash) {
    std::vector<SBPrefix> prefix_hits;
    prefix_hits.push_back(full_hash.hash.prefix);

    // Make sure the full hits is empty unless we need to test the
    // full hash is hit in database's local cache.
    std::vector<SBFullHashResult> empty_full_hits;
    TestSafeBrowsingDatabase* db = db_factory_.GetDb();
    db->AddUrl(url, full_hash.list_name, prefix_hits, empty_full_hits);

    TestProtocolManager* pm = pm_factory_.GetProtocolManager();
    pm->SetGetFullHashResponse(full_hash);
  }

  // This will setup the binary digest prefix in database and prepare protocol
  // manager to response with |full_hash| for get full hash request.
  void SetupResponseForDigest(const std::string& digest,
                              const SBFullHashResult& hash_result) {
    TestSafeBrowsingDatabase* db = db_factory_.GetDb();
    SBFullHash full_hash;
    safe_browsing_util::StringToSBFullHash(digest, &full_hash);
    db->AddDownloadPrefix(full_hash.prefix);

    TestProtocolManager* pm = pm_factory_.GetProtocolManager();
    pm->SetGetFullHashResponse(hash_result);
  }

  bool ShowingInterstitialPage() {
    TabContents* contents = browser()->GetSelectedTabContents();
    InterstitialPage* interstitial_page = contents->interstitial_page();
    return interstitial_page != NULL;
  }

  void IntroduceGetHashDelay(int64 ms) {
    pm_factory_.GetProtocolManager()->IntroduceDelay(ms);
  }

  int64 DownloadUrlCheckTimeout(SafeBrowsingService* sb_service) {
    return sb_service->download_urlcheck_timeout_ms_;
  }

  int64 DownloadHashCheckTimeout(SafeBrowsingService* sb_service) {
    return sb_service->download_hashcheck_timeout_ms_;
  }

  void SetDownloadUrlCheckTimeout(SafeBrowsingService* sb_service, int64 ms) {
    sb_service->download_urlcheck_timeout_ms_ = ms;
  }

  void SetDownloadHashCheckTimeout(SafeBrowsingService* sb_service, int64 ms) {
    sb_service->download_hashcheck_timeout_ms_ = ms;
  }

 private:
  TestSafeBrowsingDatabaseFactory db_factory_;
  TestSBProtocolManagerFactory pm_factory_;

  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceTest);
};

namespace {

const char kEmptyPage[] = "files/empty.html";
const char kMalwareFile[] = "files/downloads/dangerous/dangerous.exe";
const char kMalwareIframe[] = "files/safe_browsing/malware_iframe.html";
const char kMalwarePage[] = "files/safe_browsing/malware.html";

// This test goes through DownloadResourceHandler.
IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, Malware) {
  GURL url = test_server()->GetURL(kEmptyPage);

  // After adding the url to safebrowsing database and getfullhash result,
  // we should see the interstitial page.
  SBFullHashResult malware_full_hash;
  int chunk_id = 0;
  GenUrlFullhashResult(url, safe_browsing_util::kMalwareList, chunk_id,
                       &malware_full_hash);
  SetupResponseForUrl(url, malware_full_hash);
  ui_test_utils::NavigateToURL(browser(), url);
  EXPECT_TRUE(ShowingInterstitialPage());
}

const char kPrefetchMalwarePage[] = "files/safe_browsing/prefetch_malware.html";

// This test confirms that prefetches don't themselves get the
// interstitial treatment.
IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, Prefetch) {
  GURL url = test_server()->GetURL(kPrefetchMalwarePage);
  GURL malware_url = test_server()->GetURL(kMalwarePage);

  class SetPrefetchForTest {
   public:
    explicit SetPrefetchForTest(bool prefetch)
        : old_prefetch_state_(ResourceDispatcherHost::is_prefetch_enabled()) {
      ResourceDispatcherHost::set_is_prefetch_enabled(prefetch);
    }

    ~SetPrefetchForTest() {
      ResourceDispatcherHost::set_is_prefetch_enabled(old_prefetch_state_);
    }
   private:
    bool old_prefetch_state_;
  } set_prefetch_for_test(true);

  // Even though we have added this uri to the safebrowsing database and
  // getfullhash result, we should not see the interstitial page since the
  // only malware was a prefetch target.
  SBFullHashResult malware_full_hash;
  int chunk_id = 0;
  GenUrlFullhashResult(malware_url, safe_browsing_util::kMalwareList,
                       chunk_id, &malware_full_hash);
  SetupResponseForUrl(malware_url, malware_full_hash);
  ui_test_utils::NavigateToURL(browser(), url);
  EXPECT_FALSE(ShowingInterstitialPage());

  // However, when we navigate to the malware page, we should still get
  // the interstitial.
  ui_test_utils::NavigateToURL(browser(), malware_url);
  EXPECT_TRUE(ShowingInterstitialPage());
}

}  // namespace

class TestSBClient
    : public base::RefCountedThreadSafe<TestSBClient>,
      public SafeBrowsingService::Client {
 public:
  TestSBClient() : result_(SafeBrowsingService::SAFE),
                   safe_browsing_service_(g_browser_process->
                                          resource_dispatcher_host()->
                                          safe_browsing_service()) {
  }

  int GetResult() {
    return result_;
  }

  void CheckDownloadUrl(const std::vector<GURL>& url_chain) {
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableMethod(this,
                          &TestSBClient::CheckDownloadUrlOnIOThread,
                          url_chain));
    ui_test_utils::RunMessageLoop();  // Will stop in OnDownloadUrlCheckResult.
  }

  void CheckDownloadHash(const std::string& full_hash) {
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        NewRunnableMethod(this,
                          &TestSBClient::CheckDownloadHashOnIOThread,
                          full_hash));
    ui_test_utils::RunMessageLoop();  // Will stop in OnDownloadHashCheckResult.
  }

 private:
  void CheckDownloadUrlOnIOThread(const std::vector<GURL>& url_chain) {
    safe_browsing_service_->CheckDownloadUrl(url_chain, this);
  }

  void CheckDownloadHashOnIOThread(const std::string& full_hash) {
    safe_browsing_service_->CheckDownloadHash(full_hash, this);
  }

  // Called when the result of checking a download URL is known.
  void OnDownloadUrlCheckResult(const std::vector<GURL>& url_chain,
                                SafeBrowsingService::UrlCheckResult result) {
    result_ = result;
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
      NewRunnableMethod(this, &TestSBClient::DownloadCheckDone));
  }

  // Called when the result of checking a download hash is known.
  void OnDownloadHashCheckResult(const std::string& hash,
                                 SafeBrowsingService::UrlCheckResult result) {
    result_ = result;
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
      NewRunnableMethod(this, &TestSBClient::DownloadCheckDone));
  }

  void DownloadCheckDone() {
    MessageLoopForUI::current()->Quit();
  }

  SafeBrowsingService::UrlCheckResult result_;
  SafeBrowsingService* safe_browsing_service_;

  DISALLOW_COPY_AND_ASSIGN(TestSBClient);
};

// These tests use SafeBrowsingService::Client to directly interact with
// SafeBrowsingService.
namespace {

IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadUrl) {
  GURL badbin_url = test_server()->GetURL(kMalwareFile);
  std::vector<GURL> badbin_urls(1, badbin_url);

  scoped_refptr<TestSBClient> client(new TestSBClient);
  client->CheckDownloadUrl(badbin_urls);

  // Since badbin_url is not in database, it is considered to be safe.
  EXPECT_EQ(SafeBrowsingService::SAFE, client->GetResult());

  SBFullHashResult full_hash_result;
  int chunk_id = 0;
  GenUrlFullhashResult(badbin_url, safe_browsing_util::kBinUrlList,
                       chunk_id, &full_hash_result);
  SetupResponseForUrl(badbin_url, full_hash_result);

  client->CheckDownloadUrl(badbin_urls);

  // Now, the badbin_url is not safe since it is added to download database.
  EXPECT_EQ(SafeBrowsingService::BINARY_MALWARE_URL, client->GetResult());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadUrlRedirects) {
  GURL original_url = test_server()->GetURL(kEmptyPage);
  GURL badbin_url = test_server()->GetURL(kMalwareFile);
  GURL final_url = test_server()->GetURL(kEmptyPage);
  std::vector<GURL> badbin_urls;
  badbin_urls.push_back(original_url);
  badbin_urls.push_back(badbin_url);
  badbin_urls.push_back(final_url);

  scoped_refptr<TestSBClient> client(new TestSBClient);
  client->CheckDownloadUrl(badbin_urls);

  // Since badbin_url is not in database, it is considered to be safe.
  EXPECT_EQ(SafeBrowsingService::SAFE, client->GetResult());

  SBFullHashResult full_hash_result;
  int chunk_id = 0;
  GenUrlFullhashResult(badbin_url, safe_browsing_util::kBinUrlList,
                       chunk_id, &full_hash_result);
  SetupResponseForUrl(badbin_url, full_hash_result);

  client->CheckDownloadUrl(badbin_urls);

  // Now, the badbin_url is not safe since it is added to download database.
  EXPECT_EQ(SafeBrowsingService::BINARY_MALWARE_URL, client->GetResult());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadHash) {
  const std::string full_hash = "12345678902234567890323456789012";

  scoped_refptr<TestSBClient> client(new TestSBClient);
  client->CheckDownloadHash(full_hash);

  // Since badbin_url is not in database, it is considered to be safe.
  EXPECT_EQ(SafeBrowsingService::SAFE, client->GetResult());

  SBFullHashResult full_hash_result;
  int chunk_id = 0;
  GenDigestFullhashResult(full_hash, safe_browsing_util::kBinHashList,
                          chunk_id, &full_hash_result);
  SetupResponseForDigest(full_hash, full_hash_result);

  client->CheckDownloadHash(full_hash);

  // Now, the badbin_url is not safe since it is added to download database.
  EXPECT_EQ(SafeBrowsingService::BINARY_MALWARE_HASH, client->GetResult());
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadUrlTimedOut) {
  GURL badbin_url = test_server()->GetURL(kMalwareFile);
  std::vector<GURL> badbin_urls(1, badbin_url);

  scoped_refptr<TestSBClient> client(new TestSBClient);
  SBFullHashResult full_hash_result;
  int chunk_id = 0;
  GenUrlFullhashResult(badbin_url, safe_browsing_util::kBinUrlList,
                       chunk_id, &full_hash_result);
  SetupResponseForUrl(badbin_url, full_hash_result);
  client->CheckDownloadUrl(badbin_urls);

  // badbin_url is not safe since it is added to download database.
  EXPECT_EQ(SafeBrowsingService::BINARY_MALWARE_URL, client->GetResult());

  //
  // Now introducing delays and we should hit timeout.
  //
  SafeBrowsingService* sb_service =
      g_browser_process->resource_dispatcher_host()->safe_browsing_service();
  const int64 kOneSec = 1000;
  const int64 kOneMs = 1;
  int64 default_urlcheck_timeout = DownloadUrlCheckTimeout(sb_service);
  IntroduceGetHashDelay(kOneSec);
  SetDownloadUrlCheckTimeout(sb_service, kOneMs);
  client->CheckDownloadUrl(badbin_urls);

  // There should be a timeout and the hash would be considered as safe.
  EXPECT_EQ(SafeBrowsingService::SAFE, client->GetResult());

  // Need to set the timeout back to the default value.
  SetDownloadHashCheckTimeout(sb_service, default_urlcheck_timeout);
}

IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadHashTimedOut) {
  const std::string full_hash = "12345678902234567890323456789012";

  scoped_refptr<TestSBClient> client(new TestSBClient);
  SBFullHashResult full_hash_result;
  int chunk_id = 0;
  GenDigestFullhashResult(full_hash, safe_browsing_util::kBinHashList,
                          chunk_id, &full_hash_result);
  SetupResponseForDigest(full_hash, full_hash_result);
  client->CheckDownloadHash(full_hash);

  // The badbin_url is not safe since it is added to download database.
  EXPECT_EQ(SafeBrowsingService::BINARY_MALWARE_HASH, client->GetResult());

  //
  // Now introducing delays and we should hit timeout.
  //
  SafeBrowsingService* sb_service =
      g_browser_process->resource_dispatcher_host()->safe_browsing_service();
  const int64 kOneSec = 1000;
  const int64 kOneMs = 1;
  int64 default_hashcheck_timeout = DownloadHashCheckTimeout(sb_service);
  IntroduceGetHashDelay(kOneSec);
  SetDownloadHashCheckTimeout(sb_service, kOneMs);
  client->CheckDownloadHash(full_hash);

  // There should be a timeout and the hash would be considered as safe.
  EXPECT_EQ(SafeBrowsingService::SAFE, client->GetResult());

  // Need to set the timeout back to the default value.
  SetDownloadHashCheckTimeout(sb_service, default_hashcheck_timeout);
}

}  // namespace