From b120440b979924e5100ee2ff9b484a39d0584c59 Mon Sep 17 00:00:00 2001 From: sorin Date: Mon, 27 Apr 2015 09:34:15 -0700 Subject: Move the unit tests files side-by-side with the corresponding .cc files. This is a mechanical change. The idea here is that we want to simplify the directory tree of the component updater files and easily see what compilation unit has tests and which one does not. This change includes some whitespace changes due to running git cl format. BUG=479904 Review URL: https://codereview.chromium.org/1102103002 Cr-Commit-Position: refs/heads/master@{#327054} --- components/components_tests.gyp | 14 +- components/update_client.gypi | 12 +- components/update_client/BUILD.gn | 26 +- components/update_client/DEPS | 10 +- .../update_client/component_patcher_unittest.cc | 200 +++ .../update_client/component_patcher_unittest.h | 42 + .../update_client/crx_downloader_unittest.cc | 382 ++++++ components/update_client/ping_manager_unittest.cc | 178 +++ .../update_client/request_sender_unittest.cc | 206 +++ components/update_client/test/DEPS | 5 - .../test/component_patcher_unittest.cc | 200 --- .../test/component_patcher_unittest.h | 42 - .../update_client/test/crx_downloader_unittest.cc | 382 ------ .../update_client/test/ping_manager_unittest.cc | 178 --- .../update_client/test/request_sender_unittest.cc | 206 --- components/update_client/test/test_configurator.cc | 158 --- components/update_client/test/test_configurator.h | 111 -- components/update_client/test/test_installer.cc | 85 -- components/update_client/test/test_installer.h | 88 -- .../update_client/test/update_checker_unittest.cc | 237 ---- .../update_client/test/update_client_unittest.cc | 1422 -------------------- .../update_client/test/update_response_unittest.cc | 302 ----- .../test/url_request_post_interceptor.cc | 301 ----- .../test/url_request_post_interceptor.h | 165 --- components/update_client/test_configurator.cc | 158 +++ components/update_client/test_configurator.h | 111 ++ components/update_client/test_installer.cc | 85 ++ components/update_client/test_installer.h | 84 ++ .../update_client/update_checker_unittest.cc | 237 ++++ components/update_client/update_client_unittest.cc | 1422 ++++++++++++++++++++ .../update_client/update_response_unittest.cc | 302 +++++ .../update_client/url_request_post_interceptor.cc | 301 +++++ .../update_client/url_request_post_interceptor.h | 165 +++ 33 files changed, 3908 insertions(+), 3909 deletions(-) create mode 100644 components/update_client/component_patcher_unittest.cc create mode 100644 components/update_client/component_patcher_unittest.h create mode 100644 components/update_client/crx_downloader_unittest.cc create mode 100644 components/update_client/ping_manager_unittest.cc create mode 100644 components/update_client/request_sender_unittest.cc delete mode 100644 components/update_client/test/DEPS delete mode 100644 components/update_client/test/component_patcher_unittest.cc delete mode 100644 components/update_client/test/component_patcher_unittest.h delete mode 100644 components/update_client/test/crx_downloader_unittest.cc delete mode 100644 components/update_client/test/ping_manager_unittest.cc delete mode 100644 components/update_client/test/request_sender_unittest.cc delete mode 100644 components/update_client/test/test_configurator.cc delete mode 100644 components/update_client/test/test_configurator.h delete mode 100644 components/update_client/test/test_installer.cc delete mode 100644 components/update_client/test/test_installer.h delete mode 100644 components/update_client/test/update_checker_unittest.cc delete mode 100644 components/update_client/test/update_client_unittest.cc delete mode 100644 components/update_client/test/update_response_unittest.cc delete mode 100644 components/update_client/test/url_request_post_interceptor.cc delete mode 100644 components/update_client/test/url_request_post_interceptor.h create mode 100644 components/update_client/test_configurator.cc create mode 100644 components/update_client/test_configurator.h create mode 100644 components/update_client/test_installer.cc create mode 100644 components/update_client/test_installer.h create mode 100644 components/update_client/update_checker_unittest.cc create mode 100644 components/update_client/update_client_unittest.cc create mode 100644 components/update_client/update_response_unittest.cc create mode 100644 components/update_client/url_request_post_interceptor.cc create mode 100644 components/update_client/url_request_post_interceptor.h (limited to 'components') diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 9c3ea50..c9191c7 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp @@ -524,14 +524,14 @@ 'ui/zoom/page_zoom_unittests.cc', ], 'update_client_unittest_sources': [ - 'update_client/test/component_patcher_unittest.cc', - 'update_client/test/crx_downloader_unittest.cc', - 'update_client/test/ping_manager_unittest.cc', - 'update_client/test/request_sender_unittest.cc', - 'update_client/test/update_checker_unittest.cc', - 'update_client/test/update_client_unittest.cc', - 'update_client/test/update_response_unittest.cc', + 'update_client/component_patcher_unittest.cc', + 'update_client/crx_downloader_unittest.cc', + 'update_client/ping_manager_unittest.cc', + 'update_client/request_sender_unittest.cc', + 'update_client/update_checker_unittest.cc', + 'update_client/update_client_unittest.cc', 'update_client/update_query_params_unittest.cc', + 'update_client/update_response_unittest.cc', ], 'url_fixer_unittest_sources': [ 'url_fixer/url_fixer_unittest.cc', diff --git a/components/update_client.gypi b/components/update_client.gypi index d4870a8..c5759d0 100644 --- a/components/update_client.gypi +++ b/components/update_client.gypi @@ -83,12 +83,12 @@ '..', ], 'sources': [ - 'update_client/test/test_configurator.cc', - 'update_client/test/test_configurator.h', - 'update_client/test/test_installer.cc', - 'update_client/test/test_installer.h', - 'update_client/test/url_request_post_interceptor.cc', - 'update_client/test/url_request_post_interceptor.h', + 'update_client/test_configurator.cc', + 'update_client/test_configurator.h', + 'update_client/test_installer.cc', + 'update_client/test_installer.h', + 'update_client/url_request_post_interceptor.cc', + 'update_client/url_request_post_interceptor.h', ], }, ], diff --git a/components/update_client/BUILD.gn b/components/update_client/BUILD.gn index 17665721..d4e6125 100644 --- a/components/update_client/BUILD.gn +++ b/components/update_client/BUILD.gn @@ -65,12 +65,12 @@ source_set("update_client") { source_set("test_support") { testonly = true sources = [ - "test/test_configurator.cc", - "test/test_configurator.h", - "test/test_installer.cc", - "test/test_installer.h", - "test/url_request_post_interceptor.cc", - "test/url_request_post_interceptor.h", + "test_configurator.cc", + "test_configurator.h", + "test_installer.cc", + "test_installer.h", + "url_request_post_interceptor.cc", + "url_request_post_interceptor.h", ] deps = [ @@ -86,13 +86,13 @@ source_set("test_support") { source_set("unit_tests") { testonly = true sources = [ - "test/component_patcher_unittest.cc", - "test/crx_downloader_unittest.cc", - "test/ping_manager_unittest.cc", - "test/request_sender_unittest.cc", - "test/update_checker_unittest.cc", - "test/update_client_unittest.cc", - "test/update_response_unittest.cc", + "component_patcher_unittest.cc", + "crx_downloader_unittest.cc", + "ping_manager_unittest.cc", + "request_sender_unittest.cc", + "update_checker_unittest.cc", + "update_client_unittest.cc", + "update_response_unittest.cc", ] deps = [ diff --git a/components/update_client/DEPS b/components/update_client/DEPS index 79e0349..7fa7165 100644 --- a/components/update_client/DEPS +++ b/components/update_client/DEPS @@ -8,5 +8,13 @@ include_rules = [ "+ui/base/win", "+third_party/libxml", "+third_party/zlib", - "+testing", ] + +# Tests can use things in content. +# TODO(sorin): refactor to eliminate the dependency on content by using +# message loops directly. +specific_include_rules = { + ".*unittest\.cc": [ + "+content", + ] +} \ No newline at end of file diff --git a/components/update_client/component_patcher_unittest.cc b/components/update_client/component_patcher_unittest.cc new file mode 100644 index 0000000..c398abc --- /dev/null +++ b/components/update_client/component_patcher_unittest.cc @@ -0,0 +1,200 @@ +// 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 "base/base_paths.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/compiler_specific.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/macros.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/values.h" +#include "components/update_client/component_patcher.h" +#include "components/update_client/component_patcher_operation.h" +#include "components/update_client/component_patcher_unittest.h" +#include "components/update_client/test_installer.h" +#include "courgette/courgette.h" +#include "courgette/third_party/bsdiff.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class TestCallback { + public: + TestCallback(); + virtual ~TestCallback() {} + void Set(update_client::ComponentUnpacker::Error error, int extra_code); + + int error_; + int extra_code_; + bool called_; + + private: + DISALLOW_COPY_AND_ASSIGN(TestCallback); +}; + +TestCallback::TestCallback() : error_(-1), extra_code_(-1), called_(false) { +} + +void TestCallback::Set(update_client::ComponentUnpacker::Error error, + int extra_code) { + error_ = error; + extra_code_ = extra_code; + called_ = true; +} + +} // namespace + +namespace update_client { + +namespace { + +base::FilePath test_file(const char* file) { + base::FilePath path; + PathService::Get(base::DIR_SOURCE_ROOT, &path); + return path.AppendASCII("components") + .AppendASCII("test") + .AppendASCII("data") + .AppendASCII("update_client") + .AppendASCII(file); +} + +} // namespace + +ComponentPatcherOperationTest::ComponentPatcherOperationTest() { + EXPECT_TRUE(unpack_dir_.CreateUniqueTempDir()); + EXPECT_TRUE(input_dir_.CreateUniqueTempDir()); + EXPECT_TRUE(installed_dir_.CreateUniqueTempDir()); + installer_ = new ReadOnlyTestInstaller(installed_dir_.path()); + task_runner_ = base::MessageLoop::current()->task_runner(); +} + +ComponentPatcherOperationTest::~ComponentPatcherOperationTest() { +} + +// Verify that a 'create' delta update operation works correctly. +TEST_F(ComponentPatcherOperationTest, CheckCreateOperation) { + EXPECT_TRUE(base::CopyFile( + test_file("binary_output.bin"), + input_dir_.path().Append(FILE_PATH_LITERAL("binary_output.bin")))); + + scoped_ptr command_args(new base::DictionaryValue()); + command_args->SetString("output", "output.bin"); + command_args->SetString("sha256", binary_output_hash); + command_args->SetString("op", "create"); + command_args->SetString("patch", "binary_output.bin"); + + TestCallback callback; + scoped_refptr op = new DeltaUpdateOpCreate(); + op->Run(command_args.get(), input_dir_.path(), unpack_dir_.path(), NULL, + base::Bind(&TestCallback::Set, base::Unretained(&callback)), + task_runner_); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(true, callback.called_); + EXPECT_EQ(ComponentUnpacker::kNone, callback.error_); + EXPECT_EQ(0, callback.extra_code_); + EXPECT_TRUE(base::ContentsEqual( + unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")), + test_file("binary_output.bin"))); +} + +// Verify that a 'copy' delta update operation works correctly. +TEST_F(ComponentPatcherOperationTest, CheckCopyOperation) { + EXPECT_TRUE(base::CopyFile( + test_file("binary_output.bin"), + installed_dir_.path().Append(FILE_PATH_LITERAL("binary_output.bin")))); + + scoped_ptr command_args(new base::DictionaryValue()); + command_args->SetString("output", "output.bin"); + command_args->SetString("sha256", binary_output_hash); + command_args->SetString("op", "copy"); + command_args->SetString("input", "binary_output.bin"); + + TestCallback callback; + scoped_refptr op = new DeltaUpdateOpCopy(); + op->Run(command_args.get(), input_dir_.path(), unpack_dir_.path(), + installer_.get(), + base::Bind(&TestCallback::Set, base::Unretained(&callback)), + task_runner_); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(true, callback.called_); + EXPECT_EQ(ComponentUnpacker::kNone, callback.error_); + EXPECT_EQ(0, callback.extra_code_); + EXPECT_TRUE(base::ContentsEqual( + unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")), + test_file("binary_output.bin"))); +} + +// Verify that a 'courgette' delta update operation works correctly. +TEST_F(ComponentPatcherOperationTest, CheckCourgetteOperation) { + EXPECT_TRUE(base::CopyFile( + test_file("binary_input.bin"), + installed_dir_.path().Append(FILE_PATH_LITERAL("binary_input.bin")))); + EXPECT_TRUE(base::CopyFile(test_file("binary_courgette_patch.bin"), + input_dir_.path().Append(FILE_PATH_LITERAL( + "binary_courgette_patch.bin")))); + + scoped_ptr command_args(new base::DictionaryValue()); + command_args->SetString("output", "output.bin"); + command_args->SetString("sha256", binary_output_hash); + command_args->SetString("op", "courgette"); + command_args->SetString("input", "binary_input.bin"); + command_args->SetString("patch", "binary_courgette_patch.bin"); + + TestCallback callback; + scoped_refptr op = + CreateDeltaUpdateOp("courgette", NULL /* out_of_process_patcher */); + op->Run(command_args.get(), input_dir_.path(), unpack_dir_.path(), + installer_.get(), + base::Bind(&TestCallback::Set, base::Unretained(&callback)), + task_runner_); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(true, callback.called_); + EXPECT_EQ(ComponentUnpacker::kNone, callback.error_); + EXPECT_EQ(0, callback.extra_code_); + EXPECT_TRUE(base::ContentsEqual( + unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")), + test_file("binary_output.bin"))); +} + +// Verify that a 'bsdiff' delta update operation works correctly. +TEST_F(ComponentPatcherOperationTest, CheckBsdiffOperation) { + EXPECT_TRUE(base::CopyFile( + test_file("binary_input.bin"), + installed_dir_.path().Append(FILE_PATH_LITERAL("binary_input.bin")))); + EXPECT_TRUE(base::CopyFile( + test_file("binary_bsdiff_patch.bin"), + input_dir_.path().Append(FILE_PATH_LITERAL("binary_bsdiff_patch.bin")))); + + scoped_ptr command_args(new base::DictionaryValue()); + command_args->SetString("output", "output.bin"); + command_args->SetString("sha256", binary_output_hash); + command_args->SetString("op", "courgette"); + command_args->SetString("input", "binary_input.bin"); + command_args->SetString("patch", "binary_bsdiff_patch.bin"); + + TestCallback callback; + scoped_refptr op = + CreateDeltaUpdateOp("bsdiff", NULL /* out_of_process_patcher */); + op->Run(command_args.get(), input_dir_.path(), unpack_dir_.path(), + installer_.get(), + base::Bind(&TestCallback::Set, base::Unretained(&callback)), + task_runner_); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(true, callback.called_); + EXPECT_EQ(ComponentUnpacker::kNone, callback.error_); + EXPECT_EQ(0, callback.extra_code_); + EXPECT_TRUE(base::ContentsEqual( + unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")), + test_file("binary_output.bin"))); +} + +} // namespace update_client diff --git a/components/update_client/component_patcher_unittest.h b/components/update_client/component_patcher_unittest.h new file mode 100644 index 0000000..8b3a797 --- /dev/null +++ b/components/update_client/component_patcher_unittest.h @@ -0,0 +1,42 @@ +// 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. + +#ifndef COMPONENTS_UPDATE_CLIENT_COMPONENT_PATCHER_UNITTEST_H_ +#define COMPONENTS_UPDATE_CLIENT_COMPONENT_PATCHER_UNITTEST_H_ + +#include "base/files/file_path.h" +#include "base/files/scoped_temp_dir.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "courgette/courgette.h" +#include "courgette/third_party/bsdiff.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace update_client { + +class MockComponentPatcher; +class ReadOnlyTestInstaller; + +const char binary_output_hash[] = + "599aba6d15a7da390621ef1bacb66601ed6aed04dadc1f9b445dcfe31296142a"; + +class ComponentPatcherOperationTest : public testing::Test { + public: + ComponentPatcherOperationTest(); + ~ComponentPatcherOperationTest() override; + + protected: + base::ScopedTempDir input_dir_; + base::ScopedTempDir installed_dir_; + base::ScopedTempDir unpack_dir_; + scoped_refptr installer_; + scoped_refptr task_runner_; + + private: + base::MessageLoopForIO loop_; +}; + +} // namespace update_client + +#endif // COMPONENTS_UPDATE_CLIENT_COMPONENT_PATCHER_UNITTEST_H_ diff --git a/components/update_client/crx_downloader_unittest.cc b/components/update_client/crx_downloader_unittest.cc new file mode 100644 index 0000000..4b80f13 --- /dev/null +++ b/components/update_client/crx_downloader_unittest.cc @@ -0,0 +1,382 @@ +// 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 "base/bind.h" +#include "base/bind_helpers.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "components/update_client/crx_downloader.h" +#include "net/base/net_errors.h" +#include "net/url_request/test_url_request_interceptor.h" +#include "net/url_request/url_request_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::ContentsEqual; + +namespace update_client { + +namespace { + +// Intercepts HTTP GET requests sent to "localhost". +typedef net::LocalHostTestURLRequestInterceptor GetInterceptor; + +const char kTestFileName[] = "jebgalgnebhfojomionfpkfelancnnkf.crx"; + +base::FilePath MakeTestFilePath(const char* file) { + base::FilePath path; + PathService::Get(base::DIR_SOURCE_ROOT, &path); + return path.AppendASCII("components") + .AppendASCII("test") + .AppendASCII("data") + .AppendASCII("update_client") + .AppendASCII(file); +} + +} // namespace + +class CrxDownloaderTest : public testing::Test { + public: + CrxDownloaderTest(); + ~CrxDownloaderTest() override; + + // Overrides from testing::Test. + void SetUp() override; + void TearDown() override; + + void Quit(); + void RunThreads(); + void RunThreadsUntilIdle(); + + void DownloadComplete(int crx_context, const CrxDownloader::Result& result); + + void DownloadProgress(int crx_context, const CrxDownloader::Result& result); + + protected: + scoped_ptr crx_downloader_; + + scoped_ptr get_interceptor_; + + CrxDownloader::DownloadCallback callback_; + CrxDownloader::ProgressCallback progress_callback_; + + int crx_context_; + + int num_download_complete_calls_; + CrxDownloader::Result download_complete_result_; + + // These members are updated by DownloadProgress. + int num_progress_calls_; + CrxDownloader::Result download_progress_result_; + + // A magic value for the context to be used in the tests. + static const int kExpectedContext = 0xaabb; + + private: + base::MessageLoopForIO loop_; + scoped_refptr context_; + base::Closure quit_closure_; +}; + +const int CrxDownloaderTest::kExpectedContext; + +CrxDownloaderTest::CrxDownloaderTest() + : callback_(base::Bind(&CrxDownloaderTest::DownloadComplete, + base::Unretained(this), + kExpectedContext)), + progress_callback_(base::Bind(&CrxDownloaderTest::DownloadProgress, + base::Unretained(this), + kExpectedContext)), + crx_context_(0), + num_download_complete_calls_(0), + num_progress_calls_(0), + context_(new net::TestURLRequestContextGetter( + base::MessageLoopProxy::current())) { +} + +CrxDownloaderTest::~CrxDownloaderTest() { + context_ = NULL; + + // The GetInterceptor requires the message loop to run to destruct correctly. + get_interceptor_.reset(); + RunThreadsUntilIdle(); +} + +void CrxDownloaderTest::SetUp() { + num_download_complete_calls_ = 0; + download_complete_result_ = CrxDownloader::Result(); + num_progress_calls_ = 0; + download_progress_result_ = CrxDownloader::Result(); + + // Do not use the background downloader in these tests. + crx_downloader_.reset(CrxDownloader::Create(false, context_.get(), + base::MessageLoopProxy::current(), + NULL).release()); + crx_downloader_->set_progress_callback(progress_callback_); + + get_interceptor_.reset(new GetInterceptor(base::MessageLoopProxy::current(), + base::MessageLoopProxy::current())); +} + +void CrxDownloaderTest::TearDown() { + crx_downloader_.reset(); +} + +void CrxDownloaderTest::Quit() { + if (!quit_closure_.is_null()) + quit_closure_.Run(); +} + +void CrxDownloaderTest::DownloadComplete(int crx_context, + const CrxDownloader::Result& result) { + ++num_download_complete_calls_; + crx_context_ = crx_context; + download_complete_result_ = result; + Quit(); +} + +void CrxDownloaderTest::DownloadProgress(int crx_context, + const CrxDownloader::Result& result) { + ++num_progress_calls_; + download_progress_result_ = result; +} + +void CrxDownloaderTest::RunThreads() { + base::RunLoop runloop; + quit_closure_ = runloop.QuitClosure(); + runloop.Run(); + + // Since some tests need to drain currently enqueued tasks such as network + // intercepts on the IO thread, run the threads until they are + // idle. The component updater service won't loop again until the loop count + // is set and the service is started. + RunThreadsUntilIdle(); +} + +void CrxDownloaderTest::RunThreadsUntilIdle() { + base::RunLoop().RunUntilIdle(); +} + +// Tests that starting a download without a url results in an error. +TEST_F(CrxDownloaderTest, NoUrl) { + std::vector urls; + crx_downloader_->StartDownload(urls, callback_); + RunThreadsUntilIdle(); + + EXPECT_EQ(1, num_download_complete_calls_); + EXPECT_EQ(kExpectedContext, crx_context_); + EXPECT_EQ(-1, download_complete_result_.error); + EXPECT_TRUE(download_complete_result_.response.empty()); + EXPECT_EQ(-1, download_complete_result_.downloaded_bytes); + EXPECT_EQ(-1, download_complete_result_.total_bytes); + EXPECT_EQ(0, num_progress_calls_); +} + +// Tests that downloading from one url is successful. +TEST_F(CrxDownloaderTest, OneUrl) { + const GURL expected_crx_url = + GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); + + const base::FilePath test_file(MakeTestFilePath(kTestFileName)); + get_interceptor_->SetResponse(expected_crx_url, test_file); + + crx_downloader_->StartDownloadFromUrl(expected_crx_url, callback_); + RunThreads(); + + EXPECT_EQ(1, get_interceptor_->GetHitCount()); + + EXPECT_EQ(1, num_download_complete_calls_); + EXPECT_EQ(kExpectedContext, crx_context_); + EXPECT_EQ(0, download_complete_result_.error); + EXPECT_EQ(1843, download_complete_result_.downloaded_bytes); + EXPECT_EQ(1843, download_complete_result_.total_bytes); + EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file)); + + EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false)); + + EXPECT_LE(1, num_progress_calls_); + EXPECT_EQ(1843, download_progress_result_.downloaded_bytes); + EXPECT_EQ(1843, download_progress_result_.total_bytes); +} + +// Tests that specifying from two urls has no side effects. Expect a successful +// download, and only one download request be made. +// This test is flaky on Android. crbug.com/329883 +#if defined(OS_ANDROID) +#define MAYBE_TwoUrls DISABLED_TwoUrls +#else +#define MAYBE_TwoUrls TwoUrls +#endif +TEST_F(CrxDownloaderTest, MAYBE_TwoUrls) { + const GURL expected_crx_url = + GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); + + const base::FilePath test_file(MakeTestFilePath(kTestFileName)); + get_interceptor_->SetResponse(expected_crx_url, test_file); + + std::vector urls; + urls.push_back(expected_crx_url); + urls.push_back(expected_crx_url); + + crx_downloader_->StartDownload(urls, callback_); + RunThreads(); + + EXPECT_EQ(1, get_interceptor_->GetHitCount()); + + EXPECT_EQ(1, num_download_complete_calls_); + EXPECT_EQ(kExpectedContext, crx_context_); + EXPECT_EQ(0, download_complete_result_.error); + EXPECT_EQ(1843, download_complete_result_.downloaded_bytes); + EXPECT_EQ(1843, download_complete_result_.total_bytes); + EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file)); + + EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false)); + + EXPECT_LE(1, num_progress_calls_); + EXPECT_EQ(1843, download_progress_result_.downloaded_bytes); + EXPECT_EQ(1843, download_progress_result_.total_bytes); +} + +// Tests that an invalid host results in a download error. +TEST_F(CrxDownloaderTest, OneUrl_InvalidHost) { + const GURL expected_crx_url = + GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); + + const base::FilePath test_file(MakeTestFilePath(kTestFileName)); + get_interceptor_->SetResponse(expected_crx_url, test_file); + + crx_downloader_->StartDownloadFromUrl( + GURL( + "http://no.such.host" + "/download/jebgalgnebhfojomionfpkfelancnnkf.crx"), + callback_); + RunThreads(); + + EXPECT_EQ(0, get_interceptor_->GetHitCount()); + + EXPECT_EQ(1, num_download_complete_calls_); + EXPECT_EQ(kExpectedContext, crx_context_); + EXPECT_NE(0, download_complete_result_.error); + EXPECT_TRUE(download_complete_result_.response.empty()); +} + +// Tests that an invalid path results in a download error. +TEST_F(CrxDownloaderTest, OneUrl_InvalidPath) { + const GURL expected_crx_url = + GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); + + const base::FilePath test_file(MakeTestFilePath(kTestFileName)); + get_interceptor_->SetResponse(expected_crx_url, test_file); + + crx_downloader_->StartDownloadFromUrl(GURL("http://localhost/no/such/file"), + callback_); + RunThreads(); + + EXPECT_EQ(0, get_interceptor_->GetHitCount()); + + EXPECT_EQ(1, num_download_complete_calls_); + EXPECT_EQ(kExpectedContext, crx_context_); + EXPECT_NE(0, download_complete_result_.error); + EXPECT_TRUE(download_complete_result_.response.empty()); +} + +// Tests that the fallback to a valid url is successful. +// This test is flaky on Android. crbug.com/329883 +#if defined(OS_ANDROID) +#define MAYBE_TwoUrls_FirstInvalid DISABLED_TwoUrls_FirstInvalid +#else +#define MAYBE_TwoUrls_FirstInvalid TwoUrls_FirstInvalid +#endif +TEST_F(CrxDownloaderTest, MAYBE_TwoUrls_FirstInvalid) { + const GURL expected_crx_url = + GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); + + const base::FilePath test_file(MakeTestFilePath(kTestFileName)); + get_interceptor_->SetResponse(expected_crx_url, test_file); + + std::vector urls; + urls.push_back(GURL("http://localhost/no/such/file")); + urls.push_back(expected_crx_url); + + crx_downloader_->StartDownload(urls, callback_); + RunThreads(); + + EXPECT_EQ(1, get_interceptor_->GetHitCount()); + + EXPECT_EQ(1, num_download_complete_calls_); + EXPECT_EQ(kExpectedContext, crx_context_); + EXPECT_EQ(0, download_complete_result_.error); + EXPECT_EQ(1843, download_complete_result_.downloaded_bytes); + EXPECT_EQ(1843, download_complete_result_.total_bytes); + EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file)); + + EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false)); + + EXPECT_LE(1, num_progress_calls_); + EXPECT_EQ(1843, download_progress_result_.downloaded_bytes); + EXPECT_EQ(1843, download_progress_result_.total_bytes); +} + +// Tests that the download succeeds if the first url is correct and the +// second bad url does not have a side-effect. +TEST_F(CrxDownloaderTest, TwoUrls_SecondInvalid) { + const GURL expected_crx_url = + GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); + + const base::FilePath test_file(MakeTestFilePath(kTestFileName)); + get_interceptor_->SetResponse(expected_crx_url, test_file); + + std::vector urls; + urls.push_back(expected_crx_url); + urls.push_back(GURL("http://localhost/no/such/file")); + + crx_downloader_->StartDownload(urls, callback_); + RunThreads(); + + EXPECT_EQ(1, get_interceptor_->GetHitCount()); + + EXPECT_EQ(1, num_download_complete_calls_); + EXPECT_EQ(kExpectedContext, crx_context_); + EXPECT_EQ(0, download_complete_result_.error); + EXPECT_EQ(1843, download_complete_result_.downloaded_bytes); + EXPECT_EQ(1843, download_complete_result_.total_bytes); + EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file)); + + EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false)); + + EXPECT_LE(1, num_progress_calls_); + EXPECT_EQ(1843, download_progress_result_.downloaded_bytes); + EXPECT_EQ(1843, download_progress_result_.total_bytes); +} + +// Tests that the download fails if both urls are bad. +TEST_F(CrxDownloaderTest, TwoUrls_BothInvalid) { + const GURL expected_crx_url = + GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); + + const base::FilePath test_file(MakeTestFilePath(kTestFileName)); + get_interceptor_->SetResponse(expected_crx_url, test_file); + + std::vector urls; + urls.push_back(GURL("http://localhost/no/such/file")); + urls.push_back(GURL( + "http://no.such.host/" + "/download/jebgalgnebhfojomionfpkfelancnnkf.crx")); + + crx_downloader_->StartDownload(urls, callback_); + RunThreads(); + + EXPECT_EQ(0, get_interceptor_->GetHitCount()); + + EXPECT_EQ(1, num_download_complete_calls_); + EXPECT_EQ(kExpectedContext, crx_context_); + EXPECT_NE(0, download_complete_result_.error); + EXPECT_TRUE(download_complete_result_.response.empty()); +} + +} // namespace update_client diff --git a/components/update_client/ping_manager_unittest.cc b/components/update_client/ping_manager_unittest.cc new file mode 100644 index 0000000..cfd37e1 --- /dev/null +++ b/components/update_client/ping_manager_unittest.cc @@ -0,0 +1,178 @@ +// 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 "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/version.h" +#include "components/update_client/crx_update_item.h" +#include "components/update_client/ping_manager.h" +#include "components/update_client/test_configurator.h" +#include "components/update_client/url_request_post_interceptor.h" +#include "net/url_request/url_request_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +using std::string; + +namespace update_client { + +class ComponentUpdaterPingManagerTest : public testing::Test { + public: + ComponentUpdaterPingManagerTest(); + ~ComponentUpdaterPingManagerTest() override {} + + void RunThreadsUntilIdle(); + + // Overrides from testing::Test. + void SetUp() override; + void TearDown() override; + + protected: + scoped_refptr config_; + scoped_ptr ping_manager_; + + private: + base::MessageLoopForIO loop_; +}; + +ComponentUpdaterPingManagerTest::ComponentUpdaterPingManagerTest() { +} + +void ComponentUpdaterPingManagerTest::SetUp() { + config_ = new TestConfigurator(base::MessageLoopProxy::current(), + base::MessageLoopProxy::current()); + ping_manager_.reset(new PingManager(*config_)); +} + +void ComponentUpdaterPingManagerTest::TearDown() { + ping_manager_.reset(); + config_ = nullptr; +} + +void ComponentUpdaterPingManagerTest::RunThreadsUntilIdle() { + base::RunLoop().RunUntilIdle(); +} + +// Test is flaky: http://crbug.com/349547 +TEST_F(ComponentUpdaterPingManagerTest, DISABLED_PingManagerTest) { + scoped_ptr interceptor_factory( + new InterceptorFactory(base::MessageLoopProxy::current())); + URLRequestPostInterceptor* interceptor = + interceptor_factory->CreateInterceptor(); + EXPECT_TRUE(interceptor); + + // Test eventresult="1" is sent for successful updates. + CrxUpdateItem item; + item.id = "abc"; + item.state = CrxUpdateItem::State::kUpdated; + item.previous_version = base::Version("1.0"); + item.next_version = base::Version("2.0"); + + ping_manager_->OnUpdateComplete(&item); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString(); + EXPECT_NE(string::npos, + interceptor->GetRequests()[0].find( + "" + "")) + << interceptor->GetRequestsAsString(); + interceptor->Reset(); + + // Test eventresult="0" is sent for failed updates. + item = CrxUpdateItem(); + item.id = "abc"; + item.state = CrxUpdateItem::State::kNoUpdate; + item.previous_version = base::Version("1.0"); + item.next_version = base::Version("2.0"); + + ping_manager_->OnUpdateComplete(&item); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString(); + EXPECT_NE(string::npos, + interceptor->GetRequests()[0].find( + "" + "")) + << interceptor->GetRequestsAsString(); + interceptor->Reset(); + + // Test the error values and the fingerprints. + item = CrxUpdateItem(); + item.id = "abc"; + item.state = CrxUpdateItem::State::kNoUpdate; + item.previous_version = base::Version("1.0"); + item.next_version = base::Version("2.0"); + item.previous_fp = "prev fp"; + item.next_fp = "next fp"; + item.error_category = 1; + item.error_code = 2; + item.extra_code1 = -1; + item.diff_error_category = 10; + item.diff_error_code = 20; + item.diff_extra_code1 = -10; + item.diff_update_failed = true; + item.crx_diffurls.push_back(GURL("http://host/path")); + + ping_manager_->OnUpdateComplete(&item); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString(); + EXPECT_NE(string::npos, + interceptor->GetRequests()[0].find( + "" + "")) + << interceptor->GetRequestsAsString(); + interceptor->Reset(); + + // Test the download metrics. + item = CrxUpdateItem(); + item.id = "abc"; + item.state = CrxUpdateItem::State::kUpdated; + item.previous_version = base::Version("1.0"); + item.next_version = base::Version("2.0"); + + CrxDownloader::DownloadMetrics download_metrics; + download_metrics.url = GURL("http://host1/path1"); + download_metrics.downloader = CrxDownloader::DownloadMetrics::kUrlFetcher; + download_metrics.error = -1; + download_metrics.downloaded_bytes = 123; + download_metrics.total_bytes = 456; + download_metrics.download_time_ms = 987; + item.download_metrics.push_back(download_metrics); + + download_metrics = CrxDownloader::DownloadMetrics(); + download_metrics.url = GURL("http://host2/path2"); + download_metrics.downloader = CrxDownloader::DownloadMetrics::kBits; + download_metrics.error = 0; + download_metrics.downloaded_bytes = 1230; + download_metrics.total_bytes = 4560; + download_metrics.download_time_ms = 9870; + item.download_metrics.push_back(download_metrics); + + ping_manager_->OnUpdateComplete(&item); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString(); + EXPECT_NE( + string::npos, + interceptor->GetRequests()[0].find( + "" + "" + "" + "")) + << interceptor->GetRequestsAsString(); + interceptor->Reset(); +} + +} // namespace update_client diff --git a/components/update_client/request_sender_unittest.cc b/components/update_client/request_sender_unittest.cc new file mode 100644 index 0000000..4c8e1db --- /dev/null +++ b/components/update_client/request_sender_unittest.cc @@ -0,0 +1,206 @@ +// 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 "base/compiler_specific.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "components/update_client/request_sender.h" +#include "components/update_client/test_configurator.h" +#include "components/update_client/url_request_post_interceptor.h" +#include "net/url_request/url_fetcher.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace update_client { + +namespace { + +const char kUrl1[] = "https://localhost2/path1"; +const char kUrl2[] = "https://localhost2/path2"; +const char kUrlPath1[] = "path1"; +const char kUrlPath2[] = "path2"; + +} // namespace + +class RequestSenderTest : public testing::Test { + public: + RequestSenderTest(); + ~RequestSenderTest() override; + + // Overrides from testing::Test. + void SetUp() override; + void TearDown() override; + + void RequestSenderComplete(const net::URLFetcher* source); + + protected: + void Quit(); + void RunThreads(); + void RunThreadsUntilIdle(); + + scoped_refptr config_; + scoped_ptr request_sender_; + scoped_ptr interceptor_factory_; + + URLRequestPostInterceptor* post_interceptor_1; // Owned by the factory. + URLRequestPostInterceptor* post_interceptor_2; // Owned by the factory. + + const net::URLFetcher* url_fetcher_source_; + + private: + base::MessageLoopForIO loop_; + base::Closure quit_closure_; + + DISALLOW_COPY_AND_ASSIGN(RequestSenderTest); +}; + +RequestSenderTest::RequestSenderTest() + : post_interceptor_1(NULL), + post_interceptor_2(NULL), + url_fetcher_source_(NULL) { +} + +RequestSenderTest::~RequestSenderTest() { +} + +void RequestSenderTest::SetUp() { + config_ = new TestConfigurator(base::MessageLoopProxy::current(), + base::MessageLoopProxy::current()); + interceptor_factory_.reset( + new InterceptorFactory(base::MessageLoopProxy::current())); + post_interceptor_1 = + interceptor_factory_->CreateInterceptorForPath(kUrlPath1); + post_interceptor_2 = + interceptor_factory_->CreateInterceptorForPath(kUrlPath2); + EXPECT_TRUE(post_interceptor_1); + EXPECT_TRUE(post_interceptor_2); + + request_sender_.reset(); +} + +void RequestSenderTest::TearDown() { + request_sender_.reset(); + + post_interceptor_1 = NULL; + post_interceptor_2 = NULL; + + interceptor_factory_.reset(); + + config_ = nullptr; + + RunThreadsUntilIdle(); +} + +void RequestSenderTest::RunThreads() { + base::RunLoop runloop; + quit_closure_ = runloop.QuitClosure(); + runloop.Run(); + + // Since some tests need to drain currently enqueued tasks such as network + // intercepts on the IO thread, run the threads until they are + // idle. The component updater service won't loop again until the loop count + // is set and the service is started. + RunThreadsUntilIdle(); +} + +void RequestSenderTest::RunThreadsUntilIdle() { + base::RunLoop().RunUntilIdle(); +} + +void RequestSenderTest::Quit() { + if (!quit_closure_.is_null()) + quit_closure_.Run(); +} + +void RequestSenderTest::RequestSenderComplete(const net::URLFetcher* source) { + url_fetcher_source_ = source; + Quit(); +} + +// Tests that when a request to the first url succeeds, the subsequent urls are +// not tried. +TEST_F(RequestSenderTest, RequestSendSuccess) { + EXPECT_TRUE(post_interceptor_1->ExpectRequest(new PartialMatch("test"))); + + std::vector urls; + urls.push_back(GURL(kUrl1)); + urls.push_back(GURL(kUrl2)); + request_sender_.reset(new RequestSender(*config_)); + request_sender_->Send("test", urls, + base::Bind(&RequestSenderTest::RequestSenderComplete, + base::Unretained(this))); + RunThreads(); + + EXPECT_EQ(1, post_interceptor_1->GetHitCount()) + << post_interceptor_1->GetRequestsAsString(); + EXPECT_EQ(1, post_interceptor_1->GetCount()) + << post_interceptor_1->GetRequestsAsString(); + + EXPECT_STREQ("test", post_interceptor_1->GetRequests()[0].c_str()); + EXPECT_EQ(GURL(kUrl1), url_fetcher_source_->GetOriginalURL()); + EXPECT_EQ(200, url_fetcher_source_->GetResponseCode()); +} + +// Tests that the request succeeds using the second url after the first url +// has failed. +TEST_F(RequestSenderTest, RequestSendSuccessWithFallback) { + EXPECT_TRUE(post_interceptor_1->ExpectRequest(new PartialMatch("test"), 403)); + EXPECT_TRUE(post_interceptor_2->ExpectRequest(new PartialMatch("test"))); + + std::vector urls; + urls.push_back(GURL(kUrl1)); + urls.push_back(GURL(kUrl2)); + request_sender_.reset(new RequestSender(*config_)); + request_sender_->Send("test", urls, + base::Bind(&RequestSenderTest::RequestSenderComplete, + base::Unretained(this))); + RunThreads(); + + EXPECT_EQ(1, post_interceptor_1->GetHitCount()) + << post_interceptor_1->GetRequestsAsString(); + EXPECT_EQ(1, post_interceptor_1->GetCount()) + << post_interceptor_1->GetRequestsAsString(); + EXPECT_EQ(1, post_interceptor_2->GetHitCount()) + << post_interceptor_2->GetRequestsAsString(); + EXPECT_EQ(1, post_interceptor_2->GetCount()) + << post_interceptor_2->GetRequestsAsString(); + + EXPECT_STREQ("test", post_interceptor_1->GetRequests()[0].c_str()); + EXPECT_STREQ("test", post_interceptor_2->GetRequests()[0].c_str()); + EXPECT_EQ(GURL(kUrl2), url_fetcher_source_->GetOriginalURL()); + EXPECT_EQ(200, url_fetcher_source_->GetResponseCode()); +} + +// Tests that the request fails when both urls have failed. +TEST_F(RequestSenderTest, RequestSendFailed) { + EXPECT_TRUE(post_interceptor_1->ExpectRequest(new PartialMatch("test"), 403)); + EXPECT_TRUE(post_interceptor_2->ExpectRequest(new PartialMatch("test"), 403)); + + std::vector urls; + urls.push_back(GURL(kUrl1)); + urls.push_back(GURL(kUrl2)); + request_sender_.reset(new RequestSender(*config_)); + request_sender_->Send("test", urls, + base::Bind(&RequestSenderTest::RequestSenderComplete, + base::Unretained(this))); + RunThreads(); + + EXPECT_EQ(1, post_interceptor_1->GetHitCount()) + << post_interceptor_1->GetRequestsAsString(); + EXPECT_EQ(1, post_interceptor_1->GetCount()) + << post_interceptor_1->GetRequestsAsString(); + EXPECT_EQ(1, post_interceptor_2->GetHitCount()) + << post_interceptor_2->GetRequestsAsString(); + EXPECT_EQ(1, post_interceptor_2->GetCount()) + << post_interceptor_2->GetRequestsAsString(); + + EXPECT_STREQ("test", post_interceptor_1->GetRequests()[0].c_str()); + EXPECT_STREQ("test", post_interceptor_2->GetRequests()[0].c_str()); + EXPECT_EQ(GURL(kUrl2), url_fetcher_source_->GetOriginalURL()); + EXPECT_EQ(403, url_fetcher_source_->GetResponseCode()); +} + +} // namespace update_client diff --git a/components/update_client/test/DEPS b/components/update_client/test/DEPS deleted file mode 100644 index d0c36c4..0000000 --- a/components/update_client/test/DEPS +++ /dev/null @@ -1,5 +0,0 @@ -include_rules = [ - "+content", - "+courgette", - "+net", -] diff --git a/components/update_client/test/component_patcher_unittest.cc b/components/update_client/test/component_patcher_unittest.cc deleted file mode 100644 index 4f5e143..0000000 --- a/components/update_client/test/component_patcher_unittest.cc +++ /dev/null @@ -1,200 +0,0 @@ -// 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 "base/base_paths.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/compiler_specific.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "base/path_service.h" -#include "base/run_loop.h" -#include "base/values.h" -#include "components/update_client/component_patcher.h" -#include "components/update_client/component_patcher_operation.h" -#include "components/update_client/test/component_patcher_unittest.h" -#include "components/update_client/test/test_installer.h" -#include "courgette/courgette.h" -#include "courgette/third_party/bsdiff.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -class TestCallback { - public: - TestCallback(); - virtual ~TestCallback() {} - void Set(update_client::ComponentUnpacker::Error error, int extra_code); - - int error_; - int extra_code_; - bool called_; - - private: - DISALLOW_COPY_AND_ASSIGN(TestCallback); -}; - -TestCallback::TestCallback() : error_(-1), extra_code_(-1), called_(false) { -} - -void TestCallback::Set(update_client::ComponentUnpacker::Error error, - int extra_code) { - error_ = error; - extra_code_ = extra_code; - called_ = true; -} - -} // namespace - -namespace update_client { - -namespace { - -base::FilePath test_file(const char* file) { - base::FilePath path; - PathService::Get(base::DIR_SOURCE_ROOT, &path); - return path.AppendASCII("components") - .AppendASCII("test") - .AppendASCII("data") - .AppendASCII("update_client") - .AppendASCII(file); -} - -} // namespace - -ComponentPatcherOperationTest::ComponentPatcherOperationTest() { - EXPECT_TRUE(unpack_dir_.CreateUniqueTempDir()); - EXPECT_TRUE(input_dir_.CreateUniqueTempDir()); - EXPECT_TRUE(installed_dir_.CreateUniqueTempDir()); - installer_ = new ReadOnlyTestInstaller(installed_dir_.path()); - task_runner_ = base::MessageLoop::current()->task_runner(); -} - -ComponentPatcherOperationTest::~ComponentPatcherOperationTest() { -} - -// Verify that a 'create' delta update operation works correctly. -TEST_F(ComponentPatcherOperationTest, CheckCreateOperation) { - EXPECT_TRUE(base::CopyFile( - test_file("binary_output.bin"), - input_dir_.path().Append(FILE_PATH_LITERAL("binary_output.bin")))); - - scoped_ptr command_args(new base::DictionaryValue()); - command_args->SetString("output", "output.bin"); - command_args->SetString("sha256", binary_output_hash); - command_args->SetString("op", "create"); - command_args->SetString("patch", "binary_output.bin"); - - TestCallback callback; - scoped_refptr op = new DeltaUpdateOpCreate(); - op->Run(command_args.get(), input_dir_.path(), unpack_dir_.path(), NULL, - base::Bind(&TestCallback::Set, base::Unretained(&callback)), - task_runner_); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(true, callback.called_); - EXPECT_EQ(ComponentUnpacker::kNone, callback.error_); - EXPECT_EQ(0, callback.extra_code_); - EXPECT_TRUE(base::ContentsEqual( - unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")), - test_file("binary_output.bin"))); -} - -// Verify that a 'copy' delta update operation works correctly. -TEST_F(ComponentPatcherOperationTest, CheckCopyOperation) { - EXPECT_TRUE(base::CopyFile( - test_file("binary_output.bin"), - installed_dir_.path().Append(FILE_PATH_LITERAL("binary_output.bin")))); - - scoped_ptr command_args(new base::DictionaryValue()); - command_args->SetString("output", "output.bin"); - command_args->SetString("sha256", binary_output_hash); - command_args->SetString("op", "copy"); - command_args->SetString("input", "binary_output.bin"); - - TestCallback callback; - scoped_refptr op = new DeltaUpdateOpCopy(); - op->Run(command_args.get(), input_dir_.path(), unpack_dir_.path(), - installer_.get(), - base::Bind(&TestCallback::Set, base::Unretained(&callback)), - task_runner_); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(true, callback.called_); - EXPECT_EQ(ComponentUnpacker::kNone, callback.error_); - EXPECT_EQ(0, callback.extra_code_); - EXPECT_TRUE(base::ContentsEqual( - unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")), - test_file("binary_output.bin"))); -} - -// Verify that a 'courgette' delta update operation works correctly. -TEST_F(ComponentPatcherOperationTest, CheckCourgetteOperation) { - EXPECT_TRUE(base::CopyFile( - test_file("binary_input.bin"), - installed_dir_.path().Append(FILE_PATH_LITERAL("binary_input.bin")))); - EXPECT_TRUE(base::CopyFile(test_file("binary_courgette_patch.bin"), - input_dir_.path().Append(FILE_PATH_LITERAL( - "binary_courgette_patch.bin")))); - - scoped_ptr command_args(new base::DictionaryValue()); - command_args->SetString("output", "output.bin"); - command_args->SetString("sha256", binary_output_hash); - command_args->SetString("op", "courgette"); - command_args->SetString("input", "binary_input.bin"); - command_args->SetString("patch", "binary_courgette_patch.bin"); - - TestCallback callback; - scoped_refptr op = - CreateDeltaUpdateOp("courgette", NULL /* out_of_process_patcher */); - op->Run(command_args.get(), input_dir_.path(), unpack_dir_.path(), - installer_.get(), - base::Bind(&TestCallback::Set, base::Unretained(&callback)), - task_runner_); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(true, callback.called_); - EXPECT_EQ(ComponentUnpacker::kNone, callback.error_); - EXPECT_EQ(0, callback.extra_code_); - EXPECT_TRUE(base::ContentsEqual( - unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")), - test_file("binary_output.bin"))); -} - -// Verify that a 'bsdiff' delta update operation works correctly. -TEST_F(ComponentPatcherOperationTest, CheckBsdiffOperation) { - EXPECT_TRUE(base::CopyFile( - test_file("binary_input.bin"), - installed_dir_.path().Append(FILE_PATH_LITERAL("binary_input.bin")))); - EXPECT_TRUE(base::CopyFile( - test_file("binary_bsdiff_patch.bin"), - input_dir_.path().Append(FILE_PATH_LITERAL("binary_bsdiff_patch.bin")))); - - scoped_ptr command_args(new base::DictionaryValue()); - command_args->SetString("output", "output.bin"); - command_args->SetString("sha256", binary_output_hash); - command_args->SetString("op", "courgette"); - command_args->SetString("input", "binary_input.bin"); - command_args->SetString("patch", "binary_bsdiff_patch.bin"); - - TestCallback callback; - scoped_refptr op = - CreateDeltaUpdateOp("bsdiff", NULL /* out_of_process_patcher */); - op->Run(command_args.get(), input_dir_.path(), unpack_dir_.path(), - installer_.get(), - base::Bind(&TestCallback::Set, base::Unretained(&callback)), - task_runner_); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(true, callback.called_); - EXPECT_EQ(ComponentUnpacker::kNone, callback.error_); - EXPECT_EQ(0, callback.extra_code_); - EXPECT_TRUE(base::ContentsEqual( - unpack_dir_.path().Append(FILE_PATH_LITERAL("output.bin")), - test_file("binary_output.bin"))); -} - -} // namespace update_client diff --git a/components/update_client/test/component_patcher_unittest.h b/components/update_client/test/component_patcher_unittest.h deleted file mode 100644 index 2fcd5f5..0000000 --- a/components/update_client/test/component_patcher_unittest.h +++ /dev/null @@ -1,42 +0,0 @@ -// 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. - -#ifndef COMPONENTS_UPDATE_CLIENT_TEST_COMPONENT_PATCHER_UNITTEST_H_ -#define COMPONENTS_UPDATE_CLIENT_TEST_COMPONENT_PATCHER_UNITTEST_H_ - -#include "base/files/file_path.h" -#include "base/files/scoped_temp_dir.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "courgette/courgette.h" -#include "courgette/third_party/bsdiff.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace update_client { - -class MockComponentPatcher; -class ReadOnlyTestInstaller; - -const char binary_output_hash[] = - "599aba6d15a7da390621ef1bacb66601ed6aed04dadc1f9b445dcfe31296142a"; - -class ComponentPatcherOperationTest : public testing::Test { - public: - ComponentPatcherOperationTest(); - ~ComponentPatcherOperationTest() override; - - protected: - base::ScopedTempDir input_dir_; - base::ScopedTempDir installed_dir_; - base::ScopedTempDir unpack_dir_; - scoped_refptr installer_; - scoped_refptr task_runner_; - - private: - base::MessageLoopForIO loop_; -}; - -} // namespace update_client - -#endif // COMPONENTS_UPDATE_CLIENT_TEST_COMPONENT_PATCHER_UNITTEST_H_ diff --git a/components/update_client/test/crx_downloader_unittest.cc b/components/update_client/test/crx_downloader_unittest.cc deleted file mode 100644 index 4b80f13..0000000 --- a/components/update_client/test/crx_downloader_unittest.cc +++ /dev/null @@ -1,382 +0,0 @@ -// 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 "base/bind.h" -#include "base/bind_helpers.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/path_service.h" -#include "base/run_loop.h" -#include "components/update_client/crx_downloader.h" -#include "net/base/net_errors.h" -#include "net/url_request/test_url_request_interceptor.h" -#include "net/url_request/url_request_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::ContentsEqual; - -namespace update_client { - -namespace { - -// Intercepts HTTP GET requests sent to "localhost". -typedef net::LocalHostTestURLRequestInterceptor GetInterceptor; - -const char kTestFileName[] = "jebgalgnebhfojomionfpkfelancnnkf.crx"; - -base::FilePath MakeTestFilePath(const char* file) { - base::FilePath path; - PathService::Get(base::DIR_SOURCE_ROOT, &path); - return path.AppendASCII("components") - .AppendASCII("test") - .AppendASCII("data") - .AppendASCII("update_client") - .AppendASCII(file); -} - -} // namespace - -class CrxDownloaderTest : public testing::Test { - public: - CrxDownloaderTest(); - ~CrxDownloaderTest() override; - - // Overrides from testing::Test. - void SetUp() override; - void TearDown() override; - - void Quit(); - void RunThreads(); - void RunThreadsUntilIdle(); - - void DownloadComplete(int crx_context, const CrxDownloader::Result& result); - - void DownloadProgress(int crx_context, const CrxDownloader::Result& result); - - protected: - scoped_ptr crx_downloader_; - - scoped_ptr get_interceptor_; - - CrxDownloader::DownloadCallback callback_; - CrxDownloader::ProgressCallback progress_callback_; - - int crx_context_; - - int num_download_complete_calls_; - CrxDownloader::Result download_complete_result_; - - // These members are updated by DownloadProgress. - int num_progress_calls_; - CrxDownloader::Result download_progress_result_; - - // A magic value for the context to be used in the tests. - static const int kExpectedContext = 0xaabb; - - private: - base::MessageLoopForIO loop_; - scoped_refptr context_; - base::Closure quit_closure_; -}; - -const int CrxDownloaderTest::kExpectedContext; - -CrxDownloaderTest::CrxDownloaderTest() - : callback_(base::Bind(&CrxDownloaderTest::DownloadComplete, - base::Unretained(this), - kExpectedContext)), - progress_callback_(base::Bind(&CrxDownloaderTest::DownloadProgress, - base::Unretained(this), - kExpectedContext)), - crx_context_(0), - num_download_complete_calls_(0), - num_progress_calls_(0), - context_(new net::TestURLRequestContextGetter( - base::MessageLoopProxy::current())) { -} - -CrxDownloaderTest::~CrxDownloaderTest() { - context_ = NULL; - - // The GetInterceptor requires the message loop to run to destruct correctly. - get_interceptor_.reset(); - RunThreadsUntilIdle(); -} - -void CrxDownloaderTest::SetUp() { - num_download_complete_calls_ = 0; - download_complete_result_ = CrxDownloader::Result(); - num_progress_calls_ = 0; - download_progress_result_ = CrxDownloader::Result(); - - // Do not use the background downloader in these tests. - crx_downloader_.reset(CrxDownloader::Create(false, context_.get(), - base::MessageLoopProxy::current(), - NULL).release()); - crx_downloader_->set_progress_callback(progress_callback_); - - get_interceptor_.reset(new GetInterceptor(base::MessageLoopProxy::current(), - base::MessageLoopProxy::current())); -} - -void CrxDownloaderTest::TearDown() { - crx_downloader_.reset(); -} - -void CrxDownloaderTest::Quit() { - if (!quit_closure_.is_null()) - quit_closure_.Run(); -} - -void CrxDownloaderTest::DownloadComplete(int crx_context, - const CrxDownloader::Result& result) { - ++num_download_complete_calls_; - crx_context_ = crx_context; - download_complete_result_ = result; - Quit(); -} - -void CrxDownloaderTest::DownloadProgress(int crx_context, - const CrxDownloader::Result& result) { - ++num_progress_calls_; - download_progress_result_ = result; -} - -void CrxDownloaderTest::RunThreads() { - base::RunLoop runloop; - quit_closure_ = runloop.QuitClosure(); - runloop.Run(); - - // Since some tests need to drain currently enqueued tasks such as network - // intercepts on the IO thread, run the threads until they are - // idle. The component updater service won't loop again until the loop count - // is set and the service is started. - RunThreadsUntilIdle(); -} - -void CrxDownloaderTest::RunThreadsUntilIdle() { - base::RunLoop().RunUntilIdle(); -} - -// Tests that starting a download without a url results in an error. -TEST_F(CrxDownloaderTest, NoUrl) { - std::vector urls; - crx_downloader_->StartDownload(urls, callback_); - RunThreadsUntilIdle(); - - EXPECT_EQ(1, num_download_complete_calls_); - EXPECT_EQ(kExpectedContext, crx_context_); - EXPECT_EQ(-1, download_complete_result_.error); - EXPECT_TRUE(download_complete_result_.response.empty()); - EXPECT_EQ(-1, download_complete_result_.downloaded_bytes); - EXPECT_EQ(-1, download_complete_result_.total_bytes); - EXPECT_EQ(0, num_progress_calls_); -} - -// Tests that downloading from one url is successful. -TEST_F(CrxDownloaderTest, OneUrl) { - const GURL expected_crx_url = - GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); - - const base::FilePath test_file(MakeTestFilePath(kTestFileName)); - get_interceptor_->SetResponse(expected_crx_url, test_file); - - crx_downloader_->StartDownloadFromUrl(expected_crx_url, callback_); - RunThreads(); - - EXPECT_EQ(1, get_interceptor_->GetHitCount()); - - EXPECT_EQ(1, num_download_complete_calls_); - EXPECT_EQ(kExpectedContext, crx_context_); - EXPECT_EQ(0, download_complete_result_.error); - EXPECT_EQ(1843, download_complete_result_.downloaded_bytes); - EXPECT_EQ(1843, download_complete_result_.total_bytes); - EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file)); - - EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false)); - - EXPECT_LE(1, num_progress_calls_); - EXPECT_EQ(1843, download_progress_result_.downloaded_bytes); - EXPECT_EQ(1843, download_progress_result_.total_bytes); -} - -// Tests that specifying from two urls has no side effects. Expect a successful -// download, and only one download request be made. -// This test is flaky on Android. crbug.com/329883 -#if defined(OS_ANDROID) -#define MAYBE_TwoUrls DISABLED_TwoUrls -#else -#define MAYBE_TwoUrls TwoUrls -#endif -TEST_F(CrxDownloaderTest, MAYBE_TwoUrls) { - const GURL expected_crx_url = - GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); - - const base::FilePath test_file(MakeTestFilePath(kTestFileName)); - get_interceptor_->SetResponse(expected_crx_url, test_file); - - std::vector urls; - urls.push_back(expected_crx_url); - urls.push_back(expected_crx_url); - - crx_downloader_->StartDownload(urls, callback_); - RunThreads(); - - EXPECT_EQ(1, get_interceptor_->GetHitCount()); - - EXPECT_EQ(1, num_download_complete_calls_); - EXPECT_EQ(kExpectedContext, crx_context_); - EXPECT_EQ(0, download_complete_result_.error); - EXPECT_EQ(1843, download_complete_result_.downloaded_bytes); - EXPECT_EQ(1843, download_complete_result_.total_bytes); - EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file)); - - EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false)); - - EXPECT_LE(1, num_progress_calls_); - EXPECT_EQ(1843, download_progress_result_.downloaded_bytes); - EXPECT_EQ(1843, download_progress_result_.total_bytes); -} - -// Tests that an invalid host results in a download error. -TEST_F(CrxDownloaderTest, OneUrl_InvalidHost) { - const GURL expected_crx_url = - GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); - - const base::FilePath test_file(MakeTestFilePath(kTestFileName)); - get_interceptor_->SetResponse(expected_crx_url, test_file); - - crx_downloader_->StartDownloadFromUrl( - GURL( - "http://no.such.host" - "/download/jebgalgnebhfojomionfpkfelancnnkf.crx"), - callback_); - RunThreads(); - - EXPECT_EQ(0, get_interceptor_->GetHitCount()); - - EXPECT_EQ(1, num_download_complete_calls_); - EXPECT_EQ(kExpectedContext, crx_context_); - EXPECT_NE(0, download_complete_result_.error); - EXPECT_TRUE(download_complete_result_.response.empty()); -} - -// Tests that an invalid path results in a download error. -TEST_F(CrxDownloaderTest, OneUrl_InvalidPath) { - const GURL expected_crx_url = - GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); - - const base::FilePath test_file(MakeTestFilePath(kTestFileName)); - get_interceptor_->SetResponse(expected_crx_url, test_file); - - crx_downloader_->StartDownloadFromUrl(GURL("http://localhost/no/such/file"), - callback_); - RunThreads(); - - EXPECT_EQ(0, get_interceptor_->GetHitCount()); - - EXPECT_EQ(1, num_download_complete_calls_); - EXPECT_EQ(kExpectedContext, crx_context_); - EXPECT_NE(0, download_complete_result_.error); - EXPECT_TRUE(download_complete_result_.response.empty()); -} - -// Tests that the fallback to a valid url is successful. -// This test is flaky on Android. crbug.com/329883 -#if defined(OS_ANDROID) -#define MAYBE_TwoUrls_FirstInvalid DISABLED_TwoUrls_FirstInvalid -#else -#define MAYBE_TwoUrls_FirstInvalid TwoUrls_FirstInvalid -#endif -TEST_F(CrxDownloaderTest, MAYBE_TwoUrls_FirstInvalid) { - const GURL expected_crx_url = - GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); - - const base::FilePath test_file(MakeTestFilePath(kTestFileName)); - get_interceptor_->SetResponse(expected_crx_url, test_file); - - std::vector urls; - urls.push_back(GURL("http://localhost/no/such/file")); - urls.push_back(expected_crx_url); - - crx_downloader_->StartDownload(urls, callback_); - RunThreads(); - - EXPECT_EQ(1, get_interceptor_->GetHitCount()); - - EXPECT_EQ(1, num_download_complete_calls_); - EXPECT_EQ(kExpectedContext, crx_context_); - EXPECT_EQ(0, download_complete_result_.error); - EXPECT_EQ(1843, download_complete_result_.downloaded_bytes); - EXPECT_EQ(1843, download_complete_result_.total_bytes); - EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file)); - - EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false)); - - EXPECT_LE(1, num_progress_calls_); - EXPECT_EQ(1843, download_progress_result_.downloaded_bytes); - EXPECT_EQ(1843, download_progress_result_.total_bytes); -} - -// Tests that the download succeeds if the first url is correct and the -// second bad url does not have a side-effect. -TEST_F(CrxDownloaderTest, TwoUrls_SecondInvalid) { - const GURL expected_crx_url = - GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); - - const base::FilePath test_file(MakeTestFilePath(kTestFileName)); - get_interceptor_->SetResponse(expected_crx_url, test_file); - - std::vector urls; - urls.push_back(expected_crx_url); - urls.push_back(GURL("http://localhost/no/such/file")); - - crx_downloader_->StartDownload(urls, callback_); - RunThreads(); - - EXPECT_EQ(1, get_interceptor_->GetHitCount()); - - EXPECT_EQ(1, num_download_complete_calls_); - EXPECT_EQ(kExpectedContext, crx_context_); - EXPECT_EQ(0, download_complete_result_.error); - EXPECT_EQ(1843, download_complete_result_.downloaded_bytes); - EXPECT_EQ(1843, download_complete_result_.total_bytes); - EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file)); - - EXPECT_TRUE(base::DeleteFile(download_complete_result_.response, false)); - - EXPECT_LE(1, num_progress_calls_); - EXPECT_EQ(1843, download_progress_result_.downloaded_bytes); - EXPECT_EQ(1843, download_progress_result_.total_bytes); -} - -// Tests that the download fails if both urls are bad. -TEST_F(CrxDownloaderTest, TwoUrls_BothInvalid) { - const GURL expected_crx_url = - GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx"); - - const base::FilePath test_file(MakeTestFilePath(kTestFileName)); - get_interceptor_->SetResponse(expected_crx_url, test_file); - - std::vector urls; - urls.push_back(GURL("http://localhost/no/such/file")); - urls.push_back(GURL( - "http://no.such.host/" - "/download/jebgalgnebhfojomionfpkfelancnnkf.crx")); - - crx_downloader_->StartDownload(urls, callback_); - RunThreads(); - - EXPECT_EQ(0, get_interceptor_->GetHitCount()); - - EXPECT_EQ(1, num_download_complete_calls_); - EXPECT_EQ(kExpectedContext, crx_context_); - EXPECT_NE(0, download_complete_result_.error); - EXPECT_TRUE(download_complete_result_.response.empty()); -} - -} // namespace update_client diff --git a/components/update_client/test/ping_manager_unittest.cc b/components/update_client/test/ping_manager_unittest.cc deleted file mode 100644 index 23308ac..0000000 --- a/components/update_client/test/ping_manager_unittest.cc +++ /dev/null @@ -1,178 +0,0 @@ -// 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 "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "base/version.h" -#include "components/update_client/crx_update_item.h" -#include "components/update_client/ping_manager.h" -#include "components/update_client/test/test_configurator.h" -#include "components/update_client/test/url_request_post_interceptor.h" -#include "net/url_request/url_request_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -using std::string; - -namespace update_client { - -class ComponentUpdaterPingManagerTest : public testing::Test { - public: - ComponentUpdaterPingManagerTest(); - ~ComponentUpdaterPingManagerTest() override {} - - void RunThreadsUntilIdle(); - - // Overrides from testing::Test. - void SetUp() override; - void TearDown() override; - - protected: - scoped_refptr config_; - scoped_ptr ping_manager_; - - private: - base::MessageLoopForIO loop_; -}; - -ComponentUpdaterPingManagerTest::ComponentUpdaterPingManagerTest() { -} - -void ComponentUpdaterPingManagerTest::SetUp() { - config_ = new TestConfigurator(base::MessageLoopProxy::current(), - base::MessageLoopProxy::current()); - ping_manager_.reset(new PingManager(*config_)); -} - -void ComponentUpdaterPingManagerTest::TearDown() { - ping_manager_.reset(); - config_ = nullptr; -} - -void ComponentUpdaterPingManagerTest::RunThreadsUntilIdle() { - base::RunLoop().RunUntilIdle(); -} - -// Test is flaky: http://crbug.com/349547 -TEST_F(ComponentUpdaterPingManagerTest, DISABLED_PingManagerTest) { - scoped_ptr interceptor_factory( - new InterceptorFactory(base::MessageLoopProxy::current())); - URLRequestPostInterceptor* interceptor = - interceptor_factory->CreateInterceptor(); - EXPECT_TRUE(interceptor); - - // Test eventresult="1" is sent for successful updates. - CrxUpdateItem item; - item.id = "abc"; - item.state = CrxUpdateItem::State::kUpdated; - item.previous_version = base::Version("1.0"); - item.next_version = base::Version("2.0"); - - ping_manager_->OnUpdateComplete(&item); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString(); - EXPECT_NE(string::npos, - interceptor->GetRequests()[0].find( - "" - "")) - << interceptor->GetRequestsAsString(); - interceptor->Reset(); - - // Test eventresult="0" is sent for failed updates. - item = CrxUpdateItem(); - item.id = "abc"; - item.state = CrxUpdateItem::State::kNoUpdate; - item.previous_version = base::Version("1.0"); - item.next_version = base::Version("2.0"); - - ping_manager_->OnUpdateComplete(&item); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString(); - EXPECT_NE(string::npos, - interceptor->GetRequests()[0].find( - "" - "")) - << interceptor->GetRequestsAsString(); - interceptor->Reset(); - - // Test the error values and the fingerprints. - item = CrxUpdateItem(); - item.id = "abc"; - item.state = CrxUpdateItem::State::kNoUpdate; - item.previous_version = base::Version("1.0"); - item.next_version = base::Version("2.0"); - item.previous_fp = "prev fp"; - item.next_fp = "next fp"; - item.error_category = 1; - item.error_code = 2; - item.extra_code1 = -1; - item.diff_error_category = 10; - item.diff_error_code = 20; - item.diff_extra_code1 = -10; - item.diff_update_failed = true; - item.crx_diffurls.push_back(GURL("http://host/path")); - - ping_manager_->OnUpdateComplete(&item); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString(); - EXPECT_NE(string::npos, - interceptor->GetRequests()[0].find( - "" - "")) - << interceptor->GetRequestsAsString(); - interceptor->Reset(); - - // Test the download metrics. - item = CrxUpdateItem(); - item.id = "abc"; - item.state = CrxUpdateItem::State::kUpdated; - item.previous_version = base::Version("1.0"); - item.next_version = base::Version("2.0"); - - CrxDownloader::DownloadMetrics download_metrics; - download_metrics.url = GURL("http://host1/path1"); - download_metrics.downloader = CrxDownloader::DownloadMetrics::kUrlFetcher; - download_metrics.error = -1; - download_metrics.downloaded_bytes = 123; - download_metrics.total_bytes = 456; - download_metrics.download_time_ms = 987; - item.download_metrics.push_back(download_metrics); - - download_metrics = CrxDownloader::DownloadMetrics(); - download_metrics.url = GURL("http://host2/path2"); - download_metrics.downloader = CrxDownloader::DownloadMetrics::kBits; - download_metrics.error = 0; - download_metrics.downloaded_bytes = 1230; - download_metrics.total_bytes = 4560; - download_metrics.download_time_ms = 9870; - item.download_metrics.push_back(download_metrics); - - ping_manager_->OnUpdateComplete(&item); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString(); - EXPECT_NE( - string::npos, - interceptor->GetRequests()[0].find( - "" - "" - "" - "")) - << interceptor->GetRequestsAsString(); - interceptor->Reset(); -} - -} // namespace update_client diff --git a/components/update_client/test/request_sender_unittest.cc b/components/update_client/test/request_sender_unittest.cc deleted file mode 100644 index 35d4487..0000000 --- a/components/update_client/test/request_sender_unittest.cc +++ /dev/null @@ -1,206 +0,0 @@ -// 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 "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/run_loop.h" -#include "components/update_client/request_sender.h" -#include "components/update_client/test/test_configurator.h" -#include "components/update_client/test/url_request_post_interceptor.h" -#include "net/url_request/url_fetcher.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace update_client { - -namespace { - -const char kUrl1[] = "https://localhost2/path1"; -const char kUrl2[] = "https://localhost2/path2"; -const char kUrlPath1[] = "path1"; -const char kUrlPath2[] = "path2"; - -} // namespace - -class RequestSenderTest : public testing::Test { - public: - RequestSenderTest(); - ~RequestSenderTest() override; - - // Overrides from testing::Test. - void SetUp() override; - void TearDown() override; - - void RequestSenderComplete(const net::URLFetcher* source); - - protected: - void Quit(); - void RunThreads(); - void RunThreadsUntilIdle(); - - scoped_refptr config_; - scoped_ptr request_sender_; - scoped_ptr interceptor_factory_; - - URLRequestPostInterceptor* post_interceptor_1; // Owned by the factory. - URLRequestPostInterceptor* post_interceptor_2; // Owned by the factory. - - const net::URLFetcher* url_fetcher_source_; - - private: - base::MessageLoopForIO loop_; - base::Closure quit_closure_; - - DISALLOW_COPY_AND_ASSIGN(RequestSenderTest); -}; - -RequestSenderTest::RequestSenderTest() - : post_interceptor_1(NULL), - post_interceptor_2(NULL), - url_fetcher_source_(NULL) { -} - -RequestSenderTest::~RequestSenderTest() { -} - -void RequestSenderTest::SetUp() { - config_ = new TestConfigurator(base::MessageLoopProxy::current(), - base::MessageLoopProxy::current()); - interceptor_factory_.reset( - new InterceptorFactory(base::MessageLoopProxy::current())); - post_interceptor_1 = - interceptor_factory_->CreateInterceptorForPath(kUrlPath1); - post_interceptor_2 = - interceptor_factory_->CreateInterceptorForPath(kUrlPath2); - EXPECT_TRUE(post_interceptor_1); - EXPECT_TRUE(post_interceptor_2); - - request_sender_.reset(); -} - -void RequestSenderTest::TearDown() { - request_sender_.reset(); - - post_interceptor_1 = NULL; - post_interceptor_2 = NULL; - - interceptor_factory_.reset(); - - config_ = nullptr; - - RunThreadsUntilIdle(); -} - -void RequestSenderTest::RunThreads() { - base::RunLoop runloop; - quit_closure_ = runloop.QuitClosure(); - runloop.Run(); - - // Since some tests need to drain currently enqueued tasks such as network - // intercepts on the IO thread, run the threads until they are - // idle. The component updater service won't loop again until the loop count - // is set and the service is started. - RunThreadsUntilIdle(); -} - -void RequestSenderTest::RunThreadsUntilIdle() { - base::RunLoop().RunUntilIdle(); -} - -void RequestSenderTest::Quit() { - if (!quit_closure_.is_null()) - quit_closure_.Run(); -} - -void RequestSenderTest::RequestSenderComplete(const net::URLFetcher* source) { - url_fetcher_source_ = source; - Quit(); -} - -// Tests that when a request to the first url succeeds, the subsequent urls are -// not tried. -TEST_F(RequestSenderTest, RequestSendSuccess) { - EXPECT_TRUE(post_interceptor_1->ExpectRequest(new PartialMatch("test"))); - - std::vector urls; - urls.push_back(GURL(kUrl1)); - urls.push_back(GURL(kUrl2)); - request_sender_.reset(new RequestSender(*config_)); - request_sender_->Send("test", urls, - base::Bind(&RequestSenderTest::RequestSenderComplete, - base::Unretained(this))); - RunThreads(); - - EXPECT_EQ(1, post_interceptor_1->GetHitCount()) - << post_interceptor_1->GetRequestsAsString(); - EXPECT_EQ(1, post_interceptor_1->GetCount()) - << post_interceptor_1->GetRequestsAsString(); - - EXPECT_STREQ("test", post_interceptor_1->GetRequests()[0].c_str()); - EXPECT_EQ(GURL(kUrl1), url_fetcher_source_->GetOriginalURL()); - EXPECT_EQ(200, url_fetcher_source_->GetResponseCode()); -} - -// Tests that the request succeeds using the second url after the first url -// has failed. -TEST_F(RequestSenderTest, RequestSendSuccessWithFallback) { - EXPECT_TRUE(post_interceptor_1->ExpectRequest(new PartialMatch("test"), 403)); - EXPECT_TRUE(post_interceptor_2->ExpectRequest(new PartialMatch("test"))); - - std::vector urls; - urls.push_back(GURL(kUrl1)); - urls.push_back(GURL(kUrl2)); - request_sender_.reset(new RequestSender(*config_)); - request_sender_->Send("test", urls, - base::Bind(&RequestSenderTest::RequestSenderComplete, - base::Unretained(this))); - RunThreads(); - - EXPECT_EQ(1, post_interceptor_1->GetHitCount()) - << post_interceptor_1->GetRequestsAsString(); - EXPECT_EQ(1, post_interceptor_1->GetCount()) - << post_interceptor_1->GetRequestsAsString(); - EXPECT_EQ(1, post_interceptor_2->GetHitCount()) - << post_interceptor_2->GetRequestsAsString(); - EXPECT_EQ(1, post_interceptor_2->GetCount()) - << post_interceptor_2->GetRequestsAsString(); - - EXPECT_STREQ("test", post_interceptor_1->GetRequests()[0].c_str()); - EXPECT_STREQ("test", post_interceptor_2->GetRequests()[0].c_str()); - EXPECT_EQ(GURL(kUrl2), url_fetcher_source_->GetOriginalURL()); - EXPECT_EQ(200, url_fetcher_source_->GetResponseCode()); -} - -// Tests that the request fails when both urls have failed. -TEST_F(RequestSenderTest, RequestSendFailed) { - EXPECT_TRUE(post_interceptor_1->ExpectRequest(new PartialMatch("test"), 403)); - EXPECT_TRUE(post_interceptor_2->ExpectRequest(new PartialMatch("test"), 403)); - - std::vector urls; - urls.push_back(GURL(kUrl1)); - urls.push_back(GURL(kUrl2)); - request_sender_.reset(new RequestSender(*config_)); - request_sender_->Send("test", urls, - base::Bind(&RequestSenderTest::RequestSenderComplete, - base::Unretained(this))); - RunThreads(); - - EXPECT_EQ(1, post_interceptor_1->GetHitCount()) - << post_interceptor_1->GetRequestsAsString(); - EXPECT_EQ(1, post_interceptor_1->GetCount()) - << post_interceptor_1->GetRequestsAsString(); - EXPECT_EQ(1, post_interceptor_2->GetHitCount()) - << post_interceptor_2->GetRequestsAsString(); - EXPECT_EQ(1, post_interceptor_2->GetCount()) - << post_interceptor_2->GetRequestsAsString(); - - EXPECT_STREQ("test", post_interceptor_1->GetRequests()[0].c_str()); - EXPECT_STREQ("test", post_interceptor_2->GetRequests()[0].c_str()); - EXPECT_EQ(GURL(kUrl2), url_fetcher_source_->GetOriginalURL()); - EXPECT_EQ(403, url_fetcher_source_->GetResponseCode()); -} - -} // namespace update_client diff --git a/components/update_client/test/test_configurator.cc b/components/update_client/test/test_configurator.cc deleted file mode 100644 index 23eaeff..0000000 --- a/components/update_client/test/test_configurator.cc +++ /dev/null @@ -1,158 +0,0 @@ -// 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 "components/update_client/test/test_configurator.h" - -#include "base/run_loop.h" -#include "base/version.h" -#include "components/update_client/component_patcher_operation.h" -#include "url/gurl.h" - -namespace update_client { - -namespace { - -std::vector MakeDefaultUrls() { - std::vector urls; - urls.push_back(GURL(POST_INTERCEPT_SCHEME - "://" POST_INTERCEPT_HOSTNAME POST_INTERCEPT_PATH)); - return urls; -} - -} // namespace - -TestConfigurator::TestConfigurator( - const scoped_refptr& worker_task_runner, - const scoped_refptr& network_task_runner) - : worker_task_runner_(worker_task_runner), - initial_time_(0), - times_(1), - recheck_time_(0), - ondemand_time_(0), - context_(new net::TestURLRequestContextGetter(network_task_runner)) { -} - -TestConfigurator::~TestConfigurator() { -} - -int TestConfigurator::InitialDelay() const { - return initial_time_; -} - -int TestConfigurator::NextCheckDelay() { - // This is called when a new full cycle of checking for updates is going - // to happen. In test we normally only test one cycle so it is a good - // time to break from the test messageloop Run() method so the test can - // finish. - if (--times_ <= 0) { - quit_closure_.Run(); - return 0; - } - return 1; -} - -int TestConfigurator::StepDelay() const { - return 0; -} - -int TestConfigurator::StepDelayMedium() { - return NextCheckDelay(); -} - -int TestConfigurator::MinimumReCheckWait() const { - return recheck_time_; -} - -int TestConfigurator::OnDemandDelay() const { - return ondemand_time_; -} - -int TestConfigurator::UpdateDelay() const { - return 1; -} - -std::vector TestConfigurator::UpdateUrl() const { - return MakeDefaultUrls(); -} - -std::vector TestConfigurator::PingUrl() const { - return UpdateUrl(); -} - -base::Version TestConfigurator::GetBrowserVersion() const { - // Needs to be larger than the required version in tested component manifests. - return base::Version("30.0"); -} - -std::string TestConfigurator::GetChannel() const { - return "fake_channel_string"; -} - -std::string TestConfigurator::GetLang() const { - return "fake_lang"; -} - -std::string TestConfigurator::GetOSLongName() const { - return "Fake Operating System"; -} - -std::string TestConfigurator::ExtraRequestParams() const { - return "extra=\"foo\""; -} - -size_t TestConfigurator::UrlSizeLimit() const { - return 256; -} - -net::URLRequestContextGetter* TestConfigurator::RequestContext() const { - return context_.get(); -} - -scoped_refptr TestConfigurator::CreateOutOfProcessPatcher() - const { - return NULL; -} - -bool TestConfigurator::DeltasEnabled() const { - return true; -} - -bool TestConfigurator::UseBackgroundDownloader() const { - return false; -} - -// Set how many update checks are called, the default value is just once. -void TestConfigurator::SetLoopCount(int times) { - times_ = times; -} - -void TestConfigurator::SetRecheckTime(int seconds) { - recheck_time_ = seconds; -} - -void TestConfigurator::SetOnDemandTime(int seconds) { - ondemand_time_ = seconds; -} - -void TestConfigurator::SetQuitClosure(const base::Closure& quit_closure) { - quit_closure_ = quit_closure; -} - -void TestConfigurator::SetInitialDelay(int seconds) { - initial_time_ = seconds; -} - -scoped_refptr -TestConfigurator::GetSequencedTaskRunner() const { - DCHECK(worker_task_runner_.get()); - return worker_task_runner_; -} - -scoped_refptr -TestConfigurator::GetSingleThreadTaskRunner() const { - // This is NULL because tests do not use the background downloader. - return NULL; -} - -} // namespace update_client diff --git a/components/update_client/test/test_configurator.h b/components/update_client/test/test_configurator.h deleted file mode 100644 index 6c2ed0e..0000000 --- a/components/update_client/test/test_configurator.h +++ /dev/null @@ -1,111 +0,0 @@ -// 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. - -#ifndef COMPONENTS_UPDATE_CLIENT_TEST_TEST_CONFIGURATOR_H_ -#define COMPONENTS_UPDATE_CLIENT_TEST_TEST_CONFIGURATOR_H_ - -#include -#include -#include - -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "components/update_client/configurator.h" -#include "net/url_request/url_request_test_util.h" - -class GURL; - -namespace base { -class SequencedTaskRunner; -class SingleThreadTaskRunner; -} // namespace base - -namespace update_client { - -#define POST_INTERCEPT_SCHEME "https" -#define POST_INTERCEPT_HOSTNAME "localhost2" -#define POST_INTERCEPT_PATH "/update2" - -struct CrxComponent; - -// component 1 has extension id "jebgalgnebhfojomionfpkfelancnnkf", and -// the RSA public key the following hash: -const uint8_t jebg_hash[] = {0x94, 0x16, 0x0b, 0x6d, 0x41, 0x75, 0xe9, 0xec, - 0x8e, 0xd5, 0xfa, 0x54, 0xb0, 0xd2, 0xdd, 0xa5, - 0x6e, 0x05, 0x6b, 0xe8, 0x73, 0x47, 0xf6, 0xc4, - 0x11, 0x9f, 0xbc, 0xb3, 0x09, 0xb3, 0x5b, 0x40}; -// component 2 has extension id "abagagagagagagagagagagagagagagag", and -// the RSA public key the following hash: -const uint8_t abag_hash[] = {0x01, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01}; -// component 3 has extension id "ihfokbkgjpifnbbojhneepfflplebdkc", and -// the RSA public key the following hash: -const uint8_t ihfo_hash[] = {0x87, 0x5e, 0xa1, 0xa6, 0x9f, 0x85, 0xd1, 0x1e, - 0x97, 0xd4, 0x4f, 0x55, 0xbf, 0xb4, 0x13, 0xa2, - 0xe7, 0xc5, 0xc8, 0xf5, 0x60, 0x19, 0x78, 0x1b, - 0x6d, 0xe9, 0x4c, 0xeb, 0x96, 0x05, 0x42, 0x17}; - -class TestConfigurator : public Configurator { - public: - TestConfigurator( - const scoped_refptr& worker_task_runner, - const scoped_refptr& network_task_runner); - - // Overrrides for Configurator. - int InitialDelay() const override; - int NextCheckDelay() override; - int StepDelay() const override; - int StepDelayMedium() override; - int MinimumReCheckWait() const override; - int OnDemandDelay() const override; - int UpdateDelay() const override; - std::vector UpdateUrl() const override; - std::vector PingUrl() const override; - base::Version GetBrowserVersion() const override; - std::string GetChannel() const override; - std::string GetLang() const override; - std::string GetOSLongName() const override; - std::string ExtraRequestParams() const override; - size_t UrlSizeLimit() const override; - net::URLRequestContextGetter* RequestContext() const override; - scoped_refptr CreateOutOfProcessPatcher() const override; - bool DeltasEnabled() const override; - bool UseBackgroundDownloader() const override; - scoped_refptr GetSequencedTaskRunner() - const override; - scoped_refptr GetSingleThreadTaskRunner() - const override; - - void SetLoopCount(int times); - void SetRecheckTime(int seconds); - void SetOnDemandTime(int seconds); - void SetQuitClosure(const base::Closure& quit_closure); - void SetInitialDelay(int seconds); - - private: - friend class base::RefCountedThreadSafe; - - ~TestConfigurator() override; - - scoped_refptr worker_task_runner_; - scoped_refptr network_task_runner_; - - int initial_time_; - int times_; - int recheck_time_; - int ondemand_time_; - - scoped_refptr context_; - base::Closure quit_closure_; - - DISALLOW_COPY_AND_ASSIGN(TestConfigurator); -}; - -} // namespace update_client - -#endif // COMPONENTS_UPDATE_CLIENT_TEST_TEST_CONFIGURATOR_H_ diff --git a/components/update_client/test/test_installer.cc b/components/update_client/test/test_installer.cc deleted file mode 100644 index 6c03f49..0000000 --- a/components/update_client/test/test_installer.cc +++ /dev/null @@ -1,85 +0,0 @@ -// 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 "components/update_client/test/test_installer.h" - -#include - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/values.h" - -namespace update_client { - -TestInstaller::TestInstaller() : error_(0), install_count_(0) { -} - -void TestInstaller::OnUpdateError(int error) { - error_ = error; -} - -bool TestInstaller::Install(const base::DictionaryValue& manifest, - const base::FilePath& unpack_path) { - ++install_count_; - return base::DeleteFile(unpack_path, true); -} - -bool TestInstaller::GetInstalledFile(const std::string& file, - base::FilePath* installed_file) { - return false; -} - -TestInstaller::~TestInstaller() { -} - -bool TestInstaller::Uninstall() { - return false; -} - -ReadOnlyTestInstaller::ReadOnlyTestInstaller(const base::FilePath& install_dir) - : install_directory_(install_dir) { -} - -ReadOnlyTestInstaller::~ReadOnlyTestInstaller() { -} - -bool ReadOnlyTestInstaller::GetInstalledFile(const std::string& file, - base::FilePath* installed_file) { - *installed_file = install_directory_.AppendASCII(file); - return true; -} - -VersionedTestInstaller::VersionedTestInstaller() { - base::CreateNewTempDirectory(FILE_PATH_LITERAL("TEST_"), &install_directory_); -} - -VersionedTestInstaller::~VersionedTestInstaller() { - base::DeleteFile(install_directory_, true); -} - -bool VersionedTestInstaller::Install(const base::DictionaryValue& manifest, - const base::FilePath& unpack_path) { - std::string version_string; - manifest.GetStringASCII("version", &version_string); - Version version(version_string.c_str()); - - base::FilePath path; - path = install_directory_.AppendASCII(version.GetString()); - base::CreateDirectory(path.DirName()); - if (!base::Move(unpack_path, path)) - return false; - current_version_ = version; - ++install_count_; - return true; -} - -bool VersionedTestInstaller::GetInstalledFile(const std::string& file, - base::FilePath* installed_file) { - base::FilePath path; - path = install_directory_.AppendASCII(current_version_.GetString()); - *installed_file = path.Append(base::FilePath::FromUTF8Unsafe(file)); - return true; -} - -} // namespace update_client diff --git a/components/update_client/test/test_installer.h b/components/update_client/test/test_installer.h deleted file mode 100644 index e15ae0a..0000000 --- a/components/update_client/test/test_installer.h +++ /dev/null @@ -1,88 +0,0 @@ -// 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. - -#ifndef COMPONENTS_UPDATE_CLIENT_TEST_TEST_INSTALLER_H_ -#define COMPONENTS_UPDATE_CLIENT_TEST_TEST_INSTALLER_H_ - -#include - -#include "base/compiler_specific.h" -#include "base/files/file_path.h" -#include "components/update_client/update_client.h" - -namespace base { -class DictionaryValue; -} - -namespace update_client { - -// TODO(sorin): consider reducing the number of the installer mocks. -// A TestInstaller is an installer that does nothing for installation except -// increment a counter. -class TestInstaller : public CrxInstaller { - public: - TestInstaller(); - - void OnUpdateError(int error) override; - - bool Install(const base::DictionaryValue& manifest, - const base::FilePath& unpack_path) override; - - bool GetInstalledFile(const std::string& file, - base::FilePath* installed_file) override; - - bool Uninstall() override; - - int error() const { - return error_; - } - - int install_count() const { - return install_count_; - } - - protected: - ~TestInstaller() override; - - int error_; - int install_count_; -}; - -// A ReadOnlyTestInstaller is an installer that knows about files in an existing -// directory. It will not write to the directory. -class ReadOnlyTestInstaller : public TestInstaller { - public: - explicit ReadOnlyTestInstaller(const base::FilePath& installed_path); - - bool GetInstalledFile(const std::string& file, - base::FilePath* installed_file) override; - - private: - ~ReadOnlyTestInstaller() override; - - base::FilePath install_directory_; -}; - -// A VersionedTestInstaller is an installer that installs files into versioned -// directories (e.g. somedir/25.23.89.141/). -class VersionedTestInstaller : public TestInstaller { - public: - VersionedTestInstaller(); - - bool Install(const base::DictionaryValue& manifest, - const base::FilePath& unpack_path) override; - - bool GetInstalledFile(const std::string& file, - base::FilePath* installed_file) override; - - private: - ~VersionedTestInstaller() override; - - base::FilePath install_directory_; - Version current_version_; -}; - -} // namespace update_client - -#endif // COMPONENTS_UPDATE_CLIENT_TEST_TEST_INSTALLER_H_ diff --git a/components/update_client/test/update_checker_unittest.cc b/components/update_client/test/update_checker_unittest.cc deleted file mode 100644 index ce6922a..0000000 --- a/components/update_client/test/update_checker_unittest.cc +++ /dev/null @@ -1,237 +0,0 @@ -// 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 "base/bind.h" -#include "base/bind_helpers.h" -#include "base/compiler_specific.h" -#include "base/files/file_util.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/path_service.h" -#include "base/run_loop.h" -#include "base/version.h" -#include "components/update_client/crx_update_item.h" -#include "components/update_client/test/test_configurator.h" -#include "components/update_client/test/url_request_post_interceptor.h" -#include "components/update_client/update_checker.h" -#include "net/url_request/url_request_test_util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -using std::string; - -namespace update_client { - -namespace { - -base::FilePath test_file(const char* file) { - base::FilePath path; - PathService::Get(base::DIR_SOURCE_ROOT, &path); - return path.AppendASCII("components") - .AppendASCII("test") - .AppendASCII("data") - .AppendASCII("update_client") - .AppendASCII(file); -} - -} // namespace - -class UpdateCheckerTest : public testing::Test { - public: - UpdateCheckerTest(); - ~UpdateCheckerTest() override; - - // Overrides from testing::Test. - void SetUp() override; - void TearDown() override; - - void UpdateCheckComplete(const GURL& original_url, - int error, - const std::string& error_message, - const UpdateResponse::Results& results); - - protected: - void Quit(); - void RunThreads(); - void RunThreadsUntilIdle(); - - CrxUpdateItem BuildCrxUpdateItem(); - - scoped_refptr config_; - - scoped_ptr update_checker_; - - scoped_ptr interceptor_factory_; - URLRequestPostInterceptor* post_interceptor_; // Owned by the factory. - - GURL original_url_; - int error_; - std::string error_message_; - UpdateResponse::Results results_; - - private: - base::MessageLoopForIO loop_; - base::Closure quit_closure_; - - DISALLOW_COPY_AND_ASSIGN(UpdateCheckerTest); -}; - -UpdateCheckerTest::UpdateCheckerTest() : post_interceptor_(NULL), error_(0) { -} - -UpdateCheckerTest::~UpdateCheckerTest() { -} - -void UpdateCheckerTest::SetUp() { - config_ = new TestConfigurator(base::MessageLoopProxy::current(), - base::MessageLoopProxy::current()); - interceptor_factory_.reset( - new InterceptorFactory(base::MessageLoopProxy::current())); - post_interceptor_ = interceptor_factory_->CreateInterceptor(); - EXPECT_TRUE(post_interceptor_); - - update_checker_.reset(); - - error_ = 0; - error_message_.clear(); - results_ = UpdateResponse::Results(); -} - -void UpdateCheckerTest::TearDown() { - update_checker_.reset(); - - post_interceptor_ = NULL; - interceptor_factory_.reset(); - - config_ = nullptr; - - // The PostInterceptor requires the message loop to run to destruct correctly. - // TODO(sorin): This is fragile and should be fixed. - RunThreadsUntilIdle(); -} - -void UpdateCheckerTest::RunThreads() { - base::RunLoop runloop; - quit_closure_ = runloop.QuitClosure(); - runloop.Run(); - - // Since some tests need to drain currently enqueued tasks such as network - // intercepts on the IO thread, run the threads until they are - // idle. The component updater service won't loop again until the loop count - // is set and the service is started. - RunThreadsUntilIdle(); -} - -void UpdateCheckerTest::RunThreadsUntilIdle() { - base::RunLoop().RunUntilIdle(); -} - -void UpdateCheckerTest::Quit() { - if (!quit_closure_.is_null()) - quit_closure_.Run(); -} - -void UpdateCheckerTest::UpdateCheckComplete( - const GURL& original_url, - int error, - const std::string& error_message, - const UpdateResponse::Results& results) { - original_url_ = original_url; - error_ = error; - error_message_ = error_message; - results_ = results; - Quit(); -} - -CrxUpdateItem UpdateCheckerTest::BuildCrxUpdateItem() { - CrxComponent crx_component; - crx_component.name = "test_jebg"; - crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); - crx_component.installer = NULL; - crx_component.version = base::Version("0.9"); - crx_component.fingerprint = "fp1"; - - CrxUpdateItem crx_update_item; - crx_update_item.state = CrxUpdateItem::State::kNew; - crx_update_item.id = "jebgalgnebhfojomionfpkfelancnnkf"; - crx_update_item.component = crx_component; - - return crx_update_item; -} - -TEST_F(UpdateCheckerTest, UpdateCheckSuccess) { - EXPECT_TRUE(post_interceptor_->ExpectRequest( - new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml"))); - - update_checker_ = UpdateChecker::Create(*config_).Pass(); - - CrxUpdateItem item(BuildCrxUpdateItem()); - std::vector items_to_check; - items_to_check.push_back(&item); - - update_checker_->CheckForUpdates( - items_to_check, "extra=\"params\"", - base::Bind(&UpdateCheckerTest::UpdateCheckComplete, - base::Unretained(this))); - - RunThreads(); - - EXPECT_EQ(1, post_interceptor_->GetHitCount()) - << post_interceptor_->GetRequestsAsString(); - EXPECT_EQ(1, post_interceptor_->GetCount()) - << post_interceptor_->GetRequestsAsString(); - - // Sanity check the request. - EXPECT_NE(string::npos, post_interceptor_->GetRequests()[0].find( - "request protocol=\"3.0\" extra=\"params\"")); - EXPECT_NE( - string::npos, - post_interceptor_->GetRequests()[0].find( - "app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">" - "")); - - EXPECT_NE(string::npos, - post_interceptor_->GetRequests()[0].find("ExpectRequest(new PartialMatch("updatecheck"), 403)); - - update_checker_ = UpdateChecker::Create(*config_).Pass(); - - CrxUpdateItem item(BuildCrxUpdateItem()); - std::vector items_to_check; - items_to_check.push_back(&item); - - update_checker_->CheckForUpdates( - items_to_check, "", base::Bind(&UpdateCheckerTest::UpdateCheckComplete, - base::Unretained(this))); - - RunThreads(); - - EXPECT_EQ(1, post_interceptor_->GetHitCount()) - << post_interceptor_->GetRequestsAsString(); - EXPECT_EQ(1, post_interceptor_->GetCount()) - << post_interceptor_->GetRequestsAsString(); - - EXPECT_EQ(config_->UpdateUrl().front(), original_url_); - EXPECT_EQ(403, error_); - EXPECT_STREQ("network error", error_message_.c_str()); - EXPECT_EQ(0ul, results_.list.size()); -} - -} // namespace update_client diff --git a/components/update_client/test/update_client_unittest.cc b/components/update_client/test/update_client_unittest.cc deleted file mode 100644 index 602fb96..0000000 --- a/components/update_client/test/update_client_unittest.cc +++ /dev/null @@ -1,1422 +0,0 @@ -// Copyright 2015 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 "base/bind.h" -#include "base/bind_helpers.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/location.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/path_service.h" -#include "base/run_loop.h" -#include "base/thread_task_runner_handle.h" -#include "base/values.h" -#include "base/version.h" -#include "components/update_client/crx_update_item.h" -#include "components/update_client/ping_manager.h" -#include "components/update_client/test/test_configurator.h" -#include "components/update_client/test/test_installer.h" -#include "components/update_client/update_checker.h" -#include "components/update_client/update_client_internal.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "url/gurl.h" - -namespace update_client { - -namespace { - -using base::FilePath; - -// Makes a copy of the file specified by |from_path| in a temporary directory -// and returns the path of the copy. Returns true if successful. Cleans up if -// there was an error creating the copy. -bool MakeTestFile(const FilePath& from_path, FilePath* to_path) { - FilePath temp_dir; - bool result = - CreateNewTempDirectory(FILE_PATH_LITERAL("update_client"), &temp_dir); - if (!result) - return false; - - FilePath temp_file; - result = CreateTemporaryFileInDir(temp_dir, &temp_file); - if (!result) - return false; - - result = CopyFile(from_path, temp_file); - if (!result) { - DeleteFile(temp_file, false); - return false; - } - - *to_path = temp_file; - return true; -} - -using Events = UpdateClient::Observer::Events; - -class MockObserver : public UpdateClient::Observer { - public: - MOCK_METHOD2(OnEvent, void(Events event, const std::string&)); -}; - -class FakePingManagerImpl : public PingManager { - public: - explicit FakePingManagerImpl(const Configurator& config); - ~FakePingManagerImpl() override; - - void OnUpdateComplete(const CrxUpdateItem* item) override; - - const std::vector& items() const; - - private: - std::vector items_; - DISALLOW_COPY_AND_ASSIGN(FakePingManagerImpl); -}; - -FakePingManagerImpl::FakePingManagerImpl(const Configurator& config) - : PingManager(config) { -} - -FakePingManagerImpl::~FakePingManagerImpl() { -} - -void FakePingManagerImpl::OnUpdateComplete(const CrxUpdateItem* item) { - items_.push_back(*item); -} - -const std::vector& FakePingManagerImpl::items() const { - return items_; -} - -} // namespace - -using ::testing::_; -using ::testing::AnyNumber; -using ::testing::DoAll; -using ::testing::InSequence; -using ::testing::Invoke; -using ::testing::Mock; -using ::testing::Return; - -using content::BrowserThread; - -using std::string; - -class UpdateClientTest : public testing::Test { - public: - UpdateClientTest(); - ~UpdateClientTest() override; - - void SetUp() override; - void TearDown() override; - - protected: - void RunThreads(); - - // Returns the full path to a test file. - static base::FilePath TestFilePath(const char* file); - - content::TestBrowserThreadBundle thread_bundle_; - - base::RunLoop runloop_; - base::Closure quit_closure_; - - scoped_refptr config_; - - private: - DISALLOW_COPY_AND_ASSIGN(UpdateClientTest); -}; - -UpdateClientTest::UpdateClientTest() - : config_(new TestConfigurator( - BrowserThread::GetBlockingPool() - ->GetSequencedTaskRunnerWithShutdownBehavior( - BrowserThread::GetBlockingPool()->GetSequenceToken(), - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN), - BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))) { -} - -UpdateClientTest::~UpdateClientTest() { -} - -void UpdateClientTest::SetUp() { - quit_closure_ = runloop_.QuitClosure(); -} - -void UpdateClientTest::TearDown() { -} - -void UpdateClientTest::RunThreads() { - runloop_.Run(); -} - -base::FilePath UpdateClientTest::TestFilePath(const char* file) { - base::FilePath path; - PathService::Get(base::DIR_SOURCE_ROOT, &path); - return path.AppendASCII("components") - .AppendASCII("test") - .AppendASCII("data") - .AppendASCII("update_client") - .AppendASCII(file); -} - -// Tests the scenario where one update check is done for one CRX. The CRX -// has no update. -TEST_F(UpdateClientTest, OneCrxNoUpdate) { - class DataCallbackFake { - public: - static void Callback(const std::vector& ids, - std::vector* components) { - CrxComponent crx; - crx.name = "test_jebg"; - crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); - crx.version = Version("0.9"); - crx.installer = new TestInstaller; - components->push_back(crx); - } - }; - - class CompletionCallbackFake { - public: - static void Callback(const base::Closure& quit_closure, int error) { - EXPECT_EQ(0, error); - quit_closure.Run(); - } - }; - - class FakeUpdateChecker : public UpdateChecker { - public: - static scoped_ptr Create(const Configurator& config) { - return scoped_ptr(new FakeUpdateChecker()); - } - - bool CheckForUpdates( - const std::vector& items_to_check, - const std::string& additional_attributes, - const UpdateCheckCallback& update_check_callback) override { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", - UpdateResponse::Results())); - return true; - } - }; - - class FakeCrxDownloader : public CrxDownloader { - public: - static scoped_ptr Create( - bool is_background_download, - net::URLRequestContextGetter* context_getter, - const scoped_refptr& url_fetcher_task_runner, - const scoped_refptr& - background_task_runner) { - return scoped_ptr(new FakeCrxDownloader()); - } - - private: - FakeCrxDownloader() : CrxDownloader(scoped_ptr().Pass()) {} - ~FakeCrxDownloader() override {} - - void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); } - }; - - class FakePingManager : public FakePingManagerImpl { - public: - explicit FakePingManager(const Configurator& config) - : FakePingManagerImpl(config) {} - ~FakePingManager() override { EXPECT_TRUE(items().empty()); } - }; - - scoped_ptr ping_manager(new FakePingManager(*config_)); - scoped_ptr update_client(new UpdateClientImpl( - config_, ping_manager.Pass(), &FakeUpdateChecker::Create, - &FakeCrxDownloader::Create)); - - MockObserver observer; - InSequence seq; - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - - update_client->AddObserver(&observer); - - std::vector ids; - ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf")); - - update_client->Update( - ids, base::Bind(&DataCallbackFake::Callback), - base::Bind(&CompletionCallbackFake::Callback, quit_closure_)); - - RunThreads(); - - update_client->RemoveObserver(&observer); -} - -// Tests the scenario where two CRXs are checked for updates. On CRX has -// an update, the other CRX does not. -TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) { - class DataCallbackFake { - public: - static void Callback(const std::vector& ids, - std::vector* components) { - CrxComponent crx1; - crx1.name = "test_jebg"; - crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); - crx1.version = Version("0.9"); - crx1.installer = new TestInstaller; - - CrxComponent crx2; - crx2.name = "test_abag"; - crx2.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash)); - crx2.version = Version("2.2"); - crx2.installer = new TestInstaller; - - components->push_back(crx1); - components->push_back(crx2); - } - }; - - class CompletionCallbackFake { - public: - static void Callback(const base::Closure& quit_closure, int error) { - EXPECT_EQ(0, error); - quit_closure.Run(); - } - }; - - class FakeUpdateChecker : public UpdateChecker { - public: - static scoped_ptr Create(const Configurator& config) { - return scoped_ptr(new FakeUpdateChecker()); - } - - bool CheckForUpdates( - const std::vector& items_to_check, - const std::string& additional_attributes, - const UpdateCheckCallback& update_check_callback) override { - /* - Fake the following response: - - - - - - - - - - - - - - - - - */ - UpdateResponse::Result::Manifest::Package package; - package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx"; - - UpdateResponse::Result result; - result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf"; - result.crx_urls.push_back(GURL("http://localhost/download/")); - result.manifest.version = "1.0"; - result.manifest.browser_min_version = "11.0.1.0"; - result.manifest.packages.push_back(package); - - UpdateResponse::Results results; - results.list.push_back(result); - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); - return true; - } - }; - - class FakeCrxDownloader : public CrxDownloader { - public: - static scoped_ptr Create( - bool is_background_download, - net::URLRequestContextGetter* context_getter, - const scoped_refptr& url_fetcher_task_runner, - const scoped_refptr& - background_task_runner) { - return scoped_ptr(new FakeCrxDownloader()); - } - - private: - FakeCrxDownloader() : CrxDownloader(scoped_ptr().Pass()) {} - ~FakeCrxDownloader() override {} - - void DoStartDownload(const GURL& url) override { - DownloadMetrics download_metrics; - download_metrics.url = url; - download_metrics.downloader = DownloadMetrics::kNone; - download_metrics.error = 0; - download_metrics.downloaded_bytes = 1843; - download_metrics.total_bytes = 1843; - download_metrics.download_time_ms = 1000; - - FilePath path; - EXPECT_TRUE(MakeTestFile( - TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path)); - - Result result; - result.error = 0; - result.response = path; - result.downloaded_bytes = 1843; - result.total_bytes = 1843; - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, - base::Unretained(this), result)); - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&FakeCrxDownloader::OnDownloadComplete, - base::Unretained(this), true, result, download_metrics)); - } - }; - - class FakePingManager : public FakePingManagerImpl { - public: - explicit FakePingManager(const Configurator& config) - : FakePingManagerImpl(config) {} - ~FakePingManager() override { - const auto& ping_items = items(); - EXPECT_EQ(1U, ping_items.size()); - EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id); - EXPECT_TRUE(base::Version("0.9").Equals(ping_items[0].previous_version)); - EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); - EXPECT_EQ(0, ping_items[0].error_category); - EXPECT_EQ(0, ping_items[0].error_code); - } - }; - - scoped_ptr ping_manager(new FakePingManager(*config_)); - scoped_ptr update_client(new UpdateClientImpl( - config_, ping_manager.Pass(), &FakeUpdateChecker::Create, - &FakeCrxDownloader::Create)); - - MockObserver observer; - { - InSequence seq; - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - } - { - InSequence seq; - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, - "abagagagagagagagagagagagagagagag")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED, - "abagagagagagagagagagagagagagagag")).Times(1); - } - - update_client->AddObserver(&observer); - - std::vector ids; - ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf")); - ids.push_back(std::string("abagagagagagagagagagagagagagagag")); - - update_client->Update( - ids, base::Bind(&DataCallbackFake::Callback), - base::Bind(&CompletionCallbackFake::Callback, quit_closure_)); - - RunThreads(); - - update_client->RemoveObserver(&observer); -} - -// Tests the update check for two CRXs scenario. Both CRXs have updates. -TEST_F(UpdateClientTest, TwoCrxUpdate) { - class DataCallbackFake { - public: - static void Callback(const std::vector& ids, - std::vector* components) { - CrxComponent crx1; - crx1.name = "test_jebg"; - crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); - crx1.version = Version("0.9"); - crx1.installer = new TestInstaller; - - CrxComponent crx2; - crx2.name = "test_ihfo"; - crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash)); - crx2.version = Version("0.8"); - crx2.installer = new TestInstaller; - - components->push_back(crx1); - components->push_back(crx2); - } - }; - - class CompletionCallbackFake { - public: - static void Callback(const base::Closure& quit_closure, int error) { - EXPECT_EQ(0, error); - quit_closure.Run(); - } - }; - - class FakeUpdateChecker : public UpdateChecker { - public: - static scoped_ptr Create(const Configurator& config) { - return scoped_ptr(new FakeUpdateChecker()); - } - - bool CheckForUpdates( - const std::vector& items_to_check, - const std::string& additional_attributes, - const UpdateCheckCallback& update_check_callback) override { - /* - Fake the following response: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - UpdateResponse::Result::Manifest::Package package1; - package1.name = "jebgalgnebhfojomionfpkfelancnnkf.crx"; - - UpdateResponse::Result result1; - result1.extension_id = "jebgalgnebhfojomionfpkfelancnnkf"; - result1.crx_urls.push_back(GURL("http://localhost/download/")); - result1.manifest.version = "1.0"; - result1.manifest.browser_min_version = "11.0.1.0"; - result1.manifest.packages.push_back(package1); - - UpdateResponse::Result::Manifest::Package package2; - package2.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"; - - UpdateResponse::Result result2; - result2.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; - result2.crx_urls.push_back(GURL("http://localhost/download/")); - result2.manifest.version = "1.0"; - result2.manifest.browser_min_version = "11.0.1.0"; - result2.manifest.packages.push_back(package2); - - UpdateResponse::Results results; - results.list.push_back(result1); - results.list.push_back(result2); - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); - return true; - } - }; - - class FakeCrxDownloader : public CrxDownloader { - public: - static scoped_ptr Create( - bool is_background_download, - net::URLRequestContextGetter* context_getter, - const scoped_refptr& url_fetcher_task_runner, - const scoped_refptr& - background_task_runner) { - return scoped_ptr(new FakeCrxDownloader()); - } - - private: - FakeCrxDownloader() : CrxDownloader(scoped_ptr().Pass()) {} - ~FakeCrxDownloader() override {} - - void DoStartDownload(const GURL& url) override { - DownloadMetrics download_metrics; - FilePath path; - Result result; - if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") { - download_metrics.url = url; - download_metrics.downloader = DownloadMetrics::kNone; - download_metrics.error = 0; - download_metrics.downloaded_bytes = 1843; - download_metrics.total_bytes = 1843; - download_metrics.download_time_ms = 1000; - - EXPECT_TRUE(MakeTestFile( - TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path)); - - result.error = 0; - result.response = path; - result.downloaded_bytes = 1843; - result.total_bytes = 1843; - } else if (url.path() == - "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") { - download_metrics.url = url; - download_metrics.downloader = DownloadMetrics::kNone; - download_metrics.error = 0; - download_metrics.downloaded_bytes = 53638; - download_metrics.total_bytes = 53638; - download_metrics.download_time_ms = 2000; - - EXPECT_TRUE(MakeTestFile( - TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path)); - - result.error = 0; - result.response = path; - result.downloaded_bytes = 53638; - result.total_bytes = 53638; - } else { - NOTREACHED(); - } - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, - base::Unretained(this), result)); - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&FakeCrxDownloader::OnDownloadComplete, - base::Unretained(this), true, result, download_metrics)); - } - }; - - class FakePingManager : public FakePingManagerImpl { - public: - explicit FakePingManager(const Configurator& config) - : FakePingManagerImpl(config) {} - ~FakePingManager() override { - const auto& ping_items = items(); - EXPECT_EQ(2U, ping_items.size()); - EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id); - EXPECT_TRUE(base::Version("0.9").Equals(ping_items[0].previous_version)); - EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); - EXPECT_EQ(0, ping_items[0].error_category); - EXPECT_EQ(0, ping_items[0].error_code); - EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id); - EXPECT_TRUE(base::Version("0.8").Equals(ping_items[1].previous_version)); - EXPECT_TRUE(base::Version("1.0").Equals(ping_items[1].next_version)); - EXPECT_EQ(0, ping_items[1].error_category); - EXPECT_EQ(0, ping_items[1].error_code); - } - }; - - scoped_ptr ping_manager(new FakePingManager(*config_)); - scoped_ptr update_client(new UpdateClientImpl( - config_, ping_manager.Pass(), &FakeUpdateChecker::Create, - &FakeCrxDownloader::Create)); - - MockObserver observer; - { - InSequence seq; - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - } - { - InSequence seq; - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - } - - update_client->AddObserver(&observer); - - std::vector ids; - ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf")); - ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc")); - - update_client->Update( - ids, base::Bind(&DataCallbackFake::Callback), - base::Bind(&CompletionCallbackFake::Callback, quit_closure_)); - - RunThreads(); - - update_client->RemoveObserver(&observer); -} - -// Tests the differential update scenario for one CRX. -TEST_F(UpdateClientTest, OneCrxDiffUpdate) { - class DataCallbackFake { - public: - static void Callback(const std::vector& ids, - std::vector* components) { - static int num_calls = 0; - - // Must use the same stateful installer object. - static scoped_refptr installer( - new VersionedTestInstaller()); - - ++num_calls; - - CrxComponent crx; - crx.name = "test_ihfo"; - crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash)); - crx.installer = installer; - if (num_calls == 1) { - crx.version = Version("0.8"); - } else if (num_calls == 2) { - crx.version = Version("1.0"); - } else { - NOTREACHED(); - } - - components->push_back(crx); - } - }; - - class CompletionCallbackFake { - public: - static void Callback(const base::Closure& quit_closure, int error) { - EXPECT_EQ(0, error); - quit_closure.Run(); - } - }; - - class FakeUpdateChecker : public UpdateChecker { - public: - static scoped_ptr Create(const Configurator& config) { - return scoped_ptr(new FakeUpdateChecker()); - } - - bool CheckForUpdates( - const std::vector& items_to_check, - const std::string& additional_attributes, - const UpdateCheckCallback& update_check_callback) override { - static int num_call = 0; - ++num_call; - - UpdateResponse::Results results; - - if (num_call == 1) { - /* - Fake the following response: - - - - - - - - - - - - - - - - */ - UpdateResponse::Result::Manifest::Package package; - package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"; - package.fingerprint = "1"; - UpdateResponse::Result result; - result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; - result.crx_urls.push_back(GURL("http://localhost/download/")); - result.manifest.version = "1.0"; - result.manifest.browser_min_version = "11.0.1.0"; - result.manifest.packages.push_back(package); - results.list.push_back(result); - } else if (num_call == 2) { - /* - Fake the following response: - - - - - - - - - - - - - - - - - */ - UpdateResponse::Result::Manifest::Package package; - package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"; - package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"; - package.fingerprint = "22"; - UpdateResponse::Result result; - result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; - result.crx_urls.push_back(GURL("http://localhost/download/")); - result.crx_diffurls.push_back(GURL("http://localhost/download/")); - result.manifest.version = "2.0"; - result.manifest.browser_min_version = "11.0.1.0"; - result.manifest.packages.push_back(package); - results.list.push_back(result); - } else { - NOTREACHED(); - } - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); - return true; - } - }; - - class FakeCrxDownloader : public CrxDownloader { - public: - static scoped_ptr Create( - bool is_background_download, - net::URLRequestContextGetter* context_getter, - const scoped_refptr& url_fetcher_task_runner, - const scoped_refptr& - background_task_runner) { - return scoped_ptr(new FakeCrxDownloader()); - } - - private: - FakeCrxDownloader() : CrxDownloader(scoped_ptr().Pass()) {} - ~FakeCrxDownloader() override {} - - void DoStartDownload(const GURL& url) override { - DownloadMetrics download_metrics; - FilePath path; - Result result; - if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") { - download_metrics.url = url; - download_metrics.downloader = DownloadMetrics::kNone; - download_metrics.error = 0; - download_metrics.downloaded_bytes = 53638; - download_metrics.total_bytes = 53638; - download_metrics.download_time_ms = 2000; - - EXPECT_TRUE(MakeTestFile( - TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path)); - - result.error = 0; - result.response = path; - result.downloaded_bytes = 53638; - result.total_bytes = 53638; - } else if (url.path() == - "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") { - download_metrics.url = url; - download_metrics.downloader = DownloadMetrics::kNone; - download_metrics.error = 0; - download_metrics.downloaded_bytes = 2105; - download_metrics.total_bytes = 2105; - download_metrics.download_time_ms = 1000; - - EXPECT_TRUE(MakeTestFile( - TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path)); - - result.error = 0; - result.response = path; - result.downloaded_bytes = 2105; - result.total_bytes = 2105; - } else { - NOTREACHED(); - } - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, - base::Unretained(this), result)); - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&FakeCrxDownloader::OnDownloadComplete, - base::Unretained(this), true, result, download_metrics)); - } - }; - - class FakePingManager : public FakePingManagerImpl { - public: - explicit FakePingManager(const Configurator& config) - : FakePingManagerImpl(config) {} - ~FakePingManager() override { - const auto& ping_items = items(); - EXPECT_EQ(2U, ping_items.size()); - EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[0].id); - EXPECT_TRUE(base::Version("0.8").Equals(ping_items[0].previous_version)); - EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); - EXPECT_EQ(0, ping_items[0].error_category); - EXPECT_EQ(0, ping_items[0].error_code); - EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id); - EXPECT_TRUE(base::Version("1.0").Equals(ping_items[1].previous_version)); - EXPECT_TRUE(base::Version("2.0").Equals(ping_items[1].next_version)); - EXPECT_EQ(0, ping_items[1].diff_error_category); - EXPECT_EQ(0, ping_items[1].diff_error_code); - } - }; - - scoped_ptr ping_manager(new FakePingManager(*config_)); - scoped_ptr update_client(new UpdateClientImpl( - config_, ping_manager.Pass(), &FakeUpdateChecker::Create, - &FakeCrxDownloader::Create)); - - MockObserver observer; - { - InSequence seq; - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - } - - update_client->AddObserver(&observer); - - std::vector ids; - ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc")); - - { - base::RunLoop runloop; - update_client->Update( - ids, base::Bind(&DataCallbackFake::Callback), - base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); - runloop.Run(); - } - - { - base::RunLoop runloop; - update_client->Update( - ids, base::Bind(&DataCallbackFake::Callback), - base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); - runloop.Run(); - } - - update_client->RemoveObserver(&observer); -} - -// Tests the update scenario for one CRX where the CRX installer returns -// an error. -TEST_F(UpdateClientTest, OneCrxInstallError) { - class MockInstaller : public CrxInstaller { - public: - MOCK_METHOD1(OnUpdateError, void(int error)); - MOCK_METHOD2(Install, - bool(const base::DictionaryValue& manifest, - const base::FilePath& unpack_path)); - MOCK_METHOD2(GetInstalledFile, - bool(const std::string& file, base::FilePath* installed_file)); - MOCK_METHOD0(Uninstall, bool()); - - static void OnInstall(const base::DictionaryValue& manifest, - const base::FilePath& unpack_path) { - base::DeleteFile(unpack_path, true); - } - - protected: - ~MockInstaller() override {} - }; - - class DataCallbackFake { - public: - static void Callback(const std::vector& ids, - std::vector* components) { - scoped_refptr installer(new MockInstaller()); - - EXPECT_CALL(*installer, OnUpdateError(_)).Times(0); - EXPECT_CALL(*installer, Install(_, _)) - .WillOnce(DoAll(Invoke(MockInstaller::OnInstall), Return(false))); - EXPECT_CALL(*installer, GetInstalledFile(_, _)).Times(0); - EXPECT_CALL(*installer, Uninstall()).Times(0); - - CrxComponent crx; - crx.name = "test_jebg"; - crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); - crx.version = Version("0.9"); - crx.installer = installer; - components->push_back(crx); - } - }; - - class CompletionCallbackFake { - public: - static void Callback(const base::Closure& quit_closure, int error) { - EXPECT_EQ(0, error); - quit_closure.Run(); - } - }; - - class FakeUpdateChecker : public UpdateChecker { - public: - static scoped_ptr Create(const Configurator& config) { - return scoped_ptr(new FakeUpdateChecker()); - } - - bool CheckForUpdates( - const std::vector& items_to_check, - const std::string& additional_attributes, - const UpdateCheckCallback& update_check_callback) override { - /* - Fake the following response: - - - - - - - - - - - - - - - - - */ - UpdateResponse::Result::Manifest::Package package; - package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx"; - - UpdateResponse::Result result; - result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf"; - result.crx_urls.push_back(GURL("http://localhost/download/")); - result.manifest.version = "1.0"; - result.manifest.browser_min_version = "11.0.1.0"; - result.manifest.packages.push_back(package); - - UpdateResponse::Results results; - results.list.push_back(result); - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); - return true; - } - }; - - class FakeCrxDownloader : public CrxDownloader { - public: - static scoped_ptr Create( - bool is_background_download, - net::URLRequestContextGetter* context_getter, - const scoped_refptr& url_fetcher_task_runner, - const scoped_refptr& - background_task_runner) { - return scoped_ptr(new FakeCrxDownloader()); - } - - private: - FakeCrxDownloader() : CrxDownloader(scoped_ptr().Pass()) {} - ~FakeCrxDownloader() override {} - - void DoStartDownload(const GURL& url) override { - DownloadMetrics download_metrics; - download_metrics.url = url; - download_metrics.downloader = DownloadMetrics::kNone; - download_metrics.error = 0; - download_metrics.downloaded_bytes = 1843; - download_metrics.total_bytes = 1843; - download_metrics.download_time_ms = 1000; - - FilePath path; - EXPECT_TRUE(MakeTestFile( - TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path)); - - Result result; - result.error = 0; - result.response = path; - result.downloaded_bytes = 1843; - result.total_bytes = 1843; - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, - base::Unretained(this), result)); - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&FakeCrxDownloader::OnDownloadComplete, - base::Unretained(this), true, result, download_metrics)); - } - }; - - class FakePingManager : public FakePingManagerImpl { - public: - explicit FakePingManager(const Configurator& config) - : FakePingManagerImpl(config) {} - ~FakePingManager() override { - const auto& ping_items = items(); - EXPECT_EQ(1U, ping_items.size()); - EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id); - EXPECT_TRUE(base::Version("0.9").Equals(ping_items[0].previous_version)); - EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); - EXPECT_EQ(3, ping_items[0].error_category); // kInstallError. - EXPECT_EQ(9, ping_items[0].error_code); // kInstallerError. - } - }; - - scoped_ptr ping_manager(new FakePingManager(*config_)); - scoped_ptr update_client(new UpdateClientImpl( - config_, ping_manager.Pass(), &FakeUpdateChecker::Create, - &FakeCrxDownloader::Create)); - - MockObserver observer; - { - InSequence seq; - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED, - "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); - } - - update_client->AddObserver(&observer); - - std::vector ids; - ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf")); - - update_client->Update( - ids, base::Bind(&DataCallbackFake::Callback), - base::Bind(&CompletionCallbackFake::Callback, quit_closure_)); - - RunThreads(); - - update_client->RemoveObserver(&observer); -} - -// Tests the fallback from differential to full update scenario for one CRX. -TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) { - class DataCallbackFake { - public: - static void Callback(const std::vector& ids, - std::vector* components) { - static int num_calls = 0; - - // Must use the same stateful installer object. - static scoped_refptr installer( - new VersionedTestInstaller()); - - ++num_calls; - - CrxComponent crx; - crx.name = "test_ihfo"; - crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash)); - crx.installer = installer; - if (num_calls == 1) { - crx.version = Version("0.8"); - } else if (num_calls == 2) { - crx.version = Version("1.0"); - } else { - NOTREACHED(); - } - - components->push_back(crx); - } - }; - - class CompletionCallbackFake { - public: - static void Callback(const base::Closure& quit_closure, int error) { - EXPECT_EQ(0, error); - quit_closure.Run(); - } - }; - - class FakeUpdateChecker : public UpdateChecker { - public: - static scoped_ptr Create(const Configurator& config) { - return scoped_ptr(new FakeUpdateChecker()); - } - - bool CheckForUpdates( - const std::vector& items_to_check, - const std::string& additional_attributes, - const UpdateCheckCallback& update_check_callback) override { - static int num_call = 0; - ++num_call; - - UpdateResponse::Results results; - - if (num_call == 1) { - /* - Fake the following response: - - - - - - - - - - - - - - - - */ - UpdateResponse::Result::Manifest::Package package; - package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"; - package.fingerprint = "1"; - UpdateResponse::Result result; - result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; - result.crx_urls.push_back(GURL("http://localhost/download/")); - result.manifest.version = "1.0"; - result.manifest.browser_min_version = "11.0.1.0"; - result.manifest.packages.push_back(package); - results.list.push_back(result); - } else if (num_call == 2) { - /* - Fake the following response: - - - - - - - - - - - - - - - - - */ - UpdateResponse::Result::Manifest::Package package; - package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"; - package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"; - package.fingerprint = "22"; - UpdateResponse::Result result; - result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; - result.crx_urls.push_back(GURL("http://localhost/download/")); - result.crx_diffurls.push_back(GURL("http://localhost/download/")); - result.manifest.version = "2.0"; - result.manifest.browser_min_version = "11.0.1.0"; - result.manifest.packages.push_back(package); - results.list.push_back(result); - } else { - NOTREACHED(); - } - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); - return true; - } - }; - - class FakeCrxDownloader : public CrxDownloader { - public: - static scoped_ptr Create( - bool is_background_download, - net::URLRequestContextGetter* context_getter, - const scoped_refptr& url_fetcher_task_runner, - const scoped_refptr& - background_task_runner) { - return scoped_ptr(new FakeCrxDownloader()); - } - - private: - FakeCrxDownloader() : CrxDownloader(scoped_ptr().Pass()) {} - ~FakeCrxDownloader() override {} - - void DoStartDownload(const GURL& url) override { - DownloadMetrics download_metrics; - FilePath path; - Result result; - if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") { - download_metrics.url = url; - download_metrics.downloader = DownloadMetrics::kNone; - download_metrics.error = 0; - download_metrics.downloaded_bytes = 53638; - download_metrics.total_bytes = 53638; - download_metrics.download_time_ms = 2000; - - EXPECT_TRUE(MakeTestFile( - TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path)); - - result.error = 0; - result.response = path; - result.downloaded_bytes = 53638; - result.total_bytes = 53638; - } else if (url.path() == - "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") { - // A download error is injected on this execution path. - download_metrics.url = url; - download_metrics.downloader = DownloadMetrics::kNone; - download_metrics.error = -1; - download_metrics.downloaded_bytes = 0; - download_metrics.total_bytes = 2105; - download_metrics.download_time_ms = 1000; - - EXPECT_TRUE(MakeTestFile( - TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path)); - - result.error = -1; - result.response = path; - result.downloaded_bytes = 0; - result.total_bytes = 2105; - } else if (url.path() == - "/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx") { - download_metrics.url = url; - download_metrics.downloader = DownloadMetrics::kNone; - download_metrics.error = 0; - download_metrics.downloaded_bytes = 53855; - download_metrics.total_bytes = 53855; - download_metrics.download_time_ms = 1000; - - EXPECT_TRUE(MakeTestFile( - TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"), &path)); - - result.error = 0; - result.response = path; - result.downloaded_bytes = 53855; - result.total_bytes = 53855; - } - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, - base::Unretained(this), result)); - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&FakeCrxDownloader::OnDownloadComplete, - base::Unretained(this), true, result, download_metrics)); - } - }; - - class FakePingManager : public FakePingManagerImpl { - public: - explicit FakePingManager(const Configurator& config) - : FakePingManagerImpl(config) {} - ~FakePingManager() override { - const auto& ping_items = items(); - EXPECT_EQ(2U, ping_items.size()); - EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[0].id); - EXPECT_TRUE(base::Version("0.8").Equals(ping_items[0].previous_version)); - EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); - EXPECT_EQ(0, ping_items[0].error_category); - EXPECT_EQ(0, ping_items[0].error_code); - EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id); - EXPECT_TRUE(base::Version("1.0").Equals(ping_items[1].previous_version)); - EXPECT_TRUE(base::Version("2.0").Equals(ping_items[1].next_version)); - EXPECT_TRUE(ping_items[1].diff_update_failed); - EXPECT_EQ(1, ping_items[1].diff_error_category); // kNetworkError. - EXPECT_EQ(-1, ping_items[1].diff_error_code); - } - }; - - scoped_ptr ping_manager(new FakePingManager(*config_)); - scoped_ptr update_client(new UpdateClientImpl( - config_, ping_manager.Pass(), &FakeUpdateChecker::Create, - &FakeCrxDownloader::Create)); - - MockObserver observer; - { - InSequence seq; - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, - "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); - } - - update_client->AddObserver(&observer); - - std::vector ids; - ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc")); - - { - base::RunLoop runloop; - update_client->Update( - ids, base::Bind(&DataCallbackFake::Callback), - base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); - runloop.Run(); - } - - { - base::RunLoop runloop; - update_client->Update( - ids, base::Bind(&DataCallbackFake::Callback), - base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); - runloop.Run(); - } - - update_client->RemoveObserver(&observer); -} - -} // namespace update_client diff --git a/components/update_client/test/update_response_unittest.cc b/components/update_client/test/update_response_unittest.cc deleted file mode 100644 index e106916..0000000 --- a/components/update_client/test/update_response_unittest.cc +++ /dev/null @@ -1,302 +0,0 @@ -// 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 "base/memory/scoped_vector.h" -#include "components/update_client/update_response.h" -#include "libxml/globals.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace update_client { - -const char* kValidXml = - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - -const char* valid_xml_with_hash = - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - -const char* valid_xml_with_invalid_sizes = - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - -const char* kInvalidValidXmlMissingCodebase = - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - -const char* kMissingAppId = - "" - "" - " " - " " - " " - ""; - -const char* kInvalidCodebase = - "" - "" - " " - " " - " " - ""; - -const char* kMissingVersion = - "" - "" - " " - " " - " " - ""; - -const char* kInvalidVersion = - "" - "" - " " - " " - " " - ""; - -// The v3 version of the protocol is not using namespaces. However, the parser -// must be able to parse responses that include namespaces. -const char* kUsesNamespacePrefix = - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - -// Includes unrelated tags from other xml namespaces - this should -// not cause problems. -const char* kSimilarTagnames = - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - -// Includes a tag. -const char* kWithDaystart = - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - -// Indicates no updates available - this should not be a parse error. -const char* kNoUpdate = - "" - "" - " " - " " - " " - ""; - -// Includes two tags, one with an error. -const char* kTwoAppsOneError = - "" - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - -TEST(ComponentUpdaterUpdateResponseTest, TestParser) { - UpdateResponse parser; - - // Test parsing of a number of invalid xml cases - EXPECT_FALSE(parser.Parse(std::string())); - EXPECT_FALSE(parser.errors().empty()); - - EXPECT_TRUE(parser.Parse(kMissingAppId)); - EXPECT_TRUE(parser.results().list.empty()); - EXPECT_FALSE(parser.errors().empty()); - - EXPECT_TRUE(parser.Parse(kInvalidCodebase)); - EXPECT_TRUE(parser.results().list.empty()); - EXPECT_FALSE(parser.errors().empty()); - - EXPECT_TRUE(parser.Parse(kMissingVersion)); - EXPECT_TRUE(parser.results().list.empty()); - EXPECT_FALSE(parser.errors().empty()); - - EXPECT_TRUE(parser.Parse(kInvalidVersion)); - EXPECT_TRUE(parser.results().list.empty()); - EXPECT_FALSE(parser.errors().empty()); - - EXPECT_TRUE(parser.Parse(kInvalidValidXmlMissingCodebase)); - EXPECT_TRUE(parser.results().list.empty()); - EXPECT_FALSE(parser.errors().empty()); - - // Parse some valid XML, and check that all params came out as expected - EXPECT_TRUE(parser.Parse(kValidXml)); - EXPECT_TRUE(parser.errors().empty()); - EXPECT_EQ(1u, parser.results().list.size()); - const UpdateResponse::Result* firstResult = &parser.results().list[0]; - EXPECT_EQ(1u, firstResult->crx_urls.size()); - EXPECT_EQ(GURL("http://example.com/"), firstResult->crx_urls[0]); - EXPECT_EQ(GURL("http://diff.example.com/"), firstResult->crx_diffurls[0]); - EXPECT_EQ("1.2.3.4", firstResult->manifest.version); - EXPECT_EQ("2.0.143.0", firstResult->manifest.browser_min_version); - EXPECT_EQ(1u, firstResult->manifest.packages.size()); - EXPECT_EQ("extension_1_2_3_4.crx", firstResult->manifest.packages[0].name); - - // Parse some xml that uses namespace prefixes. - EXPECT_TRUE(parser.Parse(kUsesNamespacePrefix)); - EXPECT_TRUE(parser.errors().empty()); - EXPECT_TRUE(parser.Parse(kSimilarTagnames)); - EXPECT_TRUE(parser.errors().empty()); - xmlCleanupGlobals(); - - // Parse xml with hash value - EXPECT_TRUE(parser.Parse(valid_xml_with_hash)); - EXPECT_TRUE(parser.errors().empty()); - EXPECT_FALSE(parser.results().list.empty()); - firstResult = &parser.results().list[0]; - EXPECT_FALSE(firstResult->manifest.packages.empty()); - EXPECT_EQ("1234", firstResult->manifest.packages[0].hash_sha256); - - // Parse xml with package size value - EXPECT_TRUE(parser.Parse(valid_xml_with_invalid_sizes)); - EXPECT_TRUE(parser.errors().empty()); - EXPECT_FALSE(parser.results().list.empty()); - firstResult = &parser.results().list[0]; - EXPECT_FALSE(firstResult->manifest.packages.empty()); - EXPECT_EQ(1234, firstResult->manifest.packages[0].size); - EXPECT_EQ(-1234, firstResult->manifest.packages[1].size); - EXPECT_EQ(0, firstResult->manifest.packages[2].size); - EXPECT_EQ(0, firstResult->manifest.packages[3].size); - EXPECT_EQ(0, firstResult->manifest.packages[4].size); - EXPECT_EQ(0, firstResult->manifest.packages[5].size); - - // Parse xml with a element. - EXPECT_TRUE(parser.Parse(kWithDaystart)); - EXPECT_TRUE(parser.errors().empty()); - EXPECT_FALSE(parser.results().list.empty()); - EXPECT_EQ(parser.results().daystart_elapsed_seconds, 456); - - // Parse a no-update response. - EXPECT_TRUE(parser.Parse(kNoUpdate)); - EXPECT_TRUE(parser.errors().empty()); - EXPECT_FALSE(parser.results().list.empty()); - firstResult = &parser.results().list[0]; - EXPECT_EQ(firstResult->extension_id, "12345"); - EXPECT_EQ(firstResult->manifest.version, ""); - - // Parse xml with one error and one success tag. - EXPECT_TRUE(parser.Parse(kTwoAppsOneError)); - EXPECT_FALSE(parser.errors().empty()); - EXPECT_EQ(1u, parser.results().list.size()); - firstResult = &parser.results().list[0]; - EXPECT_EQ(firstResult->extension_id, "bbbbbbbb"); -} - -} // namespace update_client diff --git a/components/update_client/test/url_request_post_interceptor.cc b/components/update_client/test/url_request_post_interceptor.cc deleted file mode 100644 index 4aeb7a7..0000000 --- a/components/update_client/test/url_request_post_interceptor.cc +++ /dev/null @@ -1,301 +0,0 @@ -// 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 "components/update_client/test/url_request_post_interceptor.h" - -#include "base/files/file_util.h" -#include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "base/strings/stringprintf.h" -#include "components/update_client/test/test_configurator.h" -#include "net/base/upload_bytes_element_reader.h" -#include "net/base/upload_data_stream.h" -#include "net/url_request/url_request.h" -#include "net/url_request/url_request_filter.h" -#include "net/url_request/url_request_interceptor.h" -#include "net/url_request/url_request_simple_job.h" -#include "net/url_request/url_request_test_util.h" - -namespace update_client { - -// Returns a canned response. -class URLRequestMockJob : public net::URLRequestSimpleJob { - public: - URLRequestMockJob(net::URLRequest* request, - net::NetworkDelegate* network_delegate, - int response_code, - const std::string& response_body) - : net::URLRequestSimpleJob(request, network_delegate), - response_code_(response_code), - response_body_(response_body) {} - - protected: - int GetResponseCode() const override { return response_code_; } - - int GetData(std::string* mime_type, - std::string* charset, - std::string* data, - const net::CompletionCallback& callback) const override { - mime_type->assign("text/plain"); - charset->assign("US-ASCII"); - data->assign(response_body_); - return net::OK; - } - - private: - ~URLRequestMockJob() override {} - - int response_code_; - std::string response_body_; - DISALLOW_COPY_AND_ASSIGN(URLRequestMockJob); -}; - -URLRequestPostInterceptor::URLRequestPostInterceptor( - const GURL& url, - const scoped_refptr& io_task_runner) - : url_(url), io_task_runner_(io_task_runner), hit_count_(0) { -} - -URLRequestPostInterceptor::~URLRequestPostInterceptor() { - DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); - ClearExpectations(); -} - -void URLRequestPostInterceptor::ClearExpectations() { - while (!expectations_.empty()) { - Expectation expectation(expectations_.front()); - delete expectation.first; - expectations_.pop(); - } -} - -GURL URLRequestPostInterceptor::GetUrl() const { - return url_; -} - -bool URLRequestPostInterceptor::ExpectRequest( - class RequestMatcher* request_matcher) { - expectations_.push(std::make_pair(request_matcher, - ExpectationResponse(kResponseCode200, ""))); - return true; -} - -bool URLRequestPostInterceptor::ExpectRequest( - class RequestMatcher* request_matcher, - int response_code) { - expectations_.push( - std::make_pair(request_matcher, ExpectationResponse(response_code, ""))); - return true; -} - -bool URLRequestPostInterceptor::ExpectRequest( - class RequestMatcher* request_matcher, - const base::FilePath& filepath) { - std::string response; - if (filepath.empty() || !base::ReadFileToString(filepath, &response)) - return false; - - expectations_.push(std::make_pair( - request_matcher, ExpectationResponse(kResponseCode200, response))); - return true; -} - -int URLRequestPostInterceptor::GetHitCount() const { - base::AutoLock auto_lock(interceptor_lock_); - return hit_count_; -} - -int URLRequestPostInterceptor::GetCount() const { - base::AutoLock auto_lock(interceptor_lock_); - return static_cast(requests_.size()); -} - -std::vector URLRequestPostInterceptor::GetRequests() const { - base::AutoLock auto_lock(interceptor_lock_); - return requests_; -} - -std::string URLRequestPostInterceptor::GetRequestsAsString() const { - std::vector requests(GetRequests()); - - std::string s = "Requests are:"; - - int i = 0; - for (std::vector::const_iterator it = requests.begin(); - it != requests.end(); ++it) { - s.append(base::StringPrintf("\n (%d): %s", ++i, it->c_str())); - } - - return s; -} - -void URLRequestPostInterceptor::Reset() { - base::AutoLock auto_lock(interceptor_lock_); - hit_count_ = 0; - requests_.clear(); - ClearExpectations(); -} - -class URLRequestPostInterceptor::Delegate : public net::URLRequestInterceptor { - public: - Delegate(const std::string& scheme, - const std::string& hostname, - const scoped_refptr& io_task_runner) - : scheme_(scheme), hostname_(hostname), io_task_runner_(io_task_runner) {} - - void Register() { - DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); - net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( - scheme_, hostname_, scoped_ptr(this)); - } - - void Unregister() { - DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); - for (InterceptorMap::iterator it = interceptors_.begin(); - it != interceptors_.end(); ++it) - delete (*it).second; - net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(scheme_, - hostname_); - } - - void OnCreateInterceptor(URLRequestPostInterceptor* interceptor) { - DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); - DCHECK(interceptors_.find(interceptor->GetUrl()) == interceptors_.end()); - - interceptors_.insert(std::make_pair(interceptor->GetUrl(), interceptor)); - } - - private: - ~Delegate() override {} - - net::URLRequestJob* MaybeInterceptRequest( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const override { - DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); - - // Only intercepts POST. - if (!request->has_upload()) - return NULL; - - GURL url = request->url(); - if (url.has_query()) { - GURL::Replacements replacements; - replacements.ClearQuery(); - url = url.ReplaceComponents(replacements); - } - - InterceptorMap::const_iterator it(interceptors_.find(url)); - if (it == interceptors_.end()) - return NULL; - - // There is an interceptor hooked up for this url. Read the request body, - // check the existing expectations, and handle the matching case by - // popping the expectation off the queue, counting the match, and - // returning a mock object to serve the canned response. - URLRequestPostInterceptor* interceptor(it->second); - - const net::UploadDataStream* stream = request->get_upload(); - const net::UploadBytesElementReader* reader = - (*stream->GetElementReaders())[0]->AsBytesReader(); - const int size = reader->length(); - scoped_refptr buffer(new net::IOBuffer(size)); - const std::string request_body(reader->bytes()); - - { - base::AutoLock auto_lock(interceptor->interceptor_lock_); - interceptor->requests_.push_back(request_body); - if (interceptor->expectations_.empty()) - return NULL; - const URLRequestPostInterceptor::Expectation& expectation( - interceptor->expectations_.front()); - if (expectation.first->Match(request_body)) { - const int response_code(expectation.second.response_code); - const std::string response_body(expectation.second.response_body); - delete expectation.first; - interceptor->expectations_.pop(); - ++interceptor->hit_count_; - - return new URLRequestMockJob(request, network_delegate, response_code, - response_body); - } - } - - return NULL; - } - - typedef std::map InterceptorMap; - InterceptorMap interceptors_; - - const std::string scheme_; - const std::string hostname_; - scoped_refptr io_task_runner_; - - DISALLOW_COPY_AND_ASSIGN(Delegate); -}; - -URLRequestPostInterceptorFactory::URLRequestPostInterceptorFactory( - const std::string& scheme, - const std::string& hostname, - const scoped_refptr& io_task_runner) - : scheme_(scheme), - hostname_(hostname), - io_task_runner_(io_task_runner), - delegate_(new URLRequestPostInterceptor::Delegate(scheme, - hostname, - io_task_runner)) { - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&URLRequestPostInterceptor::Delegate::Register, - base::Unretained(delegate_))); -} - -URLRequestPostInterceptorFactory::~URLRequestPostInterceptorFactory() { - io_task_runner_->PostTask( - FROM_HERE, base::Bind(&URLRequestPostInterceptor::Delegate::Unregister, - base::Unretained(delegate_))); -} - -URLRequestPostInterceptor* URLRequestPostInterceptorFactory::CreateInterceptor( - const base::FilePath& filepath) { - const GURL base_url( - base::StringPrintf("%s://%s", scheme_.c_str(), hostname_.c_str())); - GURL absolute_url(base_url.Resolve(filepath.MaybeAsASCII())); - URLRequestPostInterceptor* interceptor( - new URLRequestPostInterceptor(absolute_url, io_task_runner_)); - bool res = io_task_runner_->PostTask( - FROM_HERE, - base::Bind(&URLRequestPostInterceptor::Delegate::OnCreateInterceptor, - base::Unretained(delegate_), base::Unretained(interceptor))); - if (!res) { - delete interceptor; - return NULL; - } - - return interceptor; -} - -bool PartialMatch::Match(const std::string& actual) const { - return actual.find(expected_) != std::string::npos; -} - -InterceptorFactory::InterceptorFactory( - const scoped_refptr& io_task_runner) - : URLRequestPostInterceptorFactory(POST_INTERCEPT_SCHEME, - POST_INTERCEPT_HOSTNAME, - io_task_runner) { -} - -InterceptorFactory::~InterceptorFactory() { -} - -URLRequestPostInterceptor* InterceptorFactory::CreateInterceptor() { - return CreateInterceptorForPath(POST_INTERCEPT_PATH); -} - -URLRequestPostInterceptor* InterceptorFactory::CreateInterceptorForPath( - const char* url_path) { - return URLRequestPostInterceptorFactory::CreateInterceptor( - base::FilePath::FromUTF8Unsafe(url_path)); -} - -} // namespace update_client diff --git a/components/update_client/test/url_request_post_interceptor.h b/components/update_client/test/url_request_post_interceptor.h deleted file mode 100644 index d261160..0000000 --- a/components/update_client/test/url_request_post_interceptor.h +++ /dev/null @@ -1,165 +0,0 @@ -// 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. - -#ifndef COMPONENTS_UPDATE_CLIENT_TEST_URL_REQUEST_POST_INTERCEPTOR_H_ -#define COMPONENTS_UPDATE_CLIENT_TEST_URL_REQUEST_POST_INTERCEPTOR_H_ - -#include -#include -#include -#include -#include -#include - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/lock.h" -#include "url/gurl.h" - -namespace base { -class FilePath; -class SequencedTaskRunner; -} - -namespace net { -class URLRequest; -} - -namespace update_client { - -// Intercepts requests to a file path, counts them, and captures the body of -// the requests. Optionally, for each request, it can return a canned response -// from a given file. The class maintains a queue of expectations, and returns -// one and only one response for each request that matches and it is -// intercepted. -class URLRequestPostInterceptor { - public: - // Allows a generic string maching interface when setting up expectations. - class RequestMatcher { - public: - virtual bool Match(const std::string& actual) const = 0; - virtual ~RequestMatcher() {} - }; - - // Returns the url that is intercepted. - GURL GetUrl() const; - - // Sets an expection for the body of the POST request and optionally, - // provides a canned response identified by a |file_path| to be returned when - // the expectation is met. If no |file_path| is provided, then an empty - // response body is served. If |response_code| is provided, then an empty - // response body with that response code is returned. - // Returns |true| if the expectation was set. This class takes ownership of - // the |request_matcher| object. - bool ExpectRequest(class RequestMatcher* request_matcher); - bool ExpectRequest(class RequestMatcher* request_matcher, int response_code); - bool ExpectRequest(class RequestMatcher* request_matcher, - const base::FilePath& filepath); - - // Returns how many requests have been intercepted and matched by - // an expectation. One expectation can only be matched by one request. - int GetHitCount() const; - - // Returns how many requests in total have been captured by the interceptor. - int GetCount() const; - - // Returns all requests that have been intercepted, matched or not. - std::vector GetRequests() const; - - // Returns all requests as a string for debugging purposes. - std::string GetRequestsAsString() const; - - // Resets the state of the interceptor so that new expectations can be set. - void Reset(); - - class Delegate; - - private: - friend class URLRequestPostInterceptorFactory; - - static const int kResponseCode200 = 200; - - struct ExpectationResponse { - ExpectationResponse(int code, const std::string& body) - : response_code(code), response_body(body) {} - const int response_code; - const std::string response_body; - }; - typedef std::pair Expectation; - - URLRequestPostInterceptor( - const GURL& url, - const scoped_refptr& io_task_runner); - ~URLRequestPostInterceptor(); - - void ClearExpectations(); - - const GURL url_; - scoped_refptr io_task_runner_; - - mutable base::Lock interceptor_lock_; - mutable int hit_count_; - mutable std::vector requests_; - mutable std::queue expectations_; - - DISALLOW_COPY_AND_ASSIGN(URLRequestPostInterceptor); -}; - -class URLRequestPostInterceptorFactory { - public: - URLRequestPostInterceptorFactory( - const std::string& scheme, - const std::string& hostname, - const scoped_refptr& io_task_runner); - ~URLRequestPostInterceptorFactory(); - - // Creates an interceptor object for the specified url path. Returns NULL - // in case of errors or a valid interceptor object otherwise. The caller - // does not own the returned object. - URLRequestPostInterceptor* CreateInterceptor(const base::FilePath& filepath); - - private: - const std::string scheme_; - const std::string hostname_; - scoped_refptr io_task_runner_; - - // After creation, |delegate_| lives on the IO thread and it is owned by - // a URLRequestFilter after registration. A task to unregister it and - // implicitly destroy it is posted from ~URLRequestPostInterceptorFactory(). - URLRequestPostInterceptor::Delegate* delegate_; - - DISALLOW_COPY_AND_ASSIGN(URLRequestPostInterceptorFactory); -}; - -// Intercepts HTTP POST requests sent to "localhost2". -class InterceptorFactory : public URLRequestPostInterceptorFactory { - public: - explicit InterceptorFactory( - const scoped_refptr& io_task_runner); - ~InterceptorFactory(); - - // Creates an interceptor for the url path defined by POST_INTERCEPT_PATH. - URLRequestPostInterceptor* CreateInterceptor(); - - // Creates an interceptor for the given url path. - URLRequestPostInterceptor* CreateInterceptorForPath(const char* url_path); - - private: - DISALLOW_COPY_AND_ASSIGN(InterceptorFactory); -}; - -class PartialMatch : public URLRequestPostInterceptor::RequestMatcher { - public: - explicit PartialMatch(const std::string& expected) : expected_(expected) {} - bool Match(const std::string& actual) const override; - - private: - const std::string expected_; - - DISALLOW_COPY_AND_ASSIGN(PartialMatch); -}; - -} // namespace update_client - -#endif // COMPONENTS_UPDATE_CLIENT_TEST_URL_REQUEST_POST_INTERCEPTOR_H_ diff --git a/components/update_client/test_configurator.cc b/components/update_client/test_configurator.cc new file mode 100644 index 0000000..9cd59e4 --- /dev/null +++ b/components/update_client/test_configurator.cc @@ -0,0 +1,158 @@ +// 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 "components/update_client/test_configurator.h" + +#include "base/run_loop.h" +#include "base/version.h" +#include "components/update_client/component_patcher_operation.h" +#include "url/gurl.h" + +namespace update_client { + +namespace { + +std::vector MakeDefaultUrls() { + std::vector urls; + urls.push_back(GURL(POST_INTERCEPT_SCHEME + "://" POST_INTERCEPT_HOSTNAME POST_INTERCEPT_PATH)); + return urls; +} + +} // namespace + +TestConfigurator::TestConfigurator( + const scoped_refptr& worker_task_runner, + const scoped_refptr& network_task_runner) + : worker_task_runner_(worker_task_runner), + initial_time_(0), + times_(1), + recheck_time_(0), + ondemand_time_(0), + context_(new net::TestURLRequestContextGetter(network_task_runner)) { +} + +TestConfigurator::~TestConfigurator() { +} + +int TestConfigurator::InitialDelay() const { + return initial_time_; +} + +int TestConfigurator::NextCheckDelay() { + // This is called when a new full cycle of checking for updates is going + // to happen. In test we normally only test one cycle so it is a good + // time to break from the test messageloop Run() method so the test can + // finish. + if (--times_ <= 0) { + quit_closure_.Run(); + return 0; + } + return 1; +} + +int TestConfigurator::StepDelay() const { + return 0; +} + +int TestConfigurator::StepDelayMedium() { + return NextCheckDelay(); +} + +int TestConfigurator::MinimumReCheckWait() const { + return recheck_time_; +} + +int TestConfigurator::OnDemandDelay() const { + return ondemand_time_; +} + +int TestConfigurator::UpdateDelay() const { + return 1; +} + +std::vector TestConfigurator::UpdateUrl() const { + return MakeDefaultUrls(); +} + +std::vector TestConfigurator::PingUrl() const { + return UpdateUrl(); +} + +base::Version TestConfigurator::GetBrowserVersion() const { + // Needs to be larger than the required version in tested component manifests. + return base::Version("30.0"); +} + +std::string TestConfigurator::GetChannel() const { + return "fake_channel_string"; +} + +std::string TestConfigurator::GetLang() const { + return "fake_lang"; +} + +std::string TestConfigurator::GetOSLongName() const { + return "Fake Operating System"; +} + +std::string TestConfigurator::ExtraRequestParams() const { + return "extra=\"foo\""; +} + +size_t TestConfigurator::UrlSizeLimit() const { + return 256; +} + +net::URLRequestContextGetter* TestConfigurator::RequestContext() const { + return context_.get(); +} + +scoped_refptr TestConfigurator::CreateOutOfProcessPatcher() + const { + return NULL; +} + +bool TestConfigurator::DeltasEnabled() const { + return true; +} + +bool TestConfigurator::UseBackgroundDownloader() const { + return false; +} + +// Set how many update checks are called, the default value is just once. +void TestConfigurator::SetLoopCount(int times) { + times_ = times; +} + +void TestConfigurator::SetRecheckTime(int seconds) { + recheck_time_ = seconds; +} + +void TestConfigurator::SetOnDemandTime(int seconds) { + ondemand_time_ = seconds; +} + +void TestConfigurator::SetQuitClosure(const base::Closure& quit_closure) { + quit_closure_ = quit_closure; +} + +void TestConfigurator::SetInitialDelay(int seconds) { + initial_time_ = seconds; +} + +scoped_refptr +TestConfigurator::GetSequencedTaskRunner() const { + DCHECK(worker_task_runner_.get()); + return worker_task_runner_; +} + +scoped_refptr +TestConfigurator::GetSingleThreadTaskRunner() const { + // This is NULL because tests do not use the background downloader. + return NULL; +} + +} // namespace update_client diff --git a/components/update_client/test_configurator.h b/components/update_client/test_configurator.h new file mode 100644 index 0000000..6e441e7 --- /dev/null +++ b/components/update_client/test_configurator.h @@ -0,0 +1,111 @@ +// 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. + +#ifndef COMPONENTS_UPDATE_CLIENT_TEST_CONFIGURATOR_H_ +#define COMPONENTS_UPDATE_CLIENT_TEST_CONFIGURATOR_H_ + +#include +#include +#include + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "components/update_client/configurator.h" +#include "net/url_request/url_request_test_util.h" + +class GURL; + +namespace base { +class SequencedTaskRunner; +class SingleThreadTaskRunner; +} // namespace base + +namespace update_client { + +#define POST_INTERCEPT_SCHEME "https" +#define POST_INTERCEPT_HOSTNAME "localhost2" +#define POST_INTERCEPT_PATH "/update2" + +struct CrxComponent; + +// component 1 has extension id "jebgalgnebhfojomionfpkfelancnnkf", and +// the RSA public key the following hash: +const uint8_t jebg_hash[] = {0x94, 0x16, 0x0b, 0x6d, 0x41, 0x75, 0xe9, 0xec, + 0x8e, 0xd5, 0xfa, 0x54, 0xb0, 0xd2, 0xdd, 0xa5, + 0x6e, 0x05, 0x6b, 0xe8, 0x73, 0x47, 0xf6, 0xc4, + 0x11, 0x9f, 0xbc, 0xb3, 0x09, 0xb3, 0x5b, 0x40}; +// component 2 has extension id "abagagagagagagagagagagagagagagag", and +// the RSA public key the following hash: +const uint8_t abag_hash[] = {0x01, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x01}; +// component 3 has extension id "ihfokbkgjpifnbbojhneepfflplebdkc", and +// the RSA public key the following hash: +const uint8_t ihfo_hash[] = {0x87, 0x5e, 0xa1, 0xa6, 0x9f, 0x85, 0xd1, 0x1e, + 0x97, 0xd4, 0x4f, 0x55, 0xbf, 0xb4, 0x13, 0xa2, + 0xe7, 0xc5, 0xc8, 0xf5, 0x60, 0x19, 0x78, 0x1b, + 0x6d, 0xe9, 0x4c, 0xeb, 0x96, 0x05, 0x42, 0x17}; + +class TestConfigurator : public Configurator { + public: + TestConfigurator( + const scoped_refptr& worker_task_runner, + const scoped_refptr& network_task_runner); + + // Overrrides for Configurator. + int InitialDelay() const override; + int NextCheckDelay() override; + int StepDelay() const override; + int StepDelayMedium() override; + int MinimumReCheckWait() const override; + int OnDemandDelay() const override; + int UpdateDelay() const override; + std::vector UpdateUrl() const override; + std::vector PingUrl() const override; + base::Version GetBrowserVersion() const override; + std::string GetChannel() const override; + std::string GetLang() const override; + std::string GetOSLongName() const override; + std::string ExtraRequestParams() const override; + size_t UrlSizeLimit() const override; + net::URLRequestContextGetter* RequestContext() const override; + scoped_refptr CreateOutOfProcessPatcher() const override; + bool DeltasEnabled() const override; + bool UseBackgroundDownloader() const override; + scoped_refptr GetSequencedTaskRunner() + const override; + scoped_refptr GetSingleThreadTaskRunner() + const override; + + void SetLoopCount(int times); + void SetRecheckTime(int seconds); + void SetOnDemandTime(int seconds); + void SetQuitClosure(const base::Closure& quit_closure); + void SetInitialDelay(int seconds); + + private: + friend class base::RefCountedThreadSafe; + + ~TestConfigurator() override; + + scoped_refptr worker_task_runner_; + scoped_refptr network_task_runner_; + + int initial_time_; + int times_; + int recheck_time_; + int ondemand_time_; + + scoped_refptr context_; + base::Closure quit_closure_; + + DISALLOW_COPY_AND_ASSIGN(TestConfigurator); +}; + +} // namespace update_client + +#endif // COMPONENTS_UPDATE_CLIENT_TEST_CONFIGURATOR_H_ diff --git a/components/update_client/test_installer.cc b/components/update_client/test_installer.cc new file mode 100644 index 0000000..ad6015b --- /dev/null +++ b/components/update_client/test_installer.cc @@ -0,0 +1,85 @@ +// 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 "components/update_client/test_installer.h" + +#include + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/values.h" + +namespace update_client { + +TestInstaller::TestInstaller() : error_(0), install_count_(0) { +} + +void TestInstaller::OnUpdateError(int error) { + error_ = error; +} + +bool TestInstaller::Install(const base::DictionaryValue& manifest, + const base::FilePath& unpack_path) { + ++install_count_; + return base::DeleteFile(unpack_path, true); +} + +bool TestInstaller::GetInstalledFile(const std::string& file, + base::FilePath* installed_file) { + return false; +} + +TestInstaller::~TestInstaller() { +} + +bool TestInstaller::Uninstall() { + return false; +} + +ReadOnlyTestInstaller::ReadOnlyTestInstaller(const base::FilePath& install_dir) + : install_directory_(install_dir) { +} + +ReadOnlyTestInstaller::~ReadOnlyTestInstaller() { +} + +bool ReadOnlyTestInstaller::GetInstalledFile(const std::string& file, + base::FilePath* installed_file) { + *installed_file = install_directory_.AppendASCII(file); + return true; +} + +VersionedTestInstaller::VersionedTestInstaller() { + base::CreateNewTempDirectory(FILE_PATH_LITERAL("TEST_"), &install_directory_); +} + +VersionedTestInstaller::~VersionedTestInstaller() { + base::DeleteFile(install_directory_, true); +} + +bool VersionedTestInstaller::Install(const base::DictionaryValue& manifest, + const base::FilePath& unpack_path) { + std::string version_string; + manifest.GetStringASCII("version", &version_string); + Version version(version_string.c_str()); + + base::FilePath path; + path = install_directory_.AppendASCII(version.GetString()); + base::CreateDirectory(path.DirName()); + if (!base::Move(unpack_path, path)) + return false; + current_version_ = version; + ++install_count_; + return true; +} + +bool VersionedTestInstaller::GetInstalledFile(const std::string& file, + base::FilePath* installed_file) { + base::FilePath path; + path = install_directory_.AppendASCII(current_version_.GetString()); + *installed_file = path.Append(base::FilePath::FromUTF8Unsafe(file)); + return true; +} + +} // namespace update_client diff --git a/components/update_client/test_installer.h b/components/update_client/test_installer.h new file mode 100644 index 0000000..44a6f28 --- /dev/null +++ b/components/update_client/test_installer.h @@ -0,0 +1,84 @@ +// 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. + +#ifndef COMPONENTS_UPDATE_CLIENT_TEST_INSTALLER_H_ +#define COMPONENTS_UPDATE_CLIENT_TEST_INSTALLER_H_ + +#include + +#include "base/compiler_specific.h" +#include "base/files/file_path.h" +#include "components/update_client/update_client.h" + +namespace base { +class DictionaryValue; +} + +namespace update_client { + +// TODO(sorin): consider reducing the number of the installer mocks. +// A TestInstaller is an installer that does nothing for installation except +// increment a counter. +class TestInstaller : public CrxInstaller { + public: + TestInstaller(); + + void OnUpdateError(int error) override; + + bool Install(const base::DictionaryValue& manifest, + const base::FilePath& unpack_path) override; + + bool GetInstalledFile(const std::string& file, + base::FilePath* installed_file) override; + + bool Uninstall() override; + + int error() const { return error_; } + + int install_count() const { return install_count_; } + + protected: + ~TestInstaller() override; + + int error_; + int install_count_; +}; + +// A ReadOnlyTestInstaller is an installer that knows about files in an existing +// directory. It will not write to the directory. +class ReadOnlyTestInstaller : public TestInstaller { + public: + explicit ReadOnlyTestInstaller(const base::FilePath& installed_path); + + bool GetInstalledFile(const std::string& file, + base::FilePath* installed_file) override; + + private: + ~ReadOnlyTestInstaller() override; + + base::FilePath install_directory_; +}; + +// A VersionedTestInstaller is an installer that installs files into versioned +// directories (e.g. somedir/25.23.89.141/). +class VersionedTestInstaller : public TestInstaller { + public: + VersionedTestInstaller(); + + bool Install(const base::DictionaryValue& manifest, + const base::FilePath& unpack_path) override; + + bool GetInstalledFile(const std::string& file, + base::FilePath* installed_file) override; + + private: + ~VersionedTestInstaller() override; + + base::FilePath install_directory_; + Version current_version_; +}; + +} // namespace update_client + +#endif // COMPONENTS_UPDATE_CLIENT_TEST_INSTALLER_H_ diff --git a/components/update_client/update_checker_unittest.cc b/components/update_client/update_checker_unittest.cc new file mode 100644 index 0000000..01fd5ef --- /dev/null +++ b/components/update_client/update_checker_unittest.cc @@ -0,0 +1,237 @@ +// 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 "base/bind.h" +#include "base/bind_helpers.h" +#include "base/compiler_specific.h" +#include "base/files/file_util.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/version.h" +#include "components/update_client/crx_update_item.h" +#include "components/update_client/test_configurator.h" +#include "components/update_client/update_checker.h" +#include "components/update_client/url_request_post_interceptor.h" +#include "net/url_request/url_request_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +using std::string; + +namespace update_client { + +namespace { + +base::FilePath test_file(const char* file) { + base::FilePath path; + PathService::Get(base::DIR_SOURCE_ROOT, &path); + return path.AppendASCII("components") + .AppendASCII("test") + .AppendASCII("data") + .AppendASCII("update_client") + .AppendASCII(file); +} + +} // namespace + +class UpdateCheckerTest : public testing::Test { + public: + UpdateCheckerTest(); + ~UpdateCheckerTest() override; + + // Overrides from testing::Test. + void SetUp() override; + void TearDown() override; + + void UpdateCheckComplete(const GURL& original_url, + int error, + const std::string& error_message, + const UpdateResponse::Results& results); + + protected: + void Quit(); + void RunThreads(); + void RunThreadsUntilIdle(); + + CrxUpdateItem BuildCrxUpdateItem(); + + scoped_refptr config_; + + scoped_ptr update_checker_; + + scoped_ptr interceptor_factory_; + URLRequestPostInterceptor* post_interceptor_; // Owned by the factory. + + GURL original_url_; + int error_; + std::string error_message_; + UpdateResponse::Results results_; + + private: + base::MessageLoopForIO loop_; + base::Closure quit_closure_; + + DISALLOW_COPY_AND_ASSIGN(UpdateCheckerTest); +}; + +UpdateCheckerTest::UpdateCheckerTest() : post_interceptor_(NULL), error_(0) { +} + +UpdateCheckerTest::~UpdateCheckerTest() { +} + +void UpdateCheckerTest::SetUp() { + config_ = new TestConfigurator(base::MessageLoopProxy::current(), + base::MessageLoopProxy::current()); + interceptor_factory_.reset( + new InterceptorFactory(base::MessageLoopProxy::current())); + post_interceptor_ = interceptor_factory_->CreateInterceptor(); + EXPECT_TRUE(post_interceptor_); + + update_checker_.reset(); + + error_ = 0; + error_message_.clear(); + results_ = UpdateResponse::Results(); +} + +void UpdateCheckerTest::TearDown() { + update_checker_.reset(); + + post_interceptor_ = NULL; + interceptor_factory_.reset(); + + config_ = nullptr; + + // The PostInterceptor requires the message loop to run to destruct correctly. + // TODO(sorin): This is fragile and should be fixed. + RunThreadsUntilIdle(); +} + +void UpdateCheckerTest::RunThreads() { + base::RunLoop runloop; + quit_closure_ = runloop.QuitClosure(); + runloop.Run(); + + // Since some tests need to drain currently enqueued tasks such as network + // intercepts on the IO thread, run the threads until they are + // idle. The component updater service won't loop again until the loop count + // is set and the service is started. + RunThreadsUntilIdle(); +} + +void UpdateCheckerTest::RunThreadsUntilIdle() { + base::RunLoop().RunUntilIdle(); +} + +void UpdateCheckerTest::Quit() { + if (!quit_closure_.is_null()) + quit_closure_.Run(); +} + +void UpdateCheckerTest::UpdateCheckComplete( + const GURL& original_url, + int error, + const std::string& error_message, + const UpdateResponse::Results& results) { + original_url_ = original_url; + error_ = error; + error_message_ = error_message; + results_ = results; + Quit(); +} + +CrxUpdateItem UpdateCheckerTest::BuildCrxUpdateItem() { + CrxComponent crx_component; + crx_component.name = "test_jebg"; + crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); + crx_component.installer = NULL; + crx_component.version = base::Version("0.9"); + crx_component.fingerprint = "fp1"; + + CrxUpdateItem crx_update_item; + crx_update_item.state = CrxUpdateItem::State::kNew; + crx_update_item.id = "jebgalgnebhfojomionfpkfelancnnkf"; + crx_update_item.component = crx_component; + + return crx_update_item; +} + +TEST_F(UpdateCheckerTest, UpdateCheckSuccess) { + EXPECT_TRUE(post_interceptor_->ExpectRequest( + new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml"))); + + update_checker_ = UpdateChecker::Create(*config_).Pass(); + + CrxUpdateItem item(BuildCrxUpdateItem()); + std::vector items_to_check; + items_to_check.push_back(&item); + + update_checker_->CheckForUpdates( + items_to_check, "extra=\"params\"", + base::Bind(&UpdateCheckerTest::UpdateCheckComplete, + base::Unretained(this))); + + RunThreads(); + + EXPECT_EQ(1, post_interceptor_->GetHitCount()) + << post_interceptor_->GetRequestsAsString(); + EXPECT_EQ(1, post_interceptor_->GetCount()) + << post_interceptor_->GetRequestsAsString(); + + // Sanity check the request. + EXPECT_NE(string::npos, post_interceptor_->GetRequests()[0].find( + "request protocol=\"3.0\" extra=\"params\"")); + EXPECT_NE( + string::npos, + post_interceptor_->GetRequests()[0].find( + "app appid=\"jebgalgnebhfojomionfpkfelancnnkf\" version=\"0.9\">" + "")); + + EXPECT_NE(string::npos, + post_interceptor_->GetRequests()[0].find("ExpectRequest(new PartialMatch("updatecheck"), 403)); + + update_checker_ = UpdateChecker::Create(*config_).Pass(); + + CrxUpdateItem item(BuildCrxUpdateItem()); + std::vector items_to_check; + items_to_check.push_back(&item); + + update_checker_->CheckForUpdates( + items_to_check, "", base::Bind(&UpdateCheckerTest::UpdateCheckComplete, + base::Unretained(this))); + + RunThreads(); + + EXPECT_EQ(1, post_interceptor_->GetHitCount()) + << post_interceptor_->GetRequestsAsString(); + EXPECT_EQ(1, post_interceptor_->GetCount()) + << post_interceptor_->GetRequestsAsString(); + + EXPECT_EQ(config_->UpdateUrl().front(), original_url_); + EXPECT_EQ(403, error_); + EXPECT_STREQ("network error", error_message_.c_str()); + EXPECT_EQ(0ul, results_.list.size()); +} + +} // namespace update_client diff --git a/components/update_client/update_client_unittest.cc b/components/update_client/update_client_unittest.cc new file mode 100644 index 0000000..3cc3c4f --- /dev/null +++ b/components/update_client/update_client_unittest.cc @@ -0,0 +1,1422 @@ +// Copyright 2015 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 "base/bind.h" +#include "base/bind_helpers.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/location.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/path_service.h" +#include "base/run_loop.h" +#include "base/thread_task_runner_handle.h" +#include "base/values.h" +#include "base/version.h" +#include "components/update_client/crx_update_item.h" +#include "components/update_client/ping_manager.h" +#include "components/update_client/test_configurator.h" +#include "components/update_client/test_installer.h" +#include "components/update_client/update_checker.h" +#include "components/update_client/update_client_internal.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace update_client { + +namespace { + +using base::FilePath; + +// Makes a copy of the file specified by |from_path| in a temporary directory +// and returns the path of the copy. Returns true if successful. Cleans up if +// there was an error creating the copy. +bool MakeTestFile(const FilePath& from_path, FilePath* to_path) { + FilePath temp_dir; + bool result = + CreateNewTempDirectory(FILE_PATH_LITERAL("update_client"), &temp_dir); + if (!result) + return false; + + FilePath temp_file; + result = CreateTemporaryFileInDir(temp_dir, &temp_file); + if (!result) + return false; + + result = CopyFile(from_path, temp_file); + if (!result) { + DeleteFile(temp_file, false); + return false; + } + + *to_path = temp_file; + return true; +} + +using Events = UpdateClient::Observer::Events; + +class MockObserver : public UpdateClient::Observer { + public: + MOCK_METHOD2(OnEvent, void(Events event, const std::string&)); +}; + +class FakePingManagerImpl : public PingManager { + public: + explicit FakePingManagerImpl(const Configurator& config); + ~FakePingManagerImpl() override; + + void OnUpdateComplete(const CrxUpdateItem* item) override; + + const std::vector& items() const; + + private: + std::vector items_; + DISALLOW_COPY_AND_ASSIGN(FakePingManagerImpl); +}; + +FakePingManagerImpl::FakePingManagerImpl(const Configurator& config) + : PingManager(config) { +} + +FakePingManagerImpl::~FakePingManagerImpl() { +} + +void FakePingManagerImpl::OnUpdateComplete(const CrxUpdateItem* item) { + items_.push_back(*item); +} + +const std::vector& FakePingManagerImpl::items() const { + return items_; +} + +} // namespace + +using ::testing::_; +using ::testing::AnyNumber; +using ::testing::DoAll; +using ::testing::InSequence; +using ::testing::Invoke; +using ::testing::Mock; +using ::testing::Return; + +using content::BrowserThread; + +using std::string; + +class UpdateClientTest : public testing::Test { + public: + UpdateClientTest(); + ~UpdateClientTest() override; + + void SetUp() override; + void TearDown() override; + + protected: + void RunThreads(); + + // Returns the full path to a test file. + static base::FilePath TestFilePath(const char* file); + + content::TestBrowserThreadBundle thread_bundle_; + + base::RunLoop runloop_; + base::Closure quit_closure_; + + scoped_refptr config_; + + private: + DISALLOW_COPY_AND_ASSIGN(UpdateClientTest); +}; + +UpdateClientTest::UpdateClientTest() + : config_(new TestConfigurator( + BrowserThread::GetBlockingPool() + ->GetSequencedTaskRunnerWithShutdownBehavior( + BrowserThread::GetBlockingPool()->GetSequenceToken(), + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))) { +} + +UpdateClientTest::~UpdateClientTest() { +} + +void UpdateClientTest::SetUp() { + quit_closure_ = runloop_.QuitClosure(); +} + +void UpdateClientTest::TearDown() { +} + +void UpdateClientTest::RunThreads() { + runloop_.Run(); +} + +base::FilePath UpdateClientTest::TestFilePath(const char* file) { + base::FilePath path; + PathService::Get(base::DIR_SOURCE_ROOT, &path); + return path.AppendASCII("components") + .AppendASCII("test") + .AppendASCII("data") + .AppendASCII("update_client") + .AppendASCII(file); +} + +// Tests the scenario where one update check is done for one CRX. The CRX +// has no update. +TEST_F(UpdateClientTest, OneCrxNoUpdate) { + class DataCallbackFake { + public: + static void Callback(const std::vector& ids, + std::vector* components) { + CrxComponent crx; + crx.name = "test_jebg"; + crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); + crx.version = Version("0.9"); + crx.installer = new TestInstaller; + components->push_back(crx); + } + }; + + class CompletionCallbackFake { + public: + static void Callback(const base::Closure& quit_closure, int error) { + EXPECT_EQ(0, error); + quit_closure.Run(); + } + }; + + class FakeUpdateChecker : public UpdateChecker { + public: + static scoped_ptr Create(const Configurator& config) { + return scoped_ptr(new FakeUpdateChecker()); + } + + bool CheckForUpdates( + const std::vector& items_to_check, + const std::string& additional_attributes, + const UpdateCheckCallback& update_check_callback) override { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", + UpdateResponse::Results())); + return true; + } + }; + + class FakeCrxDownloader : public CrxDownloader { + public: + static scoped_ptr Create( + bool is_background_download, + net::URLRequestContextGetter* context_getter, + const scoped_refptr& url_fetcher_task_runner, + const scoped_refptr& + background_task_runner) { + return scoped_ptr(new FakeCrxDownloader()); + } + + private: + FakeCrxDownloader() : CrxDownloader(scoped_ptr().Pass()) {} + ~FakeCrxDownloader() override {} + + void DoStartDownload(const GURL& url) override { EXPECT_TRUE(false); } + }; + + class FakePingManager : public FakePingManagerImpl { + public: + explicit FakePingManager(const Configurator& config) + : FakePingManagerImpl(config) {} + ~FakePingManager() override { EXPECT_TRUE(items().empty()); } + }; + + scoped_ptr ping_manager(new FakePingManager(*config_)); + scoped_ptr update_client(new UpdateClientImpl( + config_, ping_manager.Pass(), &FakeUpdateChecker::Create, + &FakeCrxDownloader::Create)); + + MockObserver observer; + InSequence seq; + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + + update_client->AddObserver(&observer); + + std::vector ids; + ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf")); + + update_client->Update( + ids, base::Bind(&DataCallbackFake::Callback), + base::Bind(&CompletionCallbackFake::Callback, quit_closure_)); + + RunThreads(); + + update_client->RemoveObserver(&observer); +} + +// Tests the scenario where two CRXs are checked for updates. On CRX has +// an update, the other CRX does not. +TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) { + class DataCallbackFake { + public: + static void Callback(const std::vector& ids, + std::vector* components) { + CrxComponent crx1; + crx1.name = "test_jebg"; + crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); + crx1.version = Version("0.9"); + crx1.installer = new TestInstaller; + + CrxComponent crx2; + crx2.name = "test_abag"; + crx2.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash)); + crx2.version = Version("2.2"); + crx2.installer = new TestInstaller; + + components->push_back(crx1); + components->push_back(crx2); + } + }; + + class CompletionCallbackFake { + public: + static void Callback(const base::Closure& quit_closure, int error) { + EXPECT_EQ(0, error); + quit_closure.Run(); + } + }; + + class FakeUpdateChecker : public UpdateChecker { + public: + static scoped_ptr Create(const Configurator& config) { + return scoped_ptr(new FakeUpdateChecker()); + } + + bool CheckForUpdates( + const std::vector& items_to_check, + const std::string& additional_attributes, + const UpdateCheckCallback& update_check_callback) override { + /* + Fake the following response: + + + + + + + + + + + + + + + + + */ + UpdateResponse::Result::Manifest::Package package; + package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx"; + + UpdateResponse::Result result; + result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf"; + result.crx_urls.push_back(GURL("http://localhost/download/")); + result.manifest.version = "1.0"; + result.manifest.browser_min_version = "11.0.1.0"; + result.manifest.packages.push_back(package); + + UpdateResponse::Results results; + results.list.push_back(result); + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); + return true; + } + }; + + class FakeCrxDownloader : public CrxDownloader { + public: + static scoped_ptr Create( + bool is_background_download, + net::URLRequestContextGetter* context_getter, + const scoped_refptr& url_fetcher_task_runner, + const scoped_refptr& + background_task_runner) { + return scoped_ptr(new FakeCrxDownloader()); + } + + private: + FakeCrxDownloader() : CrxDownloader(scoped_ptr().Pass()) {} + ~FakeCrxDownloader() override {} + + void DoStartDownload(const GURL& url) override { + DownloadMetrics download_metrics; + download_metrics.url = url; + download_metrics.downloader = DownloadMetrics::kNone; + download_metrics.error = 0; + download_metrics.downloaded_bytes = 1843; + download_metrics.total_bytes = 1843; + download_metrics.download_time_ms = 1000; + + FilePath path; + EXPECT_TRUE(MakeTestFile( + TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path)); + + Result result; + result.error = 0; + result.response = path; + result.downloaded_bytes = 1843; + result.total_bytes = 1843; + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, + base::Unretained(this), result)); + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&FakeCrxDownloader::OnDownloadComplete, + base::Unretained(this), true, result, download_metrics)); + } + }; + + class FakePingManager : public FakePingManagerImpl { + public: + explicit FakePingManager(const Configurator& config) + : FakePingManagerImpl(config) {} + ~FakePingManager() override { + const auto& ping_items = items(); + EXPECT_EQ(1U, ping_items.size()); + EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id); + EXPECT_TRUE(base::Version("0.9").Equals(ping_items[0].previous_version)); + EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); + EXPECT_EQ(0, ping_items[0].error_category); + EXPECT_EQ(0, ping_items[0].error_code); + } + }; + + scoped_ptr ping_manager(new FakePingManager(*config_)); + scoped_ptr update_client(new UpdateClientImpl( + config_, ping_manager.Pass(), &FakeUpdateChecker::Create, + &FakeCrxDownloader::Create)); + + MockObserver observer; + { + InSequence seq; + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + } + { + InSequence seq; + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, + "abagagagagagagagagagagagagagagag")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED, + "abagagagagagagagagagagagagagagag")).Times(1); + } + + update_client->AddObserver(&observer); + + std::vector ids; + ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf")); + ids.push_back(std::string("abagagagagagagagagagagagagagagag")); + + update_client->Update( + ids, base::Bind(&DataCallbackFake::Callback), + base::Bind(&CompletionCallbackFake::Callback, quit_closure_)); + + RunThreads(); + + update_client->RemoveObserver(&observer); +} + +// Tests the update check for two CRXs scenario. Both CRXs have updates. +TEST_F(UpdateClientTest, TwoCrxUpdate) { + class DataCallbackFake { + public: + static void Callback(const std::vector& ids, + std::vector* components) { + CrxComponent crx1; + crx1.name = "test_jebg"; + crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); + crx1.version = Version("0.9"); + crx1.installer = new TestInstaller; + + CrxComponent crx2; + crx2.name = "test_ihfo"; + crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash)); + crx2.version = Version("0.8"); + crx2.installer = new TestInstaller; + + components->push_back(crx1); + components->push_back(crx2); + } + }; + + class CompletionCallbackFake { + public: + static void Callback(const base::Closure& quit_closure, int error) { + EXPECT_EQ(0, error); + quit_closure.Run(); + } + }; + + class FakeUpdateChecker : public UpdateChecker { + public: + static scoped_ptr Create(const Configurator& config) { + return scoped_ptr(new FakeUpdateChecker()); + } + + bool CheckForUpdates( + const std::vector& items_to_check, + const std::string& additional_attributes, + const UpdateCheckCallback& update_check_callback) override { + /* + Fake the following response: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + */ + UpdateResponse::Result::Manifest::Package package1; + package1.name = "jebgalgnebhfojomionfpkfelancnnkf.crx"; + + UpdateResponse::Result result1; + result1.extension_id = "jebgalgnebhfojomionfpkfelancnnkf"; + result1.crx_urls.push_back(GURL("http://localhost/download/")); + result1.manifest.version = "1.0"; + result1.manifest.browser_min_version = "11.0.1.0"; + result1.manifest.packages.push_back(package1); + + UpdateResponse::Result::Manifest::Package package2; + package2.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"; + + UpdateResponse::Result result2; + result2.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; + result2.crx_urls.push_back(GURL("http://localhost/download/")); + result2.manifest.version = "1.0"; + result2.manifest.browser_min_version = "11.0.1.0"; + result2.manifest.packages.push_back(package2); + + UpdateResponse::Results results; + results.list.push_back(result1); + results.list.push_back(result2); + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); + return true; + } + }; + + class FakeCrxDownloader : public CrxDownloader { + public: + static scoped_ptr Create( + bool is_background_download, + net::URLRequestContextGetter* context_getter, + const scoped_refptr& url_fetcher_task_runner, + const scoped_refptr& + background_task_runner) { + return scoped_ptr(new FakeCrxDownloader()); + } + + private: + FakeCrxDownloader() : CrxDownloader(scoped_ptr().Pass()) {} + ~FakeCrxDownloader() override {} + + void DoStartDownload(const GURL& url) override { + DownloadMetrics download_metrics; + FilePath path; + Result result; + if (url.path() == "/download/jebgalgnebhfojomionfpkfelancnnkf.crx") { + download_metrics.url = url; + download_metrics.downloader = DownloadMetrics::kNone; + download_metrics.error = 0; + download_metrics.downloaded_bytes = 1843; + download_metrics.total_bytes = 1843; + download_metrics.download_time_ms = 1000; + + EXPECT_TRUE(MakeTestFile( + TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path)); + + result.error = 0; + result.response = path; + result.downloaded_bytes = 1843; + result.total_bytes = 1843; + } else if (url.path() == + "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") { + download_metrics.url = url; + download_metrics.downloader = DownloadMetrics::kNone; + download_metrics.error = 0; + download_metrics.downloaded_bytes = 53638; + download_metrics.total_bytes = 53638; + download_metrics.download_time_ms = 2000; + + EXPECT_TRUE(MakeTestFile( + TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path)); + + result.error = 0; + result.response = path; + result.downloaded_bytes = 53638; + result.total_bytes = 53638; + } else { + NOTREACHED(); + } + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, + base::Unretained(this), result)); + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&FakeCrxDownloader::OnDownloadComplete, + base::Unretained(this), true, result, download_metrics)); + } + }; + + class FakePingManager : public FakePingManagerImpl { + public: + explicit FakePingManager(const Configurator& config) + : FakePingManagerImpl(config) {} + ~FakePingManager() override { + const auto& ping_items = items(); + EXPECT_EQ(2U, ping_items.size()); + EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id); + EXPECT_TRUE(base::Version("0.9").Equals(ping_items[0].previous_version)); + EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); + EXPECT_EQ(0, ping_items[0].error_category); + EXPECT_EQ(0, ping_items[0].error_code); + EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id); + EXPECT_TRUE(base::Version("0.8").Equals(ping_items[1].previous_version)); + EXPECT_TRUE(base::Version("1.0").Equals(ping_items[1].next_version)); + EXPECT_EQ(0, ping_items[1].error_category); + EXPECT_EQ(0, ping_items[1].error_code); + } + }; + + scoped_ptr ping_manager(new FakePingManager(*config_)); + scoped_ptr update_client(new UpdateClientImpl( + config_, ping_manager.Pass(), &FakeUpdateChecker::Create, + &FakeCrxDownloader::Create)); + + MockObserver observer; + { + InSequence seq; + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + } + { + InSequence seq; + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + } + + update_client->AddObserver(&observer); + + std::vector ids; + ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf")); + ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc")); + + update_client->Update( + ids, base::Bind(&DataCallbackFake::Callback), + base::Bind(&CompletionCallbackFake::Callback, quit_closure_)); + + RunThreads(); + + update_client->RemoveObserver(&observer); +} + +// Tests the differential update scenario for one CRX. +TEST_F(UpdateClientTest, OneCrxDiffUpdate) { + class DataCallbackFake { + public: + static void Callback(const std::vector& ids, + std::vector* components) { + static int num_calls = 0; + + // Must use the same stateful installer object. + static scoped_refptr installer( + new VersionedTestInstaller()); + + ++num_calls; + + CrxComponent crx; + crx.name = "test_ihfo"; + crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash)); + crx.installer = installer; + if (num_calls == 1) { + crx.version = Version("0.8"); + } else if (num_calls == 2) { + crx.version = Version("1.0"); + } else { + NOTREACHED(); + } + + components->push_back(crx); + } + }; + + class CompletionCallbackFake { + public: + static void Callback(const base::Closure& quit_closure, int error) { + EXPECT_EQ(0, error); + quit_closure.Run(); + } + }; + + class FakeUpdateChecker : public UpdateChecker { + public: + static scoped_ptr Create(const Configurator& config) { + return scoped_ptr(new FakeUpdateChecker()); + } + + bool CheckForUpdates( + const std::vector& items_to_check, + const std::string& additional_attributes, + const UpdateCheckCallback& update_check_callback) override { + static int num_call = 0; + ++num_call; + + UpdateResponse::Results results; + + if (num_call == 1) { + /* + Fake the following response: + + + + + + + + + + + + + + + + */ + UpdateResponse::Result::Manifest::Package package; + package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"; + package.fingerprint = "1"; + UpdateResponse::Result result; + result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; + result.crx_urls.push_back(GURL("http://localhost/download/")); + result.manifest.version = "1.0"; + result.manifest.browser_min_version = "11.0.1.0"; + result.manifest.packages.push_back(package); + results.list.push_back(result); + } else if (num_call == 2) { + /* + Fake the following response: + + + + + + + + + + + + + + + + + */ + UpdateResponse::Result::Manifest::Package package; + package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"; + package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"; + package.fingerprint = "22"; + UpdateResponse::Result result; + result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; + result.crx_urls.push_back(GURL("http://localhost/download/")); + result.crx_diffurls.push_back(GURL("http://localhost/download/")); + result.manifest.version = "2.0"; + result.manifest.browser_min_version = "11.0.1.0"; + result.manifest.packages.push_back(package); + results.list.push_back(result); + } else { + NOTREACHED(); + } + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); + return true; + } + }; + + class FakeCrxDownloader : public CrxDownloader { + public: + static scoped_ptr Create( + bool is_background_download, + net::URLRequestContextGetter* context_getter, + const scoped_refptr& url_fetcher_task_runner, + const scoped_refptr& + background_task_runner) { + return scoped_ptr(new FakeCrxDownloader()); + } + + private: + FakeCrxDownloader() : CrxDownloader(scoped_ptr().Pass()) {} + ~FakeCrxDownloader() override {} + + void DoStartDownload(const GURL& url) override { + DownloadMetrics download_metrics; + FilePath path; + Result result; + if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") { + download_metrics.url = url; + download_metrics.downloader = DownloadMetrics::kNone; + download_metrics.error = 0; + download_metrics.downloaded_bytes = 53638; + download_metrics.total_bytes = 53638; + download_metrics.download_time_ms = 2000; + + EXPECT_TRUE(MakeTestFile( + TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path)); + + result.error = 0; + result.response = path; + result.downloaded_bytes = 53638; + result.total_bytes = 53638; + } else if (url.path() == + "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") { + download_metrics.url = url; + download_metrics.downloader = DownloadMetrics::kNone; + download_metrics.error = 0; + download_metrics.downloaded_bytes = 2105; + download_metrics.total_bytes = 2105; + download_metrics.download_time_ms = 1000; + + EXPECT_TRUE(MakeTestFile( + TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path)); + + result.error = 0; + result.response = path; + result.downloaded_bytes = 2105; + result.total_bytes = 2105; + } else { + NOTREACHED(); + } + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, + base::Unretained(this), result)); + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&FakeCrxDownloader::OnDownloadComplete, + base::Unretained(this), true, result, download_metrics)); + } + }; + + class FakePingManager : public FakePingManagerImpl { + public: + explicit FakePingManager(const Configurator& config) + : FakePingManagerImpl(config) {} + ~FakePingManager() override { + const auto& ping_items = items(); + EXPECT_EQ(2U, ping_items.size()); + EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[0].id); + EXPECT_TRUE(base::Version("0.8").Equals(ping_items[0].previous_version)); + EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); + EXPECT_EQ(0, ping_items[0].error_category); + EXPECT_EQ(0, ping_items[0].error_code); + EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id); + EXPECT_TRUE(base::Version("1.0").Equals(ping_items[1].previous_version)); + EXPECT_TRUE(base::Version("2.0").Equals(ping_items[1].next_version)); + EXPECT_EQ(0, ping_items[1].diff_error_category); + EXPECT_EQ(0, ping_items[1].diff_error_code); + } + }; + + scoped_ptr ping_manager(new FakePingManager(*config_)); + scoped_ptr update_client(new UpdateClientImpl( + config_, ping_manager.Pass(), &FakeUpdateChecker::Create, + &FakeCrxDownloader::Create)); + + MockObserver observer; + { + InSequence seq; + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + } + + update_client->AddObserver(&observer); + + std::vector ids; + ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc")); + + { + base::RunLoop runloop; + update_client->Update( + ids, base::Bind(&DataCallbackFake::Callback), + base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); + runloop.Run(); + } + + { + base::RunLoop runloop; + update_client->Update( + ids, base::Bind(&DataCallbackFake::Callback), + base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); + runloop.Run(); + } + + update_client->RemoveObserver(&observer); +} + +// Tests the update scenario for one CRX where the CRX installer returns +// an error. +TEST_F(UpdateClientTest, OneCrxInstallError) { + class MockInstaller : public CrxInstaller { + public: + MOCK_METHOD1(OnUpdateError, void(int error)); + MOCK_METHOD2(Install, + bool(const base::DictionaryValue& manifest, + const base::FilePath& unpack_path)); + MOCK_METHOD2(GetInstalledFile, + bool(const std::string& file, base::FilePath* installed_file)); + MOCK_METHOD0(Uninstall, bool()); + + static void OnInstall(const base::DictionaryValue& manifest, + const base::FilePath& unpack_path) { + base::DeleteFile(unpack_path, true); + } + + protected: + ~MockInstaller() override {} + }; + + class DataCallbackFake { + public: + static void Callback(const std::vector& ids, + std::vector* components) { + scoped_refptr installer(new MockInstaller()); + + EXPECT_CALL(*installer, OnUpdateError(_)).Times(0); + EXPECT_CALL(*installer, Install(_, _)) + .WillOnce(DoAll(Invoke(MockInstaller::OnInstall), Return(false))); + EXPECT_CALL(*installer, GetInstalledFile(_, _)).Times(0); + EXPECT_CALL(*installer, Uninstall()).Times(0); + + CrxComponent crx; + crx.name = "test_jebg"; + crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash)); + crx.version = Version("0.9"); + crx.installer = installer; + components->push_back(crx); + } + }; + + class CompletionCallbackFake { + public: + static void Callback(const base::Closure& quit_closure, int error) { + EXPECT_EQ(0, error); + quit_closure.Run(); + } + }; + + class FakeUpdateChecker : public UpdateChecker { + public: + static scoped_ptr Create(const Configurator& config) { + return scoped_ptr(new FakeUpdateChecker()); + } + + bool CheckForUpdates( + const std::vector& items_to_check, + const std::string& additional_attributes, + const UpdateCheckCallback& update_check_callback) override { + /* + Fake the following response: + + + + + + + + + + + + + + + + + */ + UpdateResponse::Result::Manifest::Package package; + package.name = "jebgalgnebhfojomionfpkfelancnnkf.crx"; + + UpdateResponse::Result result; + result.extension_id = "jebgalgnebhfojomionfpkfelancnnkf"; + result.crx_urls.push_back(GURL("http://localhost/download/")); + result.manifest.version = "1.0"; + result.manifest.browser_min_version = "11.0.1.0"; + result.manifest.packages.push_back(package); + + UpdateResponse::Results results; + results.list.push_back(result); + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); + return true; + } + }; + + class FakeCrxDownloader : public CrxDownloader { + public: + static scoped_ptr Create( + bool is_background_download, + net::URLRequestContextGetter* context_getter, + const scoped_refptr& url_fetcher_task_runner, + const scoped_refptr& + background_task_runner) { + return scoped_ptr(new FakeCrxDownloader()); + } + + private: + FakeCrxDownloader() : CrxDownloader(scoped_ptr().Pass()) {} + ~FakeCrxDownloader() override {} + + void DoStartDownload(const GURL& url) override { + DownloadMetrics download_metrics; + download_metrics.url = url; + download_metrics.downloader = DownloadMetrics::kNone; + download_metrics.error = 0; + download_metrics.downloaded_bytes = 1843; + download_metrics.total_bytes = 1843; + download_metrics.download_time_ms = 1000; + + FilePath path; + EXPECT_TRUE(MakeTestFile( + TestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), &path)); + + Result result; + result.error = 0; + result.response = path; + result.downloaded_bytes = 1843; + result.total_bytes = 1843; + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, + base::Unretained(this), result)); + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&FakeCrxDownloader::OnDownloadComplete, + base::Unretained(this), true, result, download_metrics)); + } + }; + + class FakePingManager : public FakePingManagerImpl { + public: + explicit FakePingManager(const Configurator& config) + : FakePingManagerImpl(config) {} + ~FakePingManager() override { + const auto& ping_items = items(); + EXPECT_EQ(1U, ping_items.size()); + EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_items[0].id); + EXPECT_TRUE(base::Version("0.9").Equals(ping_items[0].previous_version)); + EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); + EXPECT_EQ(3, ping_items[0].error_category); // kInstallError. + EXPECT_EQ(9, ping_items[0].error_code); // kInstallerError. + } + }; + + scoped_ptr ping_manager(new FakePingManager(*config_)); + scoped_ptr update_client(new UpdateClientImpl( + config_, ping_manager.Pass(), &FakeUpdateChecker::Create, + &FakeCrxDownloader::Create)); + + MockObserver observer; + { + InSequence seq; + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_NOT_UPDATED, + "jebgalgnebhfojomionfpkfelancnnkf")).Times(1); + } + + update_client->AddObserver(&observer); + + std::vector ids; + ids.push_back(std::string("jebgalgnebhfojomionfpkfelancnnkf")); + + update_client->Update( + ids, base::Bind(&DataCallbackFake::Callback), + base::Bind(&CompletionCallbackFake::Callback, quit_closure_)); + + RunThreads(); + + update_client->RemoveObserver(&observer); +} + +// Tests the fallback from differential to full update scenario for one CRX. +TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) { + class DataCallbackFake { + public: + static void Callback(const std::vector& ids, + std::vector* components) { + static int num_calls = 0; + + // Must use the same stateful installer object. + static scoped_refptr installer( + new VersionedTestInstaller()); + + ++num_calls; + + CrxComponent crx; + crx.name = "test_ihfo"; + crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash)); + crx.installer = installer; + if (num_calls == 1) { + crx.version = Version("0.8"); + } else if (num_calls == 2) { + crx.version = Version("1.0"); + } else { + NOTREACHED(); + } + + components->push_back(crx); + } + }; + + class CompletionCallbackFake { + public: + static void Callback(const base::Closure& quit_closure, int error) { + EXPECT_EQ(0, error); + quit_closure.Run(); + } + }; + + class FakeUpdateChecker : public UpdateChecker { + public: + static scoped_ptr Create(const Configurator& config) { + return scoped_ptr(new FakeUpdateChecker()); + } + + bool CheckForUpdates( + const std::vector& items_to_check, + const std::string& additional_attributes, + const UpdateCheckCallback& update_check_callback) override { + static int num_call = 0; + ++num_call; + + UpdateResponse::Results results; + + if (num_call == 1) { + /* + Fake the following response: + + + + + + + + + + + + + + + + */ + UpdateResponse::Result::Manifest::Package package; + package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"; + package.fingerprint = "1"; + UpdateResponse::Result result; + result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; + result.crx_urls.push_back(GURL("http://localhost/download/")); + result.manifest.version = "1.0"; + result.manifest.browser_min_version = "11.0.1.0"; + result.manifest.packages.push_back(package); + results.list.push_back(result); + } else if (num_call == 2) { + /* + Fake the following response: + + + + + + + + + + + + + + + + + */ + UpdateResponse::Result::Manifest::Package package; + package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"; + package.namediff = "ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"; + package.fingerprint = "22"; + UpdateResponse::Result result; + result.extension_id = "ihfokbkgjpifnbbojhneepfflplebdkc"; + result.crx_urls.push_back(GURL("http://localhost/download/")); + result.crx_diffurls.push_back(GURL("http://localhost/download/")); + result.manifest.version = "2.0"; + result.manifest.browser_min_version = "11.0.1.0"; + result.manifest.packages.push_back(package); + results.list.push_back(result); + } else { + NOTREACHED(); + } + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(update_check_callback, GURL(), 0, "", results)); + return true; + } + }; + + class FakeCrxDownloader : public CrxDownloader { + public: + static scoped_ptr Create( + bool is_background_download, + net::URLRequestContextGetter* context_getter, + const scoped_refptr& url_fetcher_task_runner, + const scoped_refptr& + background_task_runner) { + return scoped_ptr(new FakeCrxDownloader()); + } + + private: + FakeCrxDownloader() : CrxDownloader(scoped_ptr().Pass()) {} + ~FakeCrxDownloader() override {} + + void DoStartDownload(const GURL& url) override { + DownloadMetrics download_metrics; + FilePath path; + Result result; + if (url.path() == "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") { + download_metrics.url = url; + download_metrics.downloader = DownloadMetrics::kNone; + download_metrics.error = 0; + download_metrics.downloaded_bytes = 53638; + download_metrics.total_bytes = 53638; + download_metrics.download_time_ms = 2000; + + EXPECT_TRUE(MakeTestFile( + TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path)); + + result.error = 0; + result.response = path; + result.downloaded_bytes = 53638; + result.total_bytes = 53638; + } else if (url.path() == + "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx") { + // A download error is injected on this execution path. + download_metrics.url = url; + download_metrics.downloader = DownloadMetrics::kNone; + download_metrics.error = -1; + download_metrics.downloaded_bytes = 0; + download_metrics.total_bytes = 2105; + download_metrics.download_time_ms = 1000; + + EXPECT_TRUE(MakeTestFile( + TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1to2.crx"), &path)); + + result.error = -1; + result.response = path; + result.downloaded_bytes = 0; + result.total_bytes = 2105; + } else if (url.path() == + "/download/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx") { + download_metrics.url = url; + download_metrics.downloader = DownloadMetrics::kNone; + download_metrics.error = 0; + download_metrics.downloaded_bytes = 53855; + download_metrics.total_bytes = 53855; + download_metrics.download_time_ms = 1000; + + EXPECT_TRUE(MakeTestFile( + TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_2.crx"), &path)); + + result.error = 0; + result.response = path; + result.downloaded_bytes = 53855; + result.total_bytes = 53855; + } + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&FakeCrxDownloader::OnDownloadProgress, + base::Unretained(this), result)); + + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&FakeCrxDownloader::OnDownloadComplete, + base::Unretained(this), true, result, download_metrics)); + } + }; + + class FakePingManager : public FakePingManagerImpl { + public: + explicit FakePingManager(const Configurator& config) + : FakePingManagerImpl(config) {} + ~FakePingManager() override { + const auto& ping_items = items(); + EXPECT_EQ(2U, ping_items.size()); + EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[0].id); + EXPECT_TRUE(base::Version("0.8").Equals(ping_items[0].previous_version)); + EXPECT_TRUE(base::Version("1.0").Equals(ping_items[0].next_version)); + EXPECT_EQ(0, ping_items[0].error_category); + EXPECT_EQ(0, ping_items[0].error_code); + EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_items[1].id); + EXPECT_TRUE(base::Version("1.0").Equals(ping_items[1].previous_version)); + EXPECT_TRUE(base::Version("2.0").Equals(ping_items[1].next_version)); + EXPECT_TRUE(ping_items[1].diff_update_failed); + EXPECT_EQ(1, ping_items[1].diff_error_category); // kNetworkError. + EXPECT_EQ(-1, ping_items[1].diff_error_code); + } + }; + + scoped_ptr ping_manager(new FakePingManager(*config_)); + scoped_ptr update_client(new UpdateClientImpl( + config_, ping_manager.Pass(), &FakeUpdateChecker::Create, + &FakeCrxDownloader::Create)); + + MockObserver observer; + { + InSequence seq; + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED, + "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1); + } + + update_client->AddObserver(&observer); + + std::vector ids; + ids.push_back(std::string("ihfokbkgjpifnbbojhneepfflplebdkc")); + + { + base::RunLoop runloop; + update_client->Update( + ids, base::Bind(&DataCallbackFake::Callback), + base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); + runloop.Run(); + } + + { + base::RunLoop runloop; + update_client->Update( + ids, base::Bind(&DataCallbackFake::Callback), + base::Bind(&CompletionCallbackFake::Callback, runloop.QuitClosure())); + runloop.Run(); + } + + update_client->RemoveObserver(&observer); +} + +} // namespace update_client diff --git a/components/update_client/update_response_unittest.cc b/components/update_client/update_response_unittest.cc new file mode 100644 index 0000000..e106916 --- /dev/null +++ b/components/update_client/update_response_unittest.cc @@ -0,0 +1,302 @@ +// 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 "base/memory/scoped_vector.h" +#include "components/update_client/update_response.h" +#include "libxml/globals.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace update_client { + +const char* kValidXml = + "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +const char* valid_xml_with_hash = + "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +const char* valid_xml_with_invalid_sizes = + "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +const char* kInvalidValidXmlMissingCodebase = + "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +const char* kMissingAppId = + "" + "" + " " + " " + " " + ""; + +const char* kInvalidCodebase = + "" + "" + " " + " " + " " + ""; + +const char* kMissingVersion = + "" + "" + " " + " " + " " + ""; + +const char* kInvalidVersion = + "" + "" + " " + " " + " " + ""; + +// The v3 version of the protocol is not using namespaces. However, the parser +// must be able to parse responses that include namespaces. +const char* kUsesNamespacePrefix = + "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +// Includes unrelated tags from other xml namespaces - this should +// not cause problems. +const char* kSimilarTagnames = + "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +// Includes a tag. +const char* kWithDaystart = + "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +// Indicates no updates available - this should not be a parse error. +const char* kNoUpdate = + "" + "" + " " + " " + " " + ""; + +// Includes two tags, one with an error. +const char* kTwoAppsOneError = + "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +TEST(ComponentUpdaterUpdateResponseTest, TestParser) { + UpdateResponse parser; + + // Test parsing of a number of invalid xml cases + EXPECT_FALSE(parser.Parse(std::string())); + EXPECT_FALSE(parser.errors().empty()); + + EXPECT_TRUE(parser.Parse(kMissingAppId)); + EXPECT_TRUE(parser.results().list.empty()); + EXPECT_FALSE(parser.errors().empty()); + + EXPECT_TRUE(parser.Parse(kInvalidCodebase)); + EXPECT_TRUE(parser.results().list.empty()); + EXPECT_FALSE(parser.errors().empty()); + + EXPECT_TRUE(parser.Parse(kMissingVersion)); + EXPECT_TRUE(parser.results().list.empty()); + EXPECT_FALSE(parser.errors().empty()); + + EXPECT_TRUE(parser.Parse(kInvalidVersion)); + EXPECT_TRUE(parser.results().list.empty()); + EXPECT_FALSE(parser.errors().empty()); + + EXPECT_TRUE(parser.Parse(kInvalidValidXmlMissingCodebase)); + EXPECT_TRUE(parser.results().list.empty()); + EXPECT_FALSE(parser.errors().empty()); + + // Parse some valid XML, and check that all params came out as expected + EXPECT_TRUE(parser.Parse(kValidXml)); + EXPECT_TRUE(parser.errors().empty()); + EXPECT_EQ(1u, parser.results().list.size()); + const UpdateResponse::Result* firstResult = &parser.results().list[0]; + EXPECT_EQ(1u, firstResult->crx_urls.size()); + EXPECT_EQ(GURL("http://example.com/"), firstResult->crx_urls[0]); + EXPECT_EQ(GURL("http://diff.example.com/"), firstResult->crx_diffurls[0]); + EXPECT_EQ("1.2.3.4", firstResult->manifest.version); + EXPECT_EQ("2.0.143.0", firstResult->manifest.browser_min_version); + EXPECT_EQ(1u, firstResult->manifest.packages.size()); + EXPECT_EQ("extension_1_2_3_4.crx", firstResult->manifest.packages[0].name); + + // Parse some xml that uses namespace prefixes. + EXPECT_TRUE(parser.Parse(kUsesNamespacePrefix)); + EXPECT_TRUE(parser.errors().empty()); + EXPECT_TRUE(parser.Parse(kSimilarTagnames)); + EXPECT_TRUE(parser.errors().empty()); + xmlCleanupGlobals(); + + // Parse xml with hash value + EXPECT_TRUE(parser.Parse(valid_xml_with_hash)); + EXPECT_TRUE(parser.errors().empty()); + EXPECT_FALSE(parser.results().list.empty()); + firstResult = &parser.results().list[0]; + EXPECT_FALSE(firstResult->manifest.packages.empty()); + EXPECT_EQ("1234", firstResult->manifest.packages[0].hash_sha256); + + // Parse xml with package size value + EXPECT_TRUE(parser.Parse(valid_xml_with_invalid_sizes)); + EXPECT_TRUE(parser.errors().empty()); + EXPECT_FALSE(parser.results().list.empty()); + firstResult = &parser.results().list[0]; + EXPECT_FALSE(firstResult->manifest.packages.empty()); + EXPECT_EQ(1234, firstResult->manifest.packages[0].size); + EXPECT_EQ(-1234, firstResult->manifest.packages[1].size); + EXPECT_EQ(0, firstResult->manifest.packages[2].size); + EXPECT_EQ(0, firstResult->manifest.packages[3].size); + EXPECT_EQ(0, firstResult->manifest.packages[4].size); + EXPECT_EQ(0, firstResult->manifest.packages[5].size); + + // Parse xml with a element. + EXPECT_TRUE(parser.Parse(kWithDaystart)); + EXPECT_TRUE(parser.errors().empty()); + EXPECT_FALSE(parser.results().list.empty()); + EXPECT_EQ(parser.results().daystart_elapsed_seconds, 456); + + // Parse a no-update response. + EXPECT_TRUE(parser.Parse(kNoUpdate)); + EXPECT_TRUE(parser.errors().empty()); + EXPECT_FALSE(parser.results().list.empty()); + firstResult = &parser.results().list[0]; + EXPECT_EQ(firstResult->extension_id, "12345"); + EXPECT_EQ(firstResult->manifest.version, ""); + + // Parse xml with one error and one success tag. + EXPECT_TRUE(parser.Parse(kTwoAppsOneError)); + EXPECT_FALSE(parser.errors().empty()); + EXPECT_EQ(1u, parser.results().list.size()); + firstResult = &parser.results().list[0]; + EXPECT_EQ(firstResult->extension_id, "bbbbbbbb"); +} + +} // namespace update_client diff --git a/components/update_client/url_request_post_interceptor.cc b/components/update_client/url_request_post_interceptor.cc new file mode 100644 index 0000000..caf179a --- /dev/null +++ b/components/update_client/url_request_post_interceptor.cc @@ -0,0 +1,301 @@ +// 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 "components/update_client/url_request_post_interceptor.h" + +#include "base/files/file_util.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/stringprintf.h" +#include "components/update_client/test_configurator.h" +#include "net/base/upload_bytes_element_reader.h" +#include "net/base/upload_data_stream.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_filter.h" +#include "net/url_request/url_request_interceptor.h" +#include "net/url_request/url_request_simple_job.h" +#include "net/url_request/url_request_test_util.h" + +namespace update_client { + +// Returns a canned response. +class URLRequestMockJob : public net::URLRequestSimpleJob { + public: + URLRequestMockJob(net::URLRequest* request, + net::NetworkDelegate* network_delegate, + int response_code, + const std::string& response_body) + : net::URLRequestSimpleJob(request, network_delegate), + response_code_(response_code), + response_body_(response_body) {} + + protected: + int GetResponseCode() const override { return response_code_; } + + int GetData(std::string* mime_type, + std::string* charset, + std::string* data, + const net::CompletionCallback& callback) const override { + mime_type->assign("text/plain"); + charset->assign("US-ASCII"); + data->assign(response_body_); + return net::OK; + } + + private: + ~URLRequestMockJob() override {} + + int response_code_; + std::string response_body_; + DISALLOW_COPY_AND_ASSIGN(URLRequestMockJob); +}; + +URLRequestPostInterceptor::URLRequestPostInterceptor( + const GURL& url, + const scoped_refptr& io_task_runner) + : url_(url), io_task_runner_(io_task_runner), hit_count_(0) { +} + +URLRequestPostInterceptor::~URLRequestPostInterceptor() { + DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); + ClearExpectations(); +} + +void URLRequestPostInterceptor::ClearExpectations() { + while (!expectations_.empty()) { + Expectation expectation(expectations_.front()); + delete expectation.first; + expectations_.pop(); + } +} + +GURL URLRequestPostInterceptor::GetUrl() const { + return url_; +} + +bool URLRequestPostInterceptor::ExpectRequest( + class RequestMatcher* request_matcher) { + expectations_.push(std::make_pair(request_matcher, + ExpectationResponse(kResponseCode200, ""))); + return true; +} + +bool URLRequestPostInterceptor::ExpectRequest( + class RequestMatcher* request_matcher, + int response_code) { + expectations_.push( + std::make_pair(request_matcher, ExpectationResponse(response_code, ""))); + return true; +} + +bool URLRequestPostInterceptor::ExpectRequest( + class RequestMatcher* request_matcher, + const base::FilePath& filepath) { + std::string response; + if (filepath.empty() || !base::ReadFileToString(filepath, &response)) + return false; + + expectations_.push(std::make_pair( + request_matcher, ExpectationResponse(kResponseCode200, response))); + return true; +} + +int URLRequestPostInterceptor::GetHitCount() const { + base::AutoLock auto_lock(interceptor_lock_); + return hit_count_; +} + +int URLRequestPostInterceptor::GetCount() const { + base::AutoLock auto_lock(interceptor_lock_); + return static_cast(requests_.size()); +} + +std::vector URLRequestPostInterceptor::GetRequests() const { + base::AutoLock auto_lock(interceptor_lock_); + return requests_; +} + +std::string URLRequestPostInterceptor::GetRequestsAsString() const { + std::vector requests(GetRequests()); + + std::string s = "Requests are:"; + + int i = 0; + for (std::vector::const_iterator it = requests.begin(); + it != requests.end(); ++it) { + s.append(base::StringPrintf("\n (%d): %s", ++i, it->c_str())); + } + + return s; +} + +void URLRequestPostInterceptor::Reset() { + base::AutoLock auto_lock(interceptor_lock_); + hit_count_ = 0; + requests_.clear(); + ClearExpectations(); +} + +class URLRequestPostInterceptor::Delegate : public net::URLRequestInterceptor { + public: + Delegate(const std::string& scheme, + const std::string& hostname, + const scoped_refptr& io_task_runner) + : scheme_(scheme), hostname_(hostname), io_task_runner_(io_task_runner) {} + + void Register() { + DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); + net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( + scheme_, hostname_, scoped_ptr(this)); + } + + void Unregister() { + DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); + for (InterceptorMap::iterator it = interceptors_.begin(); + it != interceptors_.end(); ++it) + delete (*it).second; + net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(scheme_, + hostname_); + } + + void OnCreateInterceptor(URLRequestPostInterceptor* interceptor) { + DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); + DCHECK(interceptors_.find(interceptor->GetUrl()) == interceptors_.end()); + + interceptors_.insert(std::make_pair(interceptor->GetUrl(), interceptor)); + } + + private: + ~Delegate() override {} + + net::URLRequestJob* MaybeInterceptRequest( + net::URLRequest* request, + net::NetworkDelegate* network_delegate) const override { + DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); + + // Only intercepts POST. + if (!request->has_upload()) + return NULL; + + GURL url = request->url(); + if (url.has_query()) { + GURL::Replacements replacements; + replacements.ClearQuery(); + url = url.ReplaceComponents(replacements); + } + + InterceptorMap::const_iterator it(interceptors_.find(url)); + if (it == interceptors_.end()) + return NULL; + + // There is an interceptor hooked up for this url. Read the request body, + // check the existing expectations, and handle the matching case by + // popping the expectation off the queue, counting the match, and + // returning a mock object to serve the canned response. + URLRequestPostInterceptor* interceptor(it->second); + + const net::UploadDataStream* stream = request->get_upload(); + const net::UploadBytesElementReader* reader = + (*stream->GetElementReaders())[0]->AsBytesReader(); + const int size = reader->length(); + scoped_refptr buffer(new net::IOBuffer(size)); + const std::string request_body(reader->bytes()); + + { + base::AutoLock auto_lock(interceptor->interceptor_lock_); + interceptor->requests_.push_back(request_body); + if (interceptor->expectations_.empty()) + return NULL; + const URLRequestPostInterceptor::Expectation& expectation( + interceptor->expectations_.front()); + if (expectation.first->Match(request_body)) { + const int response_code(expectation.second.response_code); + const std::string response_body(expectation.second.response_body); + delete expectation.first; + interceptor->expectations_.pop(); + ++interceptor->hit_count_; + + return new URLRequestMockJob(request, network_delegate, response_code, + response_body); + } + } + + return NULL; + } + + typedef std::map InterceptorMap; + InterceptorMap interceptors_; + + const std::string scheme_; + const std::string hostname_; + scoped_refptr io_task_runner_; + + DISALLOW_COPY_AND_ASSIGN(Delegate); +}; + +URLRequestPostInterceptorFactory::URLRequestPostInterceptorFactory( + const std::string& scheme, + const std::string& hostname, + const scoped_refptr& io_task_runner) + : scheme_(scheme), + hostname_(hostname), + io_task_runner_(io_task_runner), + delegate_(new URLRequestPostInterceptor::Delegate(scheme, + hostname, + io_task_runner)) { + io_task_runner_->PostTask( + FROM_HERE, base::Bind(&URLRequestPostInterceptor::Delegate::Register, + base::Unretained(delegate_))); +} + +URLRequestPostInterceptorFactory::~URLRequestPostInterceptorFactory() { + io_task_runner_->PostTask( + FROM_HERE, base::Bind(&URLRequestPostInterceptor::Delegate::Unregister, + base::Unretained(delegate_))); +} + +URLRequestPostInterceptor* URLRequestPostInterceptorFactory::CreateInterceptor( + const base::FilePath& filepath) { + const GURL base_url( + base::StringPrintf("%s://%s", scheme_.c_str(), hostname_.c_str())); + GURL absolute_url(base_url.Resolve(filepath.MaybeAsASCII())); + URLRequestPostInterceptor* interceptor( + new URLRequestPostInterceptor(absolute_url, io_task_runner_)); + bool res = io_task_runner_->PostTask( + FROM_HERE, + base::Bind(&URLRequestPostInterceptor::Delegate::OnCreateInterceptor, + base::Unretained(delegate_), base::Unretained(interceptor))); + if (!res) { + delete interceptor; + return NULL; + } + + return interceptor; +} + +bool PartialMatch::Match(const std::string& actual) const { + return actual.find(expected_) != std::string::npos; +} + +InterceptorFactory::InterceptorFactory( + const scoped_refptr& io_task_runner) + : URLRequestPostInterceptorFactory(POST_INTERCEPT_SCHEME, + POST_INTERCEPT_HOSTNAME, + io_task_runner) { +} + +InterceptorFactory::~InterceptorFactory() { +} + +URLRequestPostInterceptor* InterceptorFactory::CreateInterceptor() { + return CreateInterceptorForPath(POST_INTERCEPT_PATH); +} + +URLRequestPostInterceptor* InterceptorFactory::CreateInterceptorForPath( + const char* url_path) { + return URLRequestPostInterceptorFactory::CreateInterceptor( + base::FilePath::FromUTF8Unsafe(url_path)); +} + +} // namespace update_client diff --git a/components/update_client/url_request_post_interceptor.h b/components/update_client/url_request_post_interceptor.h new file mode 100644 index 0000000..15672bc --- /dev/null +++ b/components/update_client/url_request_post_interceptor.h @@ -0,0 +1,165 @@ +// 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. + +#ifndef COMPONENTS_UPDATE_CLIENT_URL_REQUEST_POST_INTERCEPTOR_H_ +#define COMPONENTS_UPDATE_CLIENT_URL_REQUEST_POST_INTERCEPTOR_H_ + +#include +#include +#include +#include +#include +#include + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#include "url/gurl.h" + +namespace base { +class FilePath; +class SequencedTaskRunner; +} + +namespace net { +class URLRequest; +} + +namespace update_client { + +// Intercepts requests to a file path, counts them, and captures the body of +// the requests. Optionally, for each request, it can return a canned response +// from a given file. The class maintains a queue of expectations, and returns +// one and only one response for each request that matches and it is +// intercepted. +class URLRequestPostInterceptor { + public: + // Allows a generic string maching interface when setting up expectations. + class RequestMatcher { + public: + virtual bool Match(const std::string& actual) const = 0; + virtual ~RequestMatcher() {} + }; + + // Returns the url that is intercepted. + GURL GetUrl() const; + + // Sets an expection for the body of the POST request and optionally, + // provides a canned response identified by a |file_path| to be returned when + // the expectation is met. If no |file_path| is provided, then an empty + // response body is served. If |response_code| is provided, then an empty + // response body with that response code is returned. + // Returns |true| if the expectation was set. This class takes ownership of + // the |request_matcher| object. + bool ExpectRequest(class RequestMatcher* request_matcher); + bool ExpectRequest(class RequestMatcher* request_matcher, int response_code); + bool ExpectRequest(class RequestMatcher* request_matcher, + const base::FilePath& filepath); + + // Returns how many requests have been intercepted and matched by + // an expectation. One expectation can only be matched by one request. + int GetHitCount() const; + + // Returns how many requests in total have been captured by the interceptor. + int GetCount() const; + + // Returns all requests that have been intercepted, matched or not. + std::vector GetRequests() const; + + // Returns all requests as a string for debugging purposes. + std::string GetRequestsAsString() const; + + // Resets the state of the interceptor so that new expectations can be set. + void Reset(); + + class Delegate; + + private: + friend class URLRequestPostInterceptorFactory; + + static const int kResponseCode200 = 200; + + struct ExpectationResponse { + ExpectationResponse(int code, const std::string& body) + : response_code(code), response_body(body) {} + const int response_code; + const std::string response_body; + }; + typedef std::pair Expectation; + + URLRequestPostInterceptor( + const GURL& url, + const scoped_refptr& io_task_runner); + ~URLRequestPostInterceptor(); + + void ClearExpectations(); + + const GURL url_; + scoped_refptr io_task_runner_; + + mutable base::Lock interceptor_lock_; + mutable int hit_count_; + mutable std::vector requests_; + mutable std::queue expectations_; + + DISALLOW_COPY_AND_ASSIGN(URLRequestPostInterceptor); +}; + +class URLRequestPostInterceptorFactory { + public: + URLRequestPostInterceptorFactory( + const std::string& scheme, + const std::string& hostname, + const scoped_refptr& io_task_runner); + ~URLRequestPostInterceptorFactory(); + + // Creates an interceptor object for the specified url path. Returns NULL + // in case of errors or a valid interceptor object otherwise. The caller + // does not own the returned object. + URLRequestPostInterceptor* CreateInterceptor(const base::FilePath& filepath); + + private: + const std::string scheme_; + const std::string hostname_; + scoped_refptr io_task_runner_; + + // After creation, |delegate_| lives on the IO thread and it is owned by + // a URLRequestFilter after registration. A task to unregister it and + // implicitly destroy it is posted from ~URLRequestPostInterceptorFactory(). + URLRequestPostInterceptor::Delegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(URLRequestPostInterceptorFactory); +}; + +// Intercepts HTTP POST requests sent to "localhost2". +class InterceptorFactory : public URLRequestPostInterceptorFactory { + public: + explicit InterceptorFactory( + const scoped_refptr& io_task_runner); + ~InterceptorFactory(); + + // Creates an interceptor for the url path defined by POST_INTERCEPT_PATH. + URLRequestPostInterceptor* CreateInterceptor(); + + // Creates an interceptor for the given url path. + URLRequestPostInterceptor* CreateInterceptorForPath(const char* url_path); + + private: + DISALLOW_COPY_AND_ASSIGN(InterceptorFactory); +}; + +class PartialMatch : public URLRequestPostInterceptor::RequestMatcher { + public: + explicit PartialMatch(const std::string& expected) : expected_(expected) {} + bool Match(const std::string& actual) const override; + + private: + const std::string expected_; + + DISALLOW_COPY_AND_ASSIGN(PartialMatch); +}; + +} // namespace update_client + +#endif // COMPONENTS_UPDATE_CLIENT_URL_REQUEST_POST_INTERCEPTOR_H_ -- cgit v1.1