blob: 98680a7b6a7367a83899585a2fd6017dd064a012 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h"
#include "base/task_scheduler/post_task.h"
#include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
#include "chrome/browser/extensions/api/image_writer_private/test_utils.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/test_url_request_interceptor.h"
namespace extensions {
namespace image_writer {
namespace {
using content::BrowserThread;
using testing::_;
using testing::AnyNumber;
using testing::AtLeast;
using testing::Gt;
using testing::Lt;
const char kTestImageUrl[] = "http://localhost/test/image.zip";
typedef net::LocalHostTestURLRequestInterceptor GetInterceptor;
} // namespace
// This class gives us a generic Operation with the ability to set or inspect
// the current path to the image file.
class WriteFromUrlOperationForTest : public WriteFromUrlOperation {
public:
WriteFromUrlOperationForTest(base::WeakPtr<OperationManager> manager,
const ExtensionId& extension_id,
net::URLRequestContextGetter* request_context,
GURL url,
const std::string& hash,
const std::string& storage_unit_id)
: WriteFromUrlOperation(manager,
extension_id,
request_context,
url,
hash,
storage_unit_id,
base::FilePath(FILE_PATH_LITERAL("/var/tmp"))) {}
void StartImpl() override {}
// Following methods let us:
// 1. Expose stages for testing.
// 2. Make sure Operation methods are invoked on its task runner.
void Start() {
PostTask(base::BindOnce(&WriteFromUrlOperation::Start, this));
}
void GetDownloadTarget(const base::Closure& continuation) {
PostTask(base::BindOnce(&WriteFromUrlOperation::GetDownloadTarget, this,
continuation));
}
void Download(const base::Closure& continuation) {
PostTask(
base::BindOnce(&WriteFromUrlOperation::Download, this, continuation));
}
void VerifyDownload(const base::Closure& continuation) {
PostTask(base::BindOnce(&WriteFromUrlOperation::VerifyDownload, this,
continuation));
}
void Cancel() {
PostTask(base::BindOnce(&WriteFromUrlOperation::Cancel, this));
}
// Helpers to set-up state for intermediate stages.
void SetImagePath(const base::FilePath image_path) {
image_path_ = image_path;
}
base::FilePath GetImagePath() { return image_path_; }
private:
~WriteFromUrlOperationForTest() override {}
};
class ImageWriterWriteFromUrlOperationTest : public ImageWriterUnitTestBase {
protected:
ImageWriterWriteFromUrlOperationTest() : manager_(&test_profile_) {}
void SetUp() override {
ImageWriterUnitTestBase::SetUp();
// Turn on interception and set up our dummy file.
get_interceptor_.reset(new GetInterceptor(
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
base::CreateTaskRunnerWithTraits(
{base::MayBlock(), base::TaskPriority::BACKGROUND,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})));
get_interceptor_->SetResponse(GURL(kTestImageUrl),
test_utils_.GetImagePath());
}
void TearDown() override {
ImageWriterUnitTestBase::TearDown();
}
scoped_refptr<WriteFromUrlOperationForTest> CreateOperation(
const GURL& url,
const std::string& hash) {
scoped_refptr<WriteFromUrlOperationForTest> operation(
new WriteFromUrlOperationForTest(
manager_.AsWeakPtr(), kDummyExtensionId,
test_profile_.GetRequestContext(), url, hash,
test_utils_.GetDevicePath().AsUTF8Unsafe()));
operation->Start();
return operation;
}
TestingProfile test_profile_;
std::unique_ptr<GetInterceptor> get_interceptor_;
MockOperationManager manager_;
};
TEST_F(ImageWriterWriteFromUrlOperationTest, SelectTargetWithoutExtension) {
scoped_refptr<WriteFromUrlOperationForTest> operation =
CreateOperation(GURL("http://localhost/foo/bar"), "");
base::RunLoop run_loop;
operation->GetDownloadTarget(run_loop.QuitClosure());
run_loop.Run();
EXPECT_EQ(FILE_PATH_LITERAL("bar"),
operation->GetImagePath().BaseName().value());
operation->Cancel();
content::RunAllBlockingPoolTasksUntilIdle();
}
TEST_F(ImageWriterWriteFromUrlOperationTest, SelectTargetWithExtension) {
scoped_refptr<WriteFromUrlOperationForTest> operation =
CreateOperation(GURL("http://localhost/foo/bar.zip"), "");
base::RunLoop run_loop;
operation->GetDownloadTarget(run_loop.QuitClosure());
run_loop.Run();
EXPECT_EQ(FILE_PATH_LITERAL("bar.zip"),
operation->GetImagePath().BaseName().value());
operation->Cancel();
}
TEST_F(ImageWriterWriteFromUrlOperationTest, DownloadFile) {
// This test actually triggers the URL fetch code, which will drain the
// message queues while waiting for IO, thus we have to run until the
// operation completes.
base::RunLoop runloop;
base::FilePath download_target_path;
scoped_refptr<WriteFromUrlOperationForTest> operation =
CreateOperation(GURL(kTestImageUrl), "");
EXPECT_TRUE(base::CreateTemporaryFileInDir(test_utils_.GetTempDir(),
&download_target_path));
operation->SetImagePath(download_target_path);
EXPECT_CALL(
manager_,
OnProgress(kDummyExtensionId, image_writer_api::STAGE_DOWNLOAD, _))
.Times(AtLeast(1));
EXPECT_CALL(
manager_,
OnProgress(kDummyExtensionId, image_writer_api::STAGE_DOWNLOAD, 0))
.Times(AnyNumber());
EXPECT_CALL(
manager_,
OnProgress(kDummyExtensionId, image_writer_api::STAGE_DOWNLOAD, 100))
.Times(AnyNumber());
operation->Download(runloop.QuitClosure());
runloop.Run();
content::RunAllBlockingPoolTasksUntilIdle();
EXPECT_TRUE(base::ContentsEqual(test_utils_.GetImagePath(),
operation->GetImagePath()));
EXPECT_EQ(1, get_interceptor_->GetHitCount());
operation->Cancel();
}
TEST_F(ImageWriterWriteFromUrlOperationTest, VerifyFile) {
std::unique_ptr<char[]> data_buffer(new char[kTestFileSize]);
base::ReadFile(test_utils_.GetImagePath(), data_buffer.get(), kTestFileSize);
base::MD5Digest expected_digest;
base::MD5Sum(data_buffer.get(), kTestFileSize, &expected_digest);
std::string expected_hash = base::MD5DigestToBase16(expected_digest);
scoped_refptr<WriteFromUrlOperationForTest> operation =
CreateOperation(GURL(""), expected_hash);
EXPECT_CALL(
manager_,
OnProgress(kDummyExtensionId, image_writer_api::STAGE_VERIFYDOWNLOAD, _))
.Times(AtLeast(1));
EXPECT_CALL(
manager_,
OnProgress(kDummyExtensionId, image_writer_api::STAGE_VERIFYDOWNLOAD, 0))
.Times(AtLeast(1));
EXPECT_CALL(manager_,
OnProgress(kDummyExtensionId,
image_writer_api::STAGE_VERIFYDOWNLOAD,
100)).Times(AtLeast(1));
operation->SetImagePath(test_utils_.GetImagePath());
{
base::RunLoop run_loop;
operation->VerifyDownload(run_loop.QuitClosure());
run_loop.Run();
}
operation->Cancel();
}
} // namespace image_writer
} // namespace extensions