Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4451)

Unified Diff: chrome/browser/safe_browsing/download_feedback_service_unittest.cc

Issue 15881012: Implement safebrowsing download feedback service, enabled for dev & canary only. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/safe_browsing/download_feedback_service_unittest.cc
diff --git a/chrome/browser/safe_browsing/download_feedback_service_unittest.cc b/chrome/browser/safe_browsing/download_feedback_service_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8f0a8743949322f593f76b7b695206cded0e0436
--- /dev/null
+++ b/chrome/browser/safe_browsing/download_feedback_service_unittest.cc
@@ -0,0 +1,374 @@
+// Copyright 2013 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/download_feedback_service.h"
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "chrome/browser/safe_browsing/download_feedback.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/mock_download_item.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::SaveArg;
+
+namespace safe_browsing {
+
+namespace {
+
+class FakeDownloadFeedback : public DownloadFeedback {
+ public:
+ FakeDownloadFeedback(net::URLRequestContextGetter* request_context_getter,
+ base::TaskRunner* file_task_runner,
+ const base::FilePath& file_path,
+ const std::string& ping_request,
+ const std::string& ping_response,
+ base::Closure deletion_callback)
+ : ping_request_(ping_request),
+ ping_response_(ping_response),
+ deletion_callback_(deletion_callback),
+ start_called_(false) {
+ }
+
+ virtual ~FakeDownloadFeedback() {
+ deletion_callback_.Run();
+ }
+
+ virtual void Start(const base::Closure& finish_callback) OVERRIDE {
+ start_called_ = true;
+ finish_callback_ = finish_callback;
+ }
+
+ virtual const std::string& GetPingRequestForTesting() const OVERRIDE {
+ return ping_request_;
+ }
+
+ virtual const std::string& GetPingResponseForTesting() const OVERRIDE {
+ return ping_response_;
+ }
+
+ base::Closure finish_callback() const {
+ return finish_callback_;
+ }
+
+ bool start_called() const {
+ return start_called_;
+ }
+
+ private:
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+ scoped_refptr<base::TaskRunner> file_task_runner_;
+ base::FilePath file_path_;
+ std::string ping_request_;
+ std::string ping_response_;
+
+ base::Closure finish_callback_;
+ base::Closure deletion_callback_;
+ bool start_called_;
+};
+
+class FakeDownloadFeedbackFactory : public DownloadFeedbackFactory {
+ public:
+ virtual ~FakeDownloadFeedbackFactory() {}
+
+ virtual DownloadFeedback* CreateDownloadFeedback(
+ net::URLRequestContextGetter* request_context_getter,
+ base::TaskRunner* file_task_runner,
+ const base::FilePath& file_path,
+ const std::string& ping_request,
+ const std::string& ping_response) OVERRIDE {
+ FakeDownloadFeedback* feedback = new FakeDownloadFeedback(
+ request_context_getter,
+ file_task_runner,
+ file_path,
+ ping_request,
+ ping_response,
+ base::Bind(&FakeDownloadFeedbackFactory::DownloadFeedbackDeleted,
+ base::Unretained(this),
+ feedbacks_.size()));
+ feedbacks_.push_back(feedback);
+ return feedback;
+ }
+
+ void DownloadFeedbackDeleted(size_t n) {
+ feedbacks_[n] = NULL;
+ }
+
+ FakeDownloadFeedback* feedback(size_t n) const {
+ return feedbacks_[n];
+ }
+
+ size_t num_feedbacks() const {
+ return feedbacks_.size();
+ }
+
+ private:
+ std::vector<FakeDownloadFeedback*> feedbacks_;
+};
+
+bool WillStorePings(DownloadProtectionService::DownloadCheckResult result,
+ int64 size) {
+ content::MockDownloadItem item;
+ EXPECT_CALL(item, GetReceivedBytes()).WillRepeatedly(Return(size));
+
+ EXPECT_FALSE(DownloadFeedbackService::IsEnabledForDownload(item));
+ DownloadFeedbackService::MaybeStorePingsForDownload(result, &item, "a", "b");
+ return DownloadFeedbackService::IsEnabledForDownload(item);
+}
+
+} // namespace
+
+class DownloadFeedbackServiceTest : public testing::Test {
+ public:
+ DownloadFeedbackServiceTest()
+ : file_task_runner_(content::BrowserThread::GetMessageLoopProxyForThread(
+ content::BrowserThread::FILE)),
+ io_task_runner_(content::BrowserThread::GetMessageLoopProxyForThread(
+ content::BrowserThread::IO)),
+ request_context_getter_(
+ new net::TestURLRequestContextGetter(io_task_runner_)) {
+ }
+
+ virtual void SetUp() OVERRIDE {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kSbEnableDownloadFeedback);
+ DownloadFeedback::RegisterFactory(&download_feedback_factory_);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ DownloadFeedback::RegisterFactory(NULL);
+ }
+
+ base::FilePath CreateTestFile(int n) const {
+ base::FilePath upload_file_path(
+ temp_dir_.path().AppendASCII("test file " + base::IntToString(n)));
+ const std::string upload_file_data = "data";
+ int wrote = file_util::WriteFile(
+ upload_file_path, upload_file_data.data(), upload_file_data.size());
+ EXPECT_EQ(static_cast<int>(upload_file_data.size()), wrote);
+ return upload_file_path;
+ }
+
+ FakeDownloadFeedback* feedback(size_t n) const {
+ return download_feedback_factory_.feedback(n);
+ }
+
+ size_t num_feedbacks() const {
+ return download_feedback_factory_.num_feedbacks();
+ }
+ protected:
+ base::ScopedTempDir temp_dir_;
+ content::TestBrowserThreadBundle thread_bundle_;
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+ scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
+ FakeDownloadFeedbackFactory download_feedback_factory_;
+
+};
+
+TEST_F(DownloadFeedbackServiceTest, MaybeStorePingsForDownload) {
+ const int64 ok_size = DownloadFeedback::kMaxUploadSize;
+ const int64 bad_size = DownloadFeedback::kMaxUploadSize + 1;
+
+ EXPECT_FALSE(WillStorePings(DownloadProtectionService::SAFE, ok_size));
+ EXPECT_FALSE(WillStorePings(DownloadProtectionService::DANGEROUS, ok_size));
+ EXPECT_TRUE(WillStorePings(DownloadProtectionService::UNCOMMON, ok_size));
+ EXPECT_TRUE(
+ WillStorePings(DownloadProtectionService::DANGEROUS_HOST, ok_size));
+
+ EXPECT_FALSE(WillStorePings(DownloadProtectionService::SAFE, bad_size));
+ EXPECT_FALSE(WillStorePings(DownloadProtectionService::DANGEROUS, bad_size));
+ EXPECT_FALSE(WillStorePings(DownloadProtectionService::UNCOMMON, bad_size));
+ EXPECT_FALSE(
+ WillStorePings(DownloadProtectionService::DANGEROUS_HOST, bad_size));
+}
+
+TEST_F(DownloadFeedbackServiceTest, SingleFeedbackComplete) {
+ const base::FilePath file_path(CreateTestFile(0));
+ const std::string ping_request = "ping";
+ const std::string ping_response = "resp";
+
+ content::DownloadItem::AcquireFileCallback download_discarded_callback;
+
+ content::MockDownloadItem item;
+ EXPECT_CALL(item, GetDangerType())
+ .WillRepeatedly(Return(content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT));
+ EXPECT_CALL(item, GetReceivedBytes()).WillRepeatedly(Return(1000));
+ EXPECT_CALL(item, StealDangerousDownload(_))
+ .WillOnce(SaveArg<0>(&download_discarded_callback));
+
+ DownloadFeedbackService service(request_context_getter_, file_task_runner_);
+ service.MaybeStorePingsForDownload(
+ DownloadProtectionService::UNCOMMON, &item, ping_request, ping_response);
+ ASSERT_TRUE(DownloadFeedbackService::IsEnabledForDownload(item));
+ service.BeginFeedbackForDownload(&item);
+ ASSERT_FALSE(download_discarded_callback.is_null());
+ EXPECT_EQ(0U, num_feedbacks());
+
+ download_discarded_callback.Run(file_path);
+ ASSERT_EQ(1U, num_feedbacks());
+ ASSERT_TRUE(feedback(0));
+ EXPECT_TRUE(feedback(0)->start_called());
+ EXPECT_EQ(ping_request, feedback(0)->GetPingRequestForTesting());
+ EXPECT_EQ(ping_response, feedback(0)->GetPingResponseForTesting());
+
+ feedback(0)->finish_callback().Run();
+ EXPECT_FALSE(feedback(0));
+
+ // File should still exist since our FakeDownloadFeedback does not delete it.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(file_util::PathExists(file_path));
+}
+
+TEST_F(DownloadFeedbackServiceTest, MultiplePendingFeedbackComplete) {
+ const std::string ping_request = "ping";
+ const std::string ping_response = "resp";
+ const size_t num_downloads = 3;
+
+ content::DownloadItem::AcquireFileCallback
+ download_discarded_callback[num_downloads];
+
+ base::FilePath file_path[num_downloads];
+ content::MockDownloadItem item[num_downloads];
+ for (size_t i = 0; i < num_downloads; ++i) {
+ file_path[i] = CreateTestFile(i);
+ EXPECT_CALL(item[i], GetDangerType())
+ .WillRepeatedly(Return(content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT));
+ EXPECT_CALL(item[i], GetReceivedBytes()).WillRepeatedly(Return(1000));
+ EXPECT_CALL(item[i], StealDangerousDownload(_))
+ .WillOnce(SaveArg<0>(&download_discarded_callback[i]));
+ DownloadFeedbackService::MaybeStorePingsForDownload(
+ DownloadProtectionService::UNCOMMON, &item[i], ping_request,
+ ping_response);
+ ASSERT_TRUE(DownloadFeedbackService::IsEnabledForDownload(item[i]));
+ }
+
+ {
+ DownloadFeedbackService service(request_context_getter_, file_task_runner_);
+ for (size_t i = 0; i < num_downloads; ++i) {
+ SCOPED_TRACE(i);
+ service.BeginFeedbackForDownload(&item[i]);
+ ASSERT_FALSE(download_discarded_callback[i].is_null());
+ }
+ EXPECT_EQ(0U, num_feedbacks());
+
+ for (size_t i = 0; i < num_downloads; ++i) {
+ download_discarded_callback[i].Run(file_path[i]);
+ }
+
+ ASSERT_EQ(3U, num_feedbacks());
+ EXPECT_TRUE(feedback(0)->start_called());
+ EXPECT_FALSE(feedback(1)->start_called());
+ EXPECT_FALSE(feedback(2)->start_called());
+
+ feedback(0)->finish_callback().Run();
+
+ EXPECT_FALSE(feedback(0));
+ EXPECT_TRUE(feedback(1)->start_called());
+ EXPECT_FALSE(feedback(2)->start_called());
+
+ feedback(1)->finish_callback().Run();
+
+ EXPECT_FALSE(feedback(0));
+ EXPECT_FALSE(feedback(1));
+ EXPECT_TRUE(feedback(2)->start_called());
+
+ feedback(2)->finish_callback().Run();
+
+ EXPECT_FALSE(feedback(0));
+ EXPECT_FALSE(feedback(1));
+ EXPECT_FALSE(feedback(2));
+ }
+
+ base::RunLoop().RunUntilIdle();
+ // These files should still exist since the FakeDownloadFeedback does not
+ // delete them.
+ EXPECT_TRUE(file_util::PathExists(file_path[0]));
+ EXPECT_TRUE(file_util::PathExists(file_path[1]));
+ EXPECT_TRUE(file_util::PathExists(file_path[2]));
+}
+
+TEST_F(DownloadFeedbackServiceTest, MultiFeedbackWithIncomplete) {
+ const std::string ping_request = "ping";
+ const std::string ping_response = "resp";
+ const size_t num_downloads = 3;
+
+ content::DownloadItem::AcquireFileCallback
+ download_discarded_callback[num_downloads];
+
+ base::FilePath file_path[num_downloads];
+ content::MockDownloadItem item[num_downloads];
+ for (size_t i = 0; i < num_downloads; ++i) {
+ file_path[i] = CreateTestFile(i);
+ EXPECT_CALL(item[i], GetDangerType())
+ .WillRepeatedly(Return(content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT));
+ EXPECT_CALL(item[i], GetReceivedBytes()).WillRepeatedly(Return(1000));
+ EXPECT_CALL(item[i], StealDangerousDownload(_))
+ .WillOnce(SaveArg<0>(&download_discarded_callback[i]));
+ DownloadFeedbackService::MaybeStorePingsForDownload(
+ DownloadProtectionService::UNCOMMON, &item[i], ping_request,
+ ping_response);
+ ASSERT_TRUE(DownloadFeedbackService::IsEnabledForDownload(item[i]));
+ }
+
+ {
+ DownloadFeedbackService service(request_context_getter_, file_task_runner_);
+ for (size_t i = 0; i < num_downloads; ++i) {
+ SCOPED_TRACE(i);
+ service.BeginFeedbackForDownload(&item[i]);
+ ASSERT_FALSE(download_discarded_callback[i].is_null());
+ }
+ EXPECT_EQ(0U, num_feedbacks());
+
+ download_discarded_callback[0].Run(file_path[0]);
+ ASSERT_EQ(1U, num_feedbacks());
+ ASSERT_TRUE(feedback(0));
+ EXPECT_TRUE(feedback(0)->start_called());
+
+ download_discarded_callback[1].Run(file_path[1]);
+ ASSERT_EQ(2U, num_feedbacks());
+ ASSERT_TRUE(feedback(1));
+ EXPECT_FALSE(feedback(1)->start_called());
+
+ feedback(0)->finish_callback().Run();
+ EXPECT_FALSE(feedback(0));
+ EXPECT_TRUE(feedback(1)->start_called());
+ }
+
+ EXPECT_EQ(2U, num_feedbacks());
+ for (size_t i = 0; i < num_feedbacks(); ++i) {
+ SCOPED_TRACE(i);
+ EXPECT_FALSE(feedback(i));
+ }
+
+ // Running a download acquired callback after the DownloadFeedbackService is
+ // destroyed should delete the file.
+ download_discarded_callback[2].Run(file_path[2]);
+ EXPECT_EQ(2U, num_feedbacks());
+
+ // File should still exist since the FileUtilProxy task hasn't run yet.
+ EXPECT_TRUE(file_util::PathExists(file_path[2]));
+
+ base::RunLoop().RunUntilIdle();
+ // File should be deleted since the AcquireFileCallback ran after the service
+ // was deleted.
+ EXPECT_FALSE(file_util::PathExists(file_path[2]));
+
+ // These files should still exist since the FakeDownloadFeedback does not
+ // delete them.
+ EXPECT_TRUE(file_util::PathExists(file_path[0]));
+ EXPECT_TRUE(file_util::PathExists(file_path[1]));
+}
+
+} // namespace safe_browsing

Powered by Google App Engine
This is Rietveld 408576698