1 // 2 // Copyright (C) 2011 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 <string.h> 18 #include <unistd.h> 19 20 #include <memory> 21 #include <string> 22 #include <vector> 23 24 #include <gtest/gtest.h> 25 26 #include "update_engine/common/test_utils.h" 27 #include "update_engine/payload_consumer/bzip_extent_writer.h" 28 #include "update_engine/payload_consumer/extent_writer.h" 29 #include "update_engine/payload_consumer/xz_extent_writer.h" 30 #include "update_engine/payload_generator/bzip.h" 31 #include "update_engine/payload_generator/xz.h" 32 33 using chromeos_update_engine::test_utils::kRandomString; 34 using google::protobuf::RepeatedPtrField; 35 using std::string; 36 using std::vector; 37 38 namespace chromeos_update_engine { 39 40 namespace { 41 42 // ExtentWriter class that writes to memory, used to test the decompression 43 // step with the corresponding extent writer. 44 class MemoryExtentWriter : public ExtentWriter { 45 public: 46 // Creates the ExtentWriter that will write all the bytes to the passed |data| 47 // blob. 48 explicit MemoryExtentWriter(brillo::Blob* data) : data_(data) { 49 data_->clear(); 50 } 51 ~MemoryExtentWriter() override = default; 52 53 bool Init(FileDescriptorPtr fd, 54 const RepeatedPtrField<Extent>& extents, 55 uint32_t block_size) override { 56 return true; 57 } 58 bool Write(const void* bytes, size_t count) override { 59 data_->reserve(data_->size() + count); 60 data_->insert(data_->end(), 61 static_cast<const uint8_t*>(bytes), 62 static_cast<const uint8_t*>(bytes) + count); 63 return true; 64 } 65 66 private: 67 brillo::Blob* data_; 68 }; 69 70 template <typename W> 71 bool DecompressWithWriter(const brillo::Blob& in, brillo::Blob* out) { 72 std::unique_ptr<ExtentWriter> writer( 73 new W(std::make_unique<MemoryExtentWriter>(out))); 74 // Init() parameters are ignored by the testing MemoryExtentWriter. 75 bool ok = writer->Init(nullptr, {}, 1); 76 ok = writer->Write(in.data(), in.size()) && ok; 77 return ok; 78 } 79 80 } // namespace 81 82 template <typename T> 83 class ZipTest : public ::testing::Test { 84 public: 85 bool ZipCompress(const brillo::Blob& in, brillo::Blob* out) const = 0; 86 bool ZipDecompress(const brillo::Blob& in, brillo::Blob* out) const = 0; 87 }; 88 89 class BzipTest {}; 90 91 template <> 92 class ZipTest<BzipTest> : public ::testing::Test { 93 public: 94 bool ZipCompress(const brillo::Blob& in, brillo::Blob* out) const { 95 return BzipCompress(in, out); 96 } 97 bool ZipDecompress(const brillo::Blob& in, brillo::Blob* out) const { 98 return DecompressWithWriter<BzipExtentWriter>(in, out); 99 } 100 }; 101 102 class XzTest {}; 103 104 template <> 105 class ZipTest<XzTest> : public ::testing::Test { 106 public: 107 bool ZipCompress(const brillo::Blob& in, brillo::Blob* out) const { 108 return XzCompress(in, out); 109 } 110 bool ZipDecompress(const brillo::Blob& in, brillo::Blob* out) const { 111 return DecompressWithWriter<XzExtentWriter>(in, out); 112 } 113 }; 114 115 typedef ::testing::Types<BzipTest, XzTest> ZipTestTypes; 116 117 TYPED_TEST_CASE(ZipTest, ZipTestTypes); 118 119 TYPED_TEST(ZipTest, SimpleTest) { 120 string in_str( 121 "this should compress well xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 122 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 123 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 124 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 125 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 126 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); 127 brillo::Blob in(in_str.begin(), in_str.end()); 128 brillo::Blob out; 129 EXPECT_TRUE(this->ZipCompress(in, &out)); 130 EXPECT_LT(out.size(), in.size()); 131 EXPECT_GT(out.size(), 0U); 132 brillo::Blob decompressed; 133 EXPECT_TRUE(this->ZipDecompress(out, &decompressed)); 134 EXPECT_EQ(in.size(), decompressed.size()); 135 EXPECT_EQ(0, memcmp(in.data(), decompressed.data(), in.size())); 136 } 137 138 TYPED_TEST(ZipTest, PoorCompressionTest) { 139 brillo::Blob in(std::begin(kRandomString), std::end(kRandomString)); 140 brillo::Blob out; 141 EXPECT_TRUE(this->ZipCompress(in, &out)); 142 EXPECT_GT(out.size(), in.size()); 143 brillo::Blob decompressed; 144 EXPECT_TRUE(this->ZipDecompress(out, &decompressed)); 145 EXPECT_EQ(in.size(), decompressed.size()); 146 EXPECT_EQ(in, decompressed); 147 } 148 149 TYPED_TEST(ZipTest, MalformedZipTest) { 150 brillo::Blob in(std::begin(kRandomString), std::end(kRandomString)); 151 brillo::Blob out; 152 EXPECT_FALSE(this->ZipDecompress(in, &out)); 153 } 154 155 TYPED_TEST(ZipTest, EmptyInputsTest) { 156 brillo::Blob in; 157 brillo::Blob out; 158 EXPECT_TRUE(this->ZipDecompress(in, &out)); 159 EXPECT_EQ(0U, out.size()); 160 161 EXPECT_TRUE(this->ZipCompress(in, &out)); 162 EXPECT_EQ(0U, out.size()); 163 } 164 165 TYPED_TEST(ZipTest, CompressELFTest) { 166 string path = test_utils::GetBuildArtifactsPath("delta_generator"); 167 brillo::Blob in; 168 utils::ReadFile(path, &in); 169 brillo::Blob out; 170 EXPECT_TRUE(this->ZipCompress(in, &out)); 171 EXPECT_LT(out.size(), in.size()); 172 EXPECT_GT(out.size(), 0U); 173 brillo::Blob decompressed; 174 EXPECT_TRUE(this->ZipDecompress(out, &decompressed)); 175 EXPECT_EQ(in.size(), decompressed.size()); 176 EXPECT_EQ(0, memcmp(in.data(), decompressed.data(), in.size())); 177 } 178 179 } // namespace chromeos_update_engine 180