123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- // 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/crx_downloader.h"
- #include <utility>
- #include "base/bind.h"
- #include "base/files/file_path.h"
- #include "base/files/file_util.h"
- #include "base/memory/ref_counted.h"
- #include "base/path_service.h"
- #include "base/run_loop.h"
- #include "base/test/bind.h"
- #include "base/test/task_environment.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "build/build_config.h"
- #include "components/update_client/crx_downloader_factory.h"
- #include "components/update_client/net/network_chromium.h"
- #include "components/update_client/update_client_errors.h"
- #include "components/update_client/utils.h"
- #include "net/base/net_errors.h"
- #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
- #include "services/network/public/mojom/url_response_head.mojom.h"
- #include "services/network/test/test_url_loader_factory.h"
- #include "testing/gtest/include/gtest/gtest.h"
- using base::ContentsEqual;
- namespace update_client {
- namespace {
- const char kTestFileName[] = "jebgalgnebhfojomionfpkfelancnnkf.crx";
- const char hash_jebg[] =
- "7ab32f071cd9b5ef8e0d7913be161f532d98b3e9fa284a7cd8059c3409ce0498";
- base::FilePath MakeTestFilePath(const char* file) {
- base::FilePath path;
- base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
- return path.AppendASCII("components/test/data/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(const CrxDownloader::Result& result);
- void DownloadProgress(int64_t downloaded_bytes, int64_t total_bytes);
- int GetInterceptorCount() { return interceptor_count_; }
- void AddResponse(const GURL& url,
- const base::FilePath& file_path,
- int net_error);
- protected:
- scoped_refptr<CrxDownloader> crx_downloader_;
- network::TestURLLoaderFactory test_url_loader_factory_;
- CrxDownloader::DownloadCallback callback_;
- CrxDownloader::ProgressCallback progress_callback_;
- int num_download_complete_calls_ = 0;
- CrxDownloader::Result download_complete_result_ = {};
- // These members are updated by DownloadProgress.
- int num_progress_calls_ = 0;
- int64_t downloaded_bytes_ = -1;
- int64_t total_bytes_ = -1;
- // Accumulates the number of loads triggered.
- int interceptor_count_ = 0;
- private:
- base::test::TaskEnvironment task_environment_;
- scoped_refptr<network::SharedURLLoaderFactory>
- test_shared_url_loader_factory_;
- base::OnceClosure quit_closure_;
- };
- CrxDownloaderTest::CrxDownloaderTest()
- : callback_(base::BindOnce(&CrxDownloaderTest::DownloadComplete,
- base::Unretained(this))),
- progress_callback_(
- base::BindRepeating(&CrxDownloaderTest::DownloadProgress,
- base::Unretained(this))),
- task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
- test_shared_url_loader_factory_(
- base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
- &test_url_loader_factory_)) {}
- CrxDownloaderTest::~CrxDownloaderTest() = default;
- void CrxDownloaderTest::SetUp() {
- // Do not use the background downloader in these tests.
- crx_downloader_ =
- MakeCrxDownloaderFactory(
- base::MakeRefCounted<NetworkFetcherChromiumFactory>(
- test_shared_url_loader_factory_,
- base::BindRepeating([](const GURL& url) { return false; })))
- ->MakeCrxDownloader(false);
- crx_downloader_->set_progress_callback(progress_callback_);
- test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting(
- [&](const network::ResourceRequest& request) { interceptor_count_++; }));
- }
- void CrxDownloaderTest::TearDown() {
- crx_downloader_ = nullptr;
- }
- void CrxDownloaderTest::Quit() {
- if (!quit_closure_.is_null())
- std::move(quit_closure_).Run();
- }
- void CrxDownloaderTest::DownloadComplete(const CrxDownloader::Result& result) {
- ++num_download_complete_calls_;
- download_complete_result_ = result;
- Quit();
- }
- void CrxDownloaderTest::DownloadProgress(int64_t downloaded_bytes,
- int64_t total_bytes) {
- if (downloaded_bytes != -1 && total_bytes != -1)
- DCHECK_LE(downloaded_bytes, total_bytes);
- downloaded_bytes_ = downloaded_bytes;
- total_bytes_ = total_bytes;
- ++num_progress_calls_;
- }
- void CrxDownloaderTest::AddResponse(const GURL& url,
- const base::FilePath& file_path,
- int net_error) {
- if (net_error == net::OK) {
- std::string data;
- EXPECT_TRUE(base::ReadFileToString(file_path, &data));
- auto head = network::mojom::URLResponseHead::New();
- head->content_length = data.size();
- network::URLLoaderCompletionStatus status(net_error);
- status.decoded_body_length = data.size();
- test_url_loader_factory_.AddResponse(url, std::move(head), data, status);
- return;
- }
- EXPECT_NE(net_error, net::OK);
- test_url_loader_factory_.AddResponse(
- url, network::mojom::URLResponseHead::New(), std::string(),
- network::URLLoaderCompletionStatus(net_error));
- }
- 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();
- }
- // TODO(crbug.com/1104691): rewrite the tests to not use RunUntilIdle().
- void CrxDownloaderTest::RunThreadsUntilIdle() {
- task_environment_.RunUntilIdle();
- base::RunLoop().RunUntilIdle();
- }
- // Tests that starting a download without a url results in an error.
- TEST_F(CrxDownloaderTest, NoUrl) {
- std::vector<GURL> urls;
- crx_downloader_->StartDownload(urls, std::string("abcd"),
- std::move(callback_));
- RunThreadsUntilIdle();
- EXPECT_EQ(1, num_download_complete_calls_);
- EXPECT_EQ(static_cast<int>(CrxDownloaderError::NO_URL),
- download_complete_result_.error);
- EXPECT_TRUE(download_complete_result_.response.empty());
- EXPECT_EQ(0, num_progress_calls_);
- }
- // Tests that starting a download without providing a hash results in an error.
- TEST_F(CrxDownloaderTest, NoHash) {
- std::vector<GURL> urls(1, GURL("http://somehost/somefile"));
- crx_downloader_->StartDownload(urls, std::string(), std::move(callback_));
- RunThreadsUntilIdle();
- EXPECT_EQ(1, num_download_complete_calls_);
- EXPECT_EQ(static_cast<int>(CrxDownloaderError::NO_HASH),
- download_complete_result_.error);
- EXPECT_TRUE(download_complete_result_.response.empty());
- 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));
- AddResponse(expected_crx_url, test_file, net::OK);
- crx_downloader_->StartDownloadFromUrl(
- expected_crx_url, std::string(hash_jebg), std::move(callback_));
- RunThreads();
- EXPECT_EQ(1, GetInterceptorCount());
- EXPECT_EQ(1, num_download_complete_calls_);
- EXPECT_EQ(0, download_complete_result_.error);
- EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file));
- EXPECT_TRUE(
- DeleteFileAndEmptyParentDirectory(download_complete_result_.response));
- EXPECT_LE(1, num_progress_calls_);
- EXPECT_EQ(total_bytes_, 1015);
- }
- // Tests that downloading from one url fails if the actual hash of the file
- // does not match the expected hash.
- TEST_F(CrxDownloaderTest, OneUrlBadHash) {
- const GURL expected_crx_url =
- GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx");
- const base::FilePath test_file(MakeTestFilePath(kTestFileName));
- AddResponse(expected_crx_url, test_file, net::OK);
- crx_downloader_->StartDownloadFromUrl(
- expected_crx_url,
- std::string(
- "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9"),
- std::move(callback_));
- RunThreads();
- EXPECT_EQ(1, GetInterceptorCount());
- EXPECT_EQ(1, num_download_complete_calls_);
- EXPECT_EQ(static_cast<int>(CrxDownloaderError::BAD_HASH),
- download_complete_result_.error);
- EXPECT_TRUE(download_complete_result_.response.empty());
- EXPECT_LE(1, num_progress_calls_);
- }
- // Tests that specifying two urls has no side effects. Expect a successful
- // download, and only one download request be made.
- TEST_F(CrxDownloaderTest, TwoUrls) {
- const GURL expected_crx_url =
- GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx");
- const base::FilePath test_file(MakeTestFilePath(kTestFileName));
- AddResponse(expected_crx_url, test_file, net::OK);
- std::vector<GURL> urls;
- urls.push_back(expected_crx_url);
- urls.push_back(expected_crx_url);
- crx_downloader_->StartDownload(urls, std::string(hash_jebg),
- std::move(callback_));
- RunThreads();
- EXPECT_EQ(1, GetInterceptorCount());
- EXPECT_EQ(1, num_download_complete_calls_);
- EXPECT_EQ(0, download_complete_result_.error);
- EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file));
- EXPECT_TRUE(
- DeleteFileAndEmptyParentDirectory(download_complete_result_.response));
- EXPECT_LE(1, num_progress_calls_);
- }
- // Tests that the fallback to a valid url is successful.
- TEST_F(CrxDownloaderTest, TwoUrls_FirstInvalid) {
- const GURL expected_crx_url =
- GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx");
- const GURL no_file_url =
- GURL("http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc.crx");
- const base::FilePath test_file(MakeTestFilePath(kTestFileName));
- AddResponse(expected_crx_url, test_file, net::OK);
- AddResponse(no_file_url, base::FilePath(), net::ERR_FILE_NOT_FOUND);
- std::vector<GURL> urls;
- urls.push_back(no_file_url);
- urls.push_back(expected_crx_url);
- crx_downloader_->StartDownload(urls, std::string(hash_jebg),
- std::move(callback_));
- RunThreads();
- EXPECT_EQ(2, GetInterceptorCount());
- EXPECT_EQ(1, num_download_complete_calls_);
- EXPECT_EQ(0, download_complete_result_.error);
- EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file));
- EXPECT_TRUE(
- DeleteFileAndEmptyParentDirectory(download_complete_result_.response));
- // Expect at least some progress reported by the loader.
- EXPECT_LE(1, num_progress_calls_);
- const auto download_metrics = crx_downloader_->download_metrics();
- ASSERT_EQ(2u, download_metrics.size());
- EXPECT_EQ(no_file_url, download_metrics[0].url);
- EXPECT_EQ(net::ERR_FILE_NOT_FOUND, download_metrics[0].error);
- EXPECT_EQ(-1, download_metrics[0].downloaded_bytes);
- EXPECT_EQ(-1, download_metrics[0].total_bytes);
- EXPECT_EQ(expected_crx_url, download_metrics[1].url);
- EXPECT_EQ(0, download_metrics[1].error);
- EXPECT_EQ(1015, download_metrics[1].downloaded_bytes);
- EXPECT_EQ(1015, download_metrics[1].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 GURL no_file_url =
- GURL("http://localhost/download/ihfokbkgjpifnbbojhneepfflplebdkc.crx");
- const base::FilePath test_file(MakeTestFilePath(kTestFileName));
- AddResponse(expected_crx_url, test_file, net::OK);
- AddResponse(no_file_url, base::FilePath(), net::ERR_FILE_NOT_FOUND);
- std::vector<GURL> urls;
- urls.push_back(expected_crx_url);
- urls.push_back(no_file_url);
- crx_downloader_->StartDownload(urls, std::string(hash_jebg),
- std::move(callback_));
- RunThreads();
- EXPECT_EQ(1, GetInterceptorCount());
- EXPECT_EQ(1, num_download_complete_calls_);
- EXPECT_EQ(0, download_complete_result_.error);
- EXPECT_TRUE(ContentsEqual(download_complete_result_.response, test_file));
- EXPECT_TRUE(
- DeleteFileAndEmptyParentDirectory(download_complete_result_.response));
- EXPECT_LE(1, num_progress_calls_);
- EXPECT_EQ(1u, crx_downloader_->download_metrics().size());
- }
- // Tests that the download fails if both urls don't serve content.
- TEST_F(CrxDownloaderTest, TwoUrls_BothInvalid) {
- const GURL expected_crx_url =
- GURL("http://localhost/download/jebgalgnebhfojomionfpkfelancnnkf.crx");
- AddResponse(expected_crx_url, base::FilePath(), net::ERR_FILE_NOT_FOUND);
- std::vector<GURL> urls;
- urls.push_back(expected_crx_url);
- urls.push_back(expected_crx_url);
- crx_downloader_->StartDownload(urls, std::string(hash_jebg),
- std::move(callback_));
- RunThreads();
- EXPECT_EQ(2, GetInterceptorCount());
- EXPECT_EQ(1, num_download_complete_calls_);
- EXPECT_NE(0, download_complete_result_.error);
- EXPECT_TRUE(download_complete_result_.response.empty());
- const auto download_metrics = crx_downloader_->download_metrics();
- ASSERT_EQ(2u, download_metrics.size());
- EXPECT_EQ(expected_crx_url, download_metrics[0].url);
- EXPECT_EQ(net::ERR_FILE_NOT_FOUND, download_metrics[0].error);
- EXPECT_EQ(-1, download_metrics[0].downloaded_bytes);
- EXPECT_EQ(-1, download_metrics[0].total_bytes);
- EXPECT_EQ(expected_crx_url, download_metrics[1].url);
- EXPECT_EQ(net::ERR_FILE_NOT_FOUND, download_metrics[1].error);
- EXPECT_EQ(-1, download_metrics[1].downloaded_bytes);
- EXPECT_EQ(-1, download_metrics[1].total_bytes);
- }
- } // namespace update_client
|