1// 2// Copyright (C) 2009 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include "update_engine/payload_consumer/bzip_extent_writer.h" 18 19#include <fcntl.h> 20 21#include <algorithm> 22#include <memory> 23#include <string> 24#include <vector> 25 26#include <gtest/gtest.h> 27 28#include "update_engine/common/test_utils.h" 29#include "update_engine/common/utils.h" 30#include "update_engine/payload_generator/extent_ranges.h" 31 32using google::protobuf::RepeatedPtrField; 33using std::min; 34using std::string; 35using std::vector; 36 37namespace chromeos_update_engine { 38 39namespace { 40const uint32_t kBlockSize = 4096; 41} 42 43class BzipExtentWriterTest : public ::testing::Test { 44 protected: 45 void SetUp() override { 46 fd_.reset(new EintrSafeFileDescriptor); 47 ASSERT_TRUE(fd_->Open(temp_file_.path().c_str(), O_RDWR, 0600)); 48 } 49 void TearDown() override { 50 fd_->Close(); 51 } 52 void WriteAlignedExtents(size_t chunk_size, size_t first_chunk_size); 53 void TestZeroPad(bool aligned_size); 54 55 FileDescriptorPtr fd_; 56 test_utils::ScopedTempFile temp_file_{"BzipExtentWriterTest-file.XXXXXX"}; 57}; 58 59TEST_F(BzipExtentWriterTest, SimpleTest) { 60 vector<Extent> extents = {ExtentForRange(0, 1)}; 61 62 // 'echo test | bzip2 | hexdump' yields: 63 static const char test_uncompressed[] = "test\n"; 64 static const uint8_t test[] = { 65 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xcc, 0xc3, 66 0x71, 0xd4, 0x00, 0x00, 0x02, 0x41, 0x80, 0x00, 0x10, 0x02, 0x00, 0x0c, 67 0x00, 0x20, 0x00, 0x21, 0x9a, 0x68, 0x33, 0x4d, 0x19, 0x97, 0x8b, 0xb9, 68 0x22, 0x9c, 0x28, 0x48, 0x66, 0x61, 0xb8, 0xea, 0x00, 69 }; 70 71 BzipExtentWriter bzip_writer(std::make_unique<DirectExtentWriter>()); 72 EXPECT_TRUE( 73 bzip_writer.Init(fd_, {extents.begin(), extents.end()}, kBlockSize)); 74 EXPECT_TRUE(bzip_writer.Write(test, sizeof(test))); 75 EXPECT_TRUE(bzip_writer.End()); 76 77 brillo::Blob buf; 78 EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &buf)); 79 EXPECT_EQ(strlen(test_uncompressed), buf.size()); 80 EXPECT_EQ(string(buf.begin(), buf.end()), string(test_uncompressed)); 81} 82 83TEST_F(BzipExtentWriterTest, ChunkedTest) { 84 // Generated with: 85 // yes "ABC" | head -c 819200 | bzip2 -9 | 86 // hexdump -v -e '" " 11/1 "0x%02x, " "\n"' 87 static const uint8_t kCompressedData[] = { 88 0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xbe, 89 0x1c, 0xda, 0xee, 0x03, 0x1f, 0xff, 0xc4, 0x00, 0x00, 0x10, 0x38, 90 0x00, 0x20, 0x00, 0x50, 0x66, 0x9a, 0x05, 0x28, 0x38, 0x00, 0x11, 91 0x60, 0x00, 0x22, 0xd0, 0x00, 0x45, 0xc0, 0x00, 0x8b, 0xc5, 0xdc, 92 0x91, 0x4e, 0x14, 0x24, 0x2f, 0x87, 0x36, 0xbb, 0x80}; 93 brillo::Blob compressed_data(std::begin(kCompressedData), 94 std::end(kCompressedData)); 95 96 const brillo::Blob::size_type kDecompressedLength = 800 * 1024; // 800 KiB 97 const size_t kChunkSize = 3; 98 99 brillo::Blob decompressed_data(kDecompressedLength); 100 for (size_t i = 0; i < decompressed_data.size(); ++i) 101 decompressed_data[i] = static_cast<uint8_t>("ABC\n"[i % 4]); 102 103 vector<Extent> extents = { 104 ExtentForRange(0, (kDecompressedLength + kBlockSize - 1) / kBlockSize)}; 105 106 BzipExtentWriter bzip_writer(std::make_unique<DirectExtentWriter>()); 107 EXPECT_TRUE( 108 bzip_writer.Init(fd_, {extents.begin(), extents.end()}, kBlockSize)); 109 110 brillo::Blob original_compressed_data = compressed_data; 111 for (brillo::Blob::size_type i = 0; i < compressed_data.size(); 112 i += kChunkSize) { 113 size_t this_chunk_size = min(kChunkSize, compressed_data.size() - i); 114 EXPECT_TRUE(bzip_writer.Write(&compressed_data[i], this_chunk_size)); 115 } 116 EXPECT_TRUE(bzip_writer.End()); 117 118 // Check that the const input has not been clobbered. 119 test_utils::ExpectVectorsEq(original_compressed_data, compressed_data); 120 121 brillo::Blob output; 122 EXPECT_TRUE(utils::ReadFile(temp_file_.path(), &output)); 123 EXPECT_EQ(kDecompressedLength, output.size()); 124 test_utils::ExpectVectorsEq(decompressed_data, output); 125} 126 127} // namespace chromeos_update_engine 128