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 <string> 21#include <vector> 22 23#include <brillo/make_unique_ptr.h> 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 33using chromeos_update_engine::test_utils::kRandomString; 34using std::string; 35using std::vector; 36 37namespace chromeos_update_engine { 38 39namespace { 40 41// ExtentWriter class that writes to memory, used to test the decompression 42// step with the corresponding extent writer. 43class MemoryExtentWriter : public ExtentWriter { 44 public: 45 // Creates the ExtentWriter that will write all the bytes to the passed |data| 46 // blob. 47 explicit MemoryExtentWriter(brillo::Blob* data) : data_(data) { 48 data_->clear(); 49 } 50 ~MemoryExtentWriter() override = default; 51 52 bool Init(FileDescriptorPtr fd, 53 const vector<Extent>& extents, 54 uint32_t block_size) override { 55 return true; 56 } 57 bool Write(const void* bytes, size_t count) override { 58 data_->reserve(data_->size() + count); 59 data_->insert(data_->end(), 60 static_cast<const uint8_t*>(bytes), 61 static_cast<const uint8_t*>(bytes) + count); 62 return true; 63 } 64 bool EndImpl() override { return true; } 65 66 private: 67 brillo::Blob* data_; 68}; 69 70template <typename W> 71bool DecompressWithWriter(const brillo::Blob& in, brillo::Blob* out) { 72 std::unique_ptr<ExtentWriter> writer( 73 new W(brillo::make_unique_ptr(new 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 // Call End() even if the Write failed. 78 ok = writer->End() && ok; 79 return ok; 80} 81 82} // namespace 83 84template <typename T> 85class ZipTest : public ::testing::Test { 86 public: 87 bool ZipCompress(const brillo::Blob& in, brillo::Blob* out) const = 0; 88 bool ZipDecompress(const brillo::Blob& in, brillo::Blob* out) const = 0; 89}; 90 91class BzipTest {}; 92 93template <> 94class ZipTest<BzipTest> : public ::testing::Test { 95 public: 96 bool ZipCompress(const brillo::Blob& in, brillo::Blob* out) const { 97 return BzipCompress(in, out); 98 } 99 bool ZipDecompress(const brillo::Blob& in, brillo::Blob* out) const { 100 return DecompressWithWriter<BzipExtentWriter>(in, out); 101 } 102}; 103 104class XzTest {}; 105 106template <> 107class ZipTest<XzTest> : public ::testing::Test { 108 public: 109 bool ZipCompress(const brillo::Blob& in, brillo::Blob* out) const { 110 return XzCompress(in, out); 111 } 112 bool ZipDecompress(const brillo::Blob& in, brillo::Blob* out) const { 113 return DecompressWithWriter<XzExtentWriter>(in, out); 114 } 115}; 116 117#ifdef __ANDROID__ 118typedef ::testing::Types<BzipTest, XzTest> ZipTestTypes; 119#else 120// Chrome OS implementation of Xz compressor just returns false. 121typedef ::testing::Types<BzipTest> ZipTestTypes; 122#endif // __ANDROID__ 123 124TYPED_TEST_CASE(ZipTest, ZipTestTypes); 125 126TYPED_TEST(ZipTest, SimpleTest) { 127 string in_str( 128 "this should compress well xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 129 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 130 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 131 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 132 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 133 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); 134 brillo::Blob in(in_str.begin(), in_str.end()); 135 brillo::Blob out; 136 EXPECT_TRUE(this->ZipCompress(in, &out)); 137 EXPECT_LT(out.size(), in.size()); 138 EXPECT_GT(out.size(), 0U); 139 brillo::Blob decompressed; 140 EXPECT_TRUE(this->ZipDecompress(out, &decompressed)); 141 EXPECT_EQ(in.size(), decompressed.size()); 142 EXPECT_TRUE(!memcmp(in.data(), decompressed.data(), in.size())); 143} 144 145TYPED_TEST(ZipTest, PoorCompressionTest) { 146 brillo::Blob in(std::begin(kRandomString), std::end(kRandomString)); 147 brillo::Blob out; 148 EXPECT_TRUE(this->ZipCompress(in, &out)); 149 EXPECT_GT(out.size(), in.size()); 150 brillo::Blob decompressed; 151 EXPECT_TRUE(this->ZipDecompress(out, &decompressed)); 152 EXPECT_EQ(in.size(), decompressed.size()); 153 EXPECT_EQ(in, decompressed); 154} 155 156TYPED_TEST(ZipTest, MalformedZipTest) { 157 brillo::Blob in(std::begin(kRandomString), std::end(kRandomString)); 158 brillo::Blob out; 159 EXPECT_FALSE(this->ZipDecompress(in, &out)); 160} 161 162TYPED_TEST(ZipTest, EmptyInputsTest) { 163 brillo::Blob in; 164 brillo::Blob out; 165 EXPECT_TRUE(this->ZipDecompress(in, &out)); 166 EXPECT_EQ(0U, out.size()); 167 168 EXPECT_TRUE(this->ZipCompress(in, &out)); 169 EXPECT_EQ(0U, out.size()); 170} 171 172} // namespace chromeos_update_engine 173