blob: 30b129b618d69583a753b88f6afcd9363ffe9135 [file] [log] [blame]
// Copyright 2017 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/callback.h"
#include "base/files/file.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/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "build/build_config.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/services/patch/public/cpp/patch.h"
#include "components/update_client/component_patcher_operation.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/service_manager_connection.h"
#include "courgette/courgette.h"
#include "courgette/third_party/bsdiff/bsdiff.h"
#include "services/service_manager/public/cpp/connector.h"
namespace {
constexpr base::TaskTraits kTaskTraits = {
base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
} // namespace
class PatchTest : public InProcessBrowserTest {
public:
PatchTest() {
EXPECT_TRUE(installed_dir_.CreateUniqueTempDir());
EXPECT_TRUE(input_dir_.CreateUniqueTempDir());
EXPECT_TRUE(unpack_dir_.CreateUniqueTempDir());
}
static base::FilePath TestFile(const char* name) {
base::FilePath path;
base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
return path.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
.AppendASCII("update_client")
.AppendASCII(name);
}
base::FilePath InputFilePath(const char* name) {
base::FilePath path = installed_dir_.GetPath().AppendASCII(name);
base::RunLoop run_loop;
base::PostTaskWithTraitsAndReply(
FROM_HERE, kTaskTraits,
base::BindOnce(&PatchTest::CopyFile, TestFile(name), path),
run_loop.QuitClosure());
run_loop.Run();
return path;
}
base::FilePath PatchFilePath(const char* name) {
base::FilePath path = input_dir_.GetPath().AppendASCII(name);
base::RunLoop run_loop;
base::PostTaskWithTraitsAndReply(
FROM_HERE, kTaskTraits,
base::BindOnce(&PatchTest::CopyFile, TestFile(name), path),
run_loop.QuitClosure());
run_loop.Run();
return path;
}
base::FilePath OutputFilePath(const char* name) {
return unpack_dir_.GetPath().AppendASCII(name);
}
base::FilePath InvalidPath(const char* name) {
return input_dir_.GetPath().AppendASCII("nonexistent").AppendASCII(name);
}
void RunPatchTest(const std::string& operation,
const base::FilePath& input,
const base::FilePath& patch,
const base::FilePath& output,
int expected_result) {
base::RunLoop run_loop;
quit_closure_ = run_loop.QuitClosure();
done_called_ = false;
std::unique_ptr<service_manager::Connector> connector =
content::ServiceManagerConnection::GetForProcess()
->GetConnector()
->Clone();
base::CreateSequencedTaskRunnerWithTraits(kTaskTraits)
->PostTask(
FROM_HERE,
base::BindOnce(&PatchTest::PatchAsyncSequencedTaskRunner,
base::Unretained(this), std::move(connector),
operation, input, patch, output, expected_result));
run_loop.Run();
EXPECT_TRUE(done_called_);
}
private:
void PatchAsyncSequencedTaskRunner(
std::unique_ptr<service_manager::Connector> connector,
const std::string& operation,
const base::FilePath& input,
const base::FilePath& patch,
const base::FilePath& output,
int expected_result) {
patch::Patch(connector.get(), operation, input, patch, output,
base::BindOnce(&PatchTest::PatchDone, base::Unretained(this),
expected_result));
}
void PatchDone(int expected, int result) {
EXPECT_EQ(expected, result);
done_called_ = true;
base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI})
->PostTask(FROM_HERE, std::move(quit_closure_));
}
static void CopyFile(const base::FilePath& source,
const base::FilePath& target) {
EXPECT_TRUE(base::CopyFile(source, target));
}
base::ScopedTempDir installed_dir_;
base::ScopedTempDir input_dir_;
base::ScopedTempDir unpack_dir_;
base::OnceClosure quit_closure_;
bool done_called_;
DISALLOW_COPY_AND_ASSIGN(PatchTest);
};
IN_PROC_BROWSER_TEST_F(PatchTest, CheckBsdiffOperation) {
constexpr int kExpectedResult = bsdiff::OK;
base::FilePath input_file = InputFilePath("binary_input.bin");
base::FilePath patch_file = PatchFilePath("binary_bsdiff_patch.bin");
base::FilePath output_file = OutputFilePath("output.bin");
RunPatchTest(update_client::kBsdiff, input_file, patch_file, output_file,
kExpectedResult);
EXPECT_TRUE(base::ContentsEqual(TestFile("binary_output.bin"), output_file));
}
IN_PROC_BROWSER_TEST_F(PatchTest, CheckCourgetteOperation) {
constexpr int kExpectedResult = courgette::C_OK;
base::FilePath input_file = InputFilePath("binary_input.bin");
base::FilePath patch_file = PatchFilePath("binary_courgette_patch.bin");
base::FilePath output_file = OutputFilePath("output.bin");
RunPatchTest(update_client::kCourgette, input_file, patch_file, output_file,
kExpectedResult);
EXPECT_TRUE(base::ContentsEqual(TestFile("binary_output.bin"), output_file));
}
IN_PROC_BROWSER_TEST_F(PatchTest, InvalidInputFile) {
constexpr int kInvalidInputFile = -1;
base::FilePath invalid = InvalidPath("binary_input.bin");
base::FilePath patch_file = PatchFilePath("binary_courgette_patch.bin");
base::FilePath output_file = OutputFilePath("output.bin");
RunPatchTest(update_client::kCourgette, invalid, patch_file, output_file,
kInvalidInputFile);
}
IN_PROC_BROWSER_TEST_F(PatchTest, InvalidPatchFile) {
constexpr int kInvalidPatchFile = -1;
base::FilePath input_file = InputFilePath("binary_input.bin");
base::FilePath invalid = InvalidPath("binary_courgette_patch.bin");
base::FilePath output_file = OutputFilePath("output.bin");
RunPatchTest(update_client::kCourgette, input_file, invalid, output_file,
kInvalidPatchFile);
}
IN_PROC_BROWSER_TEST_F(PatchTest, InvalidOutputFile) {
constexpr int kInvalidOutputFile = -1;
base::FilePath input_file = InputFilePath("binary_input.bin");
base::FilePath patch_file = PatchFilePath("binary_courgette_patch.bin");
base::FilePath invalid = InvalidPath("output.bin");
RunPatchTest(update_client::kCourgette, input_file, patch_file, invalid,
kInvalidOutputFile);
}