| Index: chrome/browser/safe_browsing/last_download_finder_unittest.cc
|
| diff --git a/chrome/browser/safe_browsing/last_download_finder_unittest.cc b/chrome/browser/safe_browsing/last_download_finder_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..eedacb68d8e7c4d180f5db34326d67fe92babb30
|
| --- /dev/null
|
| +++ b/chrome/browser/safe_browsing/last_download_finder_unittest.cc
|
| @@ -0,0 +1,331 @@
|
| +// Copyright 2014 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/last_download_finder.h"
|
| +
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/callback.h"
|
| +#include "base/file_util.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "chrome/browser/history/chrome_history_client.h"
|
| +#include "chrome/browser/history/chrome_history_client_factory.h"
|
| +#include "chrome/browser/history/download_row.h"
|
| +#include "chrome/browser/history/history_service.h"
|
| +#include "chrome/browser/history/history_service_factory.h"
|
| +#include "chrome/browser/history/web_history_service_factory.h"
|
| +#include "chrome/browser/prefs/browser_prefs.h"
|
| +#include "chrome/browser/profiles/profile_manager.h"
|
| +#include "chrome/common/chrome_constants.h"
|
| +#include "chrome/common/pref_names.h"
|
| +#include "chrome/common/safe_browsing/csd.pb.h"
|
| +#include "chrome/test/base/testing_browser_process.h"
|
| +#include "chrome/test/base/testing_pref_service_syncable.h"
|
| +#include "chrome/test/base/testing_profile.h"
|
| +#include "chrome/test/base/testing_profile_manager.h"
|
| +#include "content/public/test/test_browser_thread_bundle.h"
|
| +#include "content/public/test/test_utils.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace {
|
| +
|
| +// A BrowserContextKeyedServiceFactory::TestingFactoryFunction that creates a
|
| +// HistoryService for a TestingProfile.
|
| +KeyedService* BuildHistoryService(content::BrowserContext* context) {
|
| + TestingProfile* profile = static_cast<TestingProfile*>(context);
|
| +
|
| + // Delete the file before creating the service.
|
| + base::FilePath history_path(
|
| + profile->GetPath().Append(chrome::kHistoryFilename));
|
| + if (!base::DeleteFile(history_path, false) ||
|
| + base::PathExists(history_path)) {
|
| + ADD_FAILURE() << "failed to delete history db file "
|
| + << history_path.value();
|
| + return NULL;
|
| + }
|
| +
|
| + HistoryService* history_service = new HistoryService(
|
| + ChromeHistoryClientFactory::GetForProfile(profile), profile);
|
| + if (history_service->Init(profile->GetPath()))
|
| + return history_service;
|
| +
|
| + ADD_FAILURE() << "failed to initialize history service";
|
| + delete history_service;
|
| + return NULL;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class LastDownloadFinderTest : public testing::Test {
|
| + public:
|
| + void NeverCalled(scoped_ptr<
|
| + safe_browsing::ClientIncidentReport_DownloadDetails> download) {
|
| + FAIL();
|
| + }
|
| +
|
| + // Creates a new profile that participates in safe browsing and adds a
|
| + // download to its history.
|
| + void CreateProfileWithDownload() {
|
| + TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_IN);
|
| + HistoryService* history_service =
|
| + HistoryServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS);
|
| + history_service->CreateDownload(
|
| + CreateTestDownloadRow(),
|
| + base::Bind(&LastDownloadFinderTest::OnDownloadCreated,
|
| + base::Unretained(this)));
|
| + }
|
| +
|
| + // safe_browsing::LastDownloadFinder::LastDownloadCallback implementation that
|
| + // passes the found download to |result| and then runs a closure.
|
| + void OnLastDownload(
|
| + scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails>* result,
|
| + const base::Closure& quit_closure,
|
| + scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails>
|
| + download) {
|
| + *result = download.Pass();
|
| + quit_closure.Run();
|
| + }
|
| +
|
| + protected:
|
| + // A type for specifying whether or not a profile created by CreateProfile
|
| + // participates in safe browsing.
|
| + enum SafeBrowsingDisposition {
|
| + SAFE_BROWSING_OPT_OUT,
|
| + SAFE_BROWSING_OPT_IN,
|
| + };
|
| +
|
| + LastDownloadFinderTest() : profile_number_() {}
|
| +
|
| + virtual void SetUp() OVERRIDE {
|
| + testing::Test::SetUp();
|
| + profile_manager_.reset(
|
| + new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
|
| + ASSERT_TRUE(profile_manager_->SetUp());
|
| + }
|
| +
|
| + virtual void TearDown() OVERRIDE {
|
| + // Shut down the history service on all profiles.
|
| + std::vector<Profile*> profiles(
|
| + profile_manager_->profile_manager()->GetLoadedProfiles());
|
| + for (size_t i = 0; i < profiles.size(); ++i) {
|
| + profiles[0]->AsTestingProfile()->DestroyHistoryService();
|
| + }
|
| + profile_manager_.reset();
|
| + TestingBrowserProcess::DeleteInstance();
|
| + testing::Test::TearDown();
|
| + }
|
| +
|
| + TestingProfile* CreateProfile(SafeBrowsingDisposition safe_browsing_opt_in) {
|
| + std::string profile_name("profile");
|
| + profile_name.append(base::IntToString(++profile_number_));
|
| +
|
| + // Set up keyed service factories.
|
| + TestingProfile::TestingFactories factories;
|
| + // Build up a custom history service.
|
| + factories.push_back(std::make_pair(HistoryServiceFactory::GetInstance(),
|
| + &BuildHistoryService));
|
| + // Suppress WebHistoryService since it makes network requests.
|
| + factories.push_back(std::make_pair(
|
| + WebHistoryServiceFactory::GetInstance(),
|
| + static_cast<BrowserContextKeyedServiceFactory::TestingFactoryFunction>(
|
| + NULL)));
|
| +
|
| + // Create prefs for the profile with safe browsing enabled or not.
|
| + scoped_ptr<TestingPrefServiceSyncable> prefs(
|
| + new TestingPrefServiceSyncable);
|
| + chrome::RegisterUserProfilePrefs(prefs->registry());
|
| + prefs->SetBoolean(prefs::kSafeBrowsingEnabled,
|
| + safe_browsing_opt_in == SAFE_BROWSING_OPT_IN);
|
| +
|
| + TestingProfile* profile = profile_manager_->CreateTestingProfile(
|
| + profile_name,
|
| + prefs.PassAs<PrefServiceSyncable>(),
|
| + base::UTF8ToUTF16(profile_name), // user_name
|
| + 0, // avatar_id
|
| + std::string(), // supervised_user_id
|
| + factories);
|
| +
|
| + return profile;
|
| + }
|
| +
|
| + void AddDownload(Profile* profile, const history::DownloadRow& download) {
|
| + base::RunLoop run_loop;
|
| +
|
| + HistoryService* history_service =
|
| + HistoryServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS);
|
| + history_service->CreateDownload(
|
| + download,
|
| + base::Bind(&LastDownloadFinderTest::ContinueOnDownloadCreated,
|
| + base::Unretained(this),
|
| + run_loop.QuitClosure()));
|
| + run_loop.Run();
|
| + }
|
| +
|
| + // Wait for the history backend thread to process any outstanding tasks.
|
| + // This is needed because HistoryService::QueryDownloads uses PostTaskAndReply
|
| + // to do work on the backend thread and then invoke the caller's callback on
|
| + // the originating thread. The PostTaskAndReplyRelay holds a reference to the
|
| + // backend until its RunReplyAndSelfDestruct is called on the originating
|
| + // thread. This reference MUST be released (on the originating thread,
|
| + // remember) _before_ calling DestroyHistoryService in TearDown(). See the
|
| + // giant comment in HistoryService::Cleanup explaining where the backend's
|
| + // dtor must be run.
|
| + void FlushHistoryBackend(Profile* profile) {
|
| + base::RunLoop run_loop;
|
| + HistoryServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS)
|
| + ->FlushForTest(run_loop.QuitClosure());
|
| + run_loop.Run();
|
| + // Then make sure anything bounced back to the main thread has been handled.
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + // Runs the last download finder on all loaded profiles, returning the found
|
| + // download or an empty pointer if none was found.
|
| + scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails>
|
| + RunLastDownloadFinder() {
|
| + base::RunLoop run_loop;
|
| +
|
| + scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails>
|
| + last_download;
|
| +
|
| + scoped_ptr<safe_browsing::LastDownloadFinder> finder(
|
| + safe_browsing::LastDownloadFinder::Create(
|
| + base::Bind(&LastDownloadFinderTest::OnLastDownload,
|
| + base::Unretained(this),
|
| + &last_download,
|
| + run_loop.QuitClosure())));
|
| +
|
| + if (finder)
|
| + run_loop.Run();
|
| +
|
| + return last_download.Pass();
|
| + }
|
| +
|
| + history::DownloadRow CreateTestDownloadRow() {
|
| + base::Time now(base::Time::Now());
|
| + return history::DownloadRow(
|
| + base::FilePath(FILE_PATH_LITERAL("spam.exe")),
|
| + base::FilePath(FILE_PATH_LITERAL("spam.exe")),
|
| + std::vector<GURL>(1, GURL("http://www.google.com")), // url_chain
|
| + GURL(), // referrer
|
| + "application/octet-stream", // mime_type
|
| + "application/octet-stream", // original_mime_type
|
| + now - base::TimeDelta::FromMinutes(10), // start
|
| + now - base::TimeDelta::FromMinutes(9), // end
|
| + std::string(), // etag
|
| + std::string(), // last_modified
|
| + 47LL, // received
|
| + 47LL, // total
|
| + content::DownloadItem::COMPLETE, // download_state
|
| + content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, // danger_type
|
| + content::DOWNLOAD_INTERRUPT_REASON_NONE, // interrupt_reason,
|
| + 1, // id
|
| + false, // download_opened
|
| + std::string(), // ext_id
|
| + std::string()); // ext_name
|
| + }
|
| +
|
| + void ExpectNoDownloadFound(scoped_ptr<
|
| + safe_browsing::ClientIncidentReport_DownloadDetails> download) {
|
| + EXPECT_FALSE(download);
|
| + }
|
| +
|
| + void ExpectFoundTestDownload(scoped_ptr<
|
| + safe_browsing::ClientIncidentReport_DownloadDetails> download) {
|
| + ASSERT_TRUE(download);
|
| + }
|
| +
|
| + content::TestBrowserThreadBundle browser_thread_bundle_;
|
| + scoped_ptr<TestingProfileManager> profile_manager_;
|
| +
|
| + private:
|
| + // A HistoryService::DownloadCreateCallback that asserts that the download was
|
| + // created and runs |closure|.
|
| + void ContinueOnDownloadCreated(const base::Closure& closure, bool created) {
|
| + ASSERT_TRUE(created);
|
| + closure.Run();
|
| + }
|
| +
|
| + // A HistoryService::DownloadCreateCallback that asserts that the download was
|
| + // created.
|
| + void OnDownloadCreated(bool created) { ASSERT_TRUE(created); }
|
| +
|
| + int profile_number_;
|
| +};
|
| +
|
| +// Tests that nothing happens if there are no profiles at all.
|
| +TEST_F(LastDownloadFinderTest, NoProfiles) {
|
| + ExpectNoDownloadFound(RunLastDownloadFinder());
|
| +}
|
| +
|
| +// Tests that nothing happens other than the callback being invoked if there are
|
| +// no profiles participating in safe browsing.
|
| +TEST_F(LastDownloadFinderTest, NoParticipatingProfiles) {
|
| + // Create a profile with a history service that is opted-out
|
| + TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_OUT);
|
| +
|
| + // Add a download.
|
| + AddDownload(profile, CreateTestDownloadRow());
|
| +
|
| + ExpectNoDownloadFound(RunLastDownloadFinder());
|
| +}
|
| +
|
| +// Tests that a download is found from a single profile.
|
| +TEST_F(LastDownloadFinderTest, SimpleEndToEnd) {
|
| + // Create a profile with a history service that is opted-in.
|
| + TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_IN);
|
| +
|
| + // Add a download.
|
| + AddDownload(profile, CreateTestDownloadRow());
|
| +
|
| + ExpectFoundTestDownload(RunLastDownloadFinder());
|
| +}
|
| +
|
| +// Tests that there is no crash if the finder is deleted before results arrive.
|
| +TEST_F(LastDownloadFinderTest, DeleteBeforeResults) {
|
| + // Create a profile with a history service that is opted-in.
|
| + TestingProfile* profile = CreateProfile(SAFE_BROWSING_OPT_IN);
|
| +
|
| + // Add a download.
|
| + AddDownload(profile, CreateTestDownloadRow());
|
| +
|
| + // Start a finder and kill it before the search completes.
|
| + safe_browsing::LastDownloadFinder::Create(
|
| + base::Bind(&LastDownloadFinderTest::NeverCalled, base::Unretained(this)))
|
| + .reset();
|
| +
|
| + // Flush tasks on the history backend thread.
|
| + FlushHistoryBackend(profile);
|
| +}
|
| +
|
| +// Tests that a download in profile added after the search is begun is found.
|
| +TEST_F(LastDownloadFinderTest, AddProfileAfterStarting) {
|
| + // Create a profile with a history service that is opted-in.
|
| + CreateProfile(SAFE_BROWSING_OPT_IN);
|
| +
|
| + scoped_ptr<safe_browsing::ClientIncidentReport_DownloadDetails> last_download;
|
| + base::RunLoop run_loop;
|
| +
|
| + // Post a task that will create a second profile once the main loop is run.
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&LastDownloadFinderTest::CreateProfileWithDownload,
|
| + base::Unretained(this)));
|
| +
|
| + // Create a finder that we expect will find a download in the second profile.
|
| + scoped_ptr<safe_browsing::LastDownloadFinder> finder(
|
| + safe_browsing::LastDownloadFinder::Create(
|
| + base::Bind(&LastDownloadFinderTest::OnLastDownload,
|
| + base::Unretained(this),
|
| + &last_download,
|
| + run_loop.QuitClosure())));
|
| +
|
| + run_loop.Run();
|
| +
|
| + ExpectFoundTestDownload(last_download.Pass());
|
| +}
|
|
|