| // 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/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/extensions/api/image_writer_private/error_messages.h" |
| #include "chrome/browser/extensions/api/image_writer_private/operation.h" |
| #include "chrome/browser/extensions/api/image_writer_private/operation_manager.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 "content/public/test/test_browser_thread_bundle.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/zlib/google/zip.h" |
| |
| namespace extensions { |
| namespace image_writer { |
| |
| namespace { |
| |
| using testing::_; |
| using testing::AnyNumber; |
| using testing::AtLeast; |
| using testing::Gt; |
| using testing::Lt; |
| |
| #if !defined(OS_CHROMEOS) |
| |
| void SetUpUtilityClientProgressOnVerifyWrite( |
| const std::vector<int>& progress_list, |
| bool will_succeed, |
| FakeImageWriterClient* client) { |
| client->SimulateProgressOnVerifyWrite(progress_list, will_succeed); |
| } |
| |
| #endif // !defined(OS_CHROMEOS) |
| |
| } // namespace |
| |
| // This class gives us a generic Operation with the ability to set or inspect |
| // the current path to the image file. |
| class OperationForTest : public Operation { |
| public: |
| OperationForTest(base::WeakPtr<OperationManager> manager_, |
| const ExtensionId& extension_id, |
| const std::string& device_path, |
| const base::FilePath& download_path) |
| : Operation(manager_, extension_id, device_path, download_path) {} |
| |
| void StartImpl() override {} |
| |
| // Expose internal stages for testing. |
| // Also wraps Operation's methods to run on correct sequence. |
| void Unzip(const base::Closure& continuation) { |
| PostTask(base::BindOnce(&Operation::Unzip, this, continuation)); |
| } |
| |
| void Write(const base::Closure& continuation) { |
| PostTask(base::BindOnce(&Operation::Write, this, continuation)); |
| } |
| |
| void VerifyWrite(const base::Closure& continuation) { |
| PostTask(base::BindOnce(&Operation::VerifyWrite, this, continuation)); |
| } |
| |
| void Start() { PostTask(base::BindOnce(&Operation::Start, this)); } |
| |
| void Cancel() { PostTask(base::BindOnce(&Operation::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: |
| ~OperationForTest() override {} |
| }; |
| |
| class ImageWriterOperationTest : public ImageWriterUnitTestBase { |
| protected: |
| ImageWriterOperationTest() |
| : profile_(new TestingProfile), manager_(profile_.get()) {} |
| void SetUp() override { |
| ImageWriterUnitTestBase::SetUp(); |
| |
| // Create the zip file. |
| base::FilePath image_dir = test_utils_.GetTempDir().AppendASCII("zip"); |
| ASSERT_TRUE(base::CreateDirectory(image_dir)); |
| ASSERT_TRUE(base::CreateTemporaryFileInDir(image_dir, &image_path_)); |
| |
| test_utils_.FillFile(image_path_, kImagePattern, kTestFileSize); |
| |
| zip_file_ = test_utils_.GetTempDir().AppendASCII("test_image.zip"); |
| ASSERT_TRUE(zip::Zip(image_dir, zip_file_, true)); |
| |
| // Operation setup. |
| operation_ = |
| new OperationForTest(manager_.AsWeakPtr(), |
| kDummyExtensionId, |
| test_utils_.GetDevicePath().AsUTF8Unsafe(), |
| base::FilePath(FILE_PATH_LITERAL("/var/tmp"))); |
| operation_->SetImagePath(test_utils_.GetImagePath()); |
| } |
| |
| void TearDown() override { |
| // Ensure all callbacks have been destroyed and cleanup occurs. |
| |
| // Cancel() will ensure we Shutdown() FakeImageWriterClient. |
| operation_->Cancel(); |
| scoped_task_environment_.RunUntilIdle(); |
| |
| ImageWriterUnitTestBase::TearDown(); |
| } |
| |
| base::FilePath image_path_; |
| base::FilePath zip_file_; |
| |
| std::unique_ptr<TestingProfile> profile_; |
| |
| MockOperationManager manager_; |
| scoped_refptr<OperationForTest> operation_; |
| }; |
| |
| // Unizpping a non-zip should do nothing. |
| TEST_F(ImageWriterOperationTest, UnzipNonZipFile) { |
| EXPECT_CALL(manager_, OnProgress(kDummyExtensionId, _, _)).Times(0); |
| |
| EXPECT_CALL(manager_, OnError(kDummyExtensionId, _, _, _)).Times(0); |
| EXPECT_CALL(manager_, OnProgress(kDummyExtensionId, _, _)).Times(0); |
| EXPECT_CALL(manager_, OnComplete(kDummyExtensionId)).Times(0); |
| |
| operation_->Start(); |
| base::RunLoop run_loop; |
| operation_->Unzip(run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| |
| TEST_F(ImageWriterOperationTest, UnzipZipFile) { |
| EXPECT_CALL(manager_, OnError(kDummyExtensionId, _, _, _)).Times(0); |
| EXPECT_CALL(manager_, |
| OnProgress(kDummyExtensionId, image_writer_api::STAGE_UNZIP, _)) |
| .Times(AtLeast(1)); |
| EXPECT_CALL(manager_, |
| OnProgress(kDummyExtensionId, image_writer_api::STAGE_UNZIP, 0)) |
| .Times(AtLeast(1)); |
| EXPECT_CALL(manager_, |
| OnProgress(kDummyExtensionId, image_writer_api::STAGE_UNZIP, 100)) |
| .Times(AtLeast(1)); |
| |
| operation_->SetImagePath(zip_file_); |
| |
| operation_->Start(); |
| base::RunLoop run_loop; |
| operation_->Unzip(run_loop.QuitClosure()); |
| run_loop.Run(); |
| |
| EXPECT_TRUE(base::ContentsEqual(image_path_, operation_->GetImagePath())); |
| } |
| |
| #if defined(OS_LINUX) |
| TEST_F(ImageWriterOperationTest, WriteImageToDevice) { |
| #if !defined(OS_CHROMEOS) |
| auto set_up_utility_client_progress = |
| [](const std::vector<int>& progress_list, bool will_succeed, |
| FakeImageWriterClient* client) { |
| client->SimulateProgressOnWrite(progress_list, will_succeed); |
| }; |
| // Sets up client for simulating Operation::Progress() on Operation::Write. |
| std::vector<int> progress_list{0, kTestFileSize / 2, kTestFileSize}; |
| test_utils_.RunOnUtilityClientCreation(base::BindOnce( |
| set_up_utility_client_progress, progress_list, true /* will_succeed */)); |
| #endif |
| EXPECT_CALL(manager_, OnError(kDummyExtensionId, _, _, _)).Times(0); |
| EXPECT_CALL(manager_, |
| OnProgress(kDummyExtensionId, image_writer_api::STAGE_WRITE, _)) |
| .Times(AtLeast(1)); |
| EXPECT_CALL(manager_, |
| OnProgress(kDummyExtensionId, image_writer_api::STAGE_WRITE, 0)) |
| .Times(AtLeast(1)); |
| EXPECT_CALL(manager_, |
| OnProgress(kDummyExtensionId, image_writer_api::STAGE_WRITE, 100)) |
| .Times(AtLeast(1)); |
| |
| operation_->Start(); |
| base::RunLoop run_loop; |
| operation_->Write(run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| #endif // defined(OS_LINUX) |
| |
| #if !defined(OS_CHROMEOS) |
| // Chrome OS doesn't support verification in the ImageBurner, so these two tests |
| // are skipped. |
| |
| TEST_F(ImageWriterOperationTest, VerifyFileSuccess) { |
| // Sets up client for simulating Operation::Progress() on |
| // Operation::VerifyWrite. |
| std::vector<int> progress_list{0, kTestFileSize / 2, kTestFileSize}; |
| test_utils_.RunOnUtilityClientCreation( |
| base::BindOnce(&SetUpUtilityClientProgressOnVerifyWrite, progress_list, |
| true /* will_succeed */)); |
| EXPECT_CALL(manager_, OnError(kDummyExtensionId, _, _, _)).Times(0); |
| EXPECT_CALL( |
| manager_, |
| OnProgress(kDummyExtensionId, image_writer_api::STAGE_VERIFYWRITE, _)) |
| .Times(AtLeast(1)); |
| EXPECT_CALL( |
| manager_, |
| OnProgress(kDummyExtensionId, image_writer_api::STAGE_VERIFYWRITE, 0)) |
| .Times(AtLeast(1)); |
| EXPECT_CALL( |
| manager_, |
| OnProgress(kDummyExtensionId, image_writer_api::STAGE_VERIFYWRITE, 100)) |
| .Times(AtLeast(1)); |
| |
| test_utils_.FillFile( |
| test_utils_.GetDevicePath(), kImagePattern, kTestFileSize); |
| |
| operation_->Start(); |
| base::RunLoop run_loop; |
| operation_->VerifyWrite(run_loop.QuitClosure()); |
| run_loop.Run(); |
| } |
| |
| TEST_F(ImageWriterOperationTest, VerifyFileFailure) { |
| // Sets up client for simulating Operation::Progress() on |
| // Operation::VerifyWrite. Also simulates failure. |
| std::vector<int> progress_list{0, kTestFileSize / 2}; |
| test_utils_.RunOnUtilityClientCreation( |
| base::BindOnce(&SetUpUtilityClientProgressOnVerifyWrite, progress_list, |
| false /* will_succeed */)); |
| EXPECT_CALL( |
| manager_, |
| OnProgress(kDummyExtensionId, image_writer_api::STAGE_VERIFYWRITE, _)) |
| .Times(AnyNumber()); |
| EXPECT_CALL( |
| manager_, |
| OnProgress(kDummyExtensionId, image_writer_api::STAGE_VERIFYWRITE, 100)) |
| .Times(0); |
| EXPECT_CALL(manager_, OnComplete(kDummyExtensionId)).Times(0); |
| EXPECT_CALL( |
| manager_, |
| OnError(kDummyExtensionId, image_writer_api::STAGE_VERIFYWRITE, _, _)) |
| .Times(1); |
| |
| test_utils_.FillFile( |
| test_utils_.GetDevicePath(), kDevicePattern, kTestFileSize); |
| |
| operation_->Start(); |
| operation_->VerifyWrite(base::Bind(&base::DoNothing)); |
| content::RunAllBlockingPoolTasksUntilIdle(); |
| } |
| #endif // !defined(OS_CHROMEOS) |
| |
| // Tests that on creation the operation_ has the expected state. |
| TEST_F(ImageWriterOperationTest, Creation) { |
| EXPECT_EQ(0, operation_->GetProgress()); |
| EXPECT_EQ(image_writer_api::STAGE_UNKNOWN, operation_->GetStage()); |
| } |
| |
| } // namespace image_writer |
| } // namespace extensions |