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.
MemoryExtentWriter(brillo::Blob * data)48 explicit MemoryExtentWriter(brillo::Blob* data) : data_(data) {
49 data_->clear();
50 }
51 ~MemoryExtentWriter() override = default;
52
Init(FileDescriptorPtr fd,const RepeatedPtrField<Extent> & extents,uint32_t block_size)53 bool Init(FileDescriptorPtr fd,
54 const RepeatedPtrField<Extent>& extents,
55 uint32_t block_size) override {
56 return true;
57 }
Write(const void * bytes,size_t count)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 }
EndImpl()65 bool EndImpl() override { return true; }
66
67 private:
68 brillo::Blob* data_;
69 };
70
71 template <typename W>
DecompressWithWriter(const brillo::Blob & in,brillo::Blob * out)72 bool DecompressWithWriter(const brillo::Blob& in, brillo::Blob* out) {
73 std::unique_ptr<ExtentWriter> writer(
74 new W(std::make_unique<MemoryExtentWriter>(out)));
75 // Init() parameters are ignored by the testing MemoryExtentWriter.
76 bool ok = writer->Init(nullptr, {}, 1);
77 ok = writer->Write(in.data(), in.size()) && ok;
78 // Call End() even if the Write failed.
79 ok = writer->End() && ok;
80 return ok;
81 }
82
83 } // namespace
84
85 template <typename T>
86 class ZipTest : public ::testing::Test {
87 public:
88 bool ZipCompress(const brillo::Blob& in, brillo::Blob* out) const = 0;
89 bool ZipDecompress(const brillo::Blob& in, brillo::Blob* out) const = 0;
90 };
91
92 class BzipTest {};
93
94 template <>
95 class ZipTest<BzipTest> : public ::testing::Test {
96 public:
ZipCompress(const brillo::Blob & in,brillo::Blob * out) const97 bool ZipCompress(const brillo::Blob& in, brillo::Blob* out) const {
98 return BzipCompress(in, out);
99 }
ZipDecompress(const brillo::Blob & in,brillo::Blob * out) const100 bool ZipDecompress(const brillo::Blob& in, brillo::Blob* out) const {
101 return DecompressWithWriter<BzipExtentWriter>(in, out);
102 }
103 };
104
105 class XzTest {};
106
107 template <>
108 class ZipTest<XzTest> : public ::testing::Test {
109 public:
ZipCompress(const brillo::Blob & in,brillo::Blob * out) const110 bool ZipCompress(const brillo::Blob& in, brillo::Blob* out) const {
111 return XzCompress(in, out);
112 }
ZipDecompress(const brillo::Blob & in,brillo::Blob * out) const113 bool ZipDecompress(const brillo::Blob& in, brillo::Blob* out) const {
114 return DecompressWithWriter<XzExtentWriter>(in, out);
115 }
116 };
117
118 #ifdef __ANDROID__
119 typedef ::testing::Types<BzipTest, XzTest> ZipTestTypes;
120 #else
121 // Chrome OS implementation of Xz compressor just returns false.
122 typedef ::testing::Types<BzipTest> ZipTestTypes;
123 #endif // __ANDROID__
124
125 TYPED_TEST_CASE(ZipTest, ZipTestTypes);
126
TYPED_TEST(ZipTest,SimpleTest)127 TYPED_TEST(ZipTest, SimpleTest) {
128 string in_str(
129 "this should compress well xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
130 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
131 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
132 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
133 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
134 "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
135 brillo::Blob in(in_str.begin(), in_str.end());
136 brillo::Blob out;
137 EXPECT_TRUE(this->ZipCompress(in, &out));
138 EXPECT_LT(out.size(), in.size());
139 EXPECT_GT(out.size(), 0U);
140 brillo::Blob decompressed;
141 EXPECT_TRUE(this->ZipDecompress(out, &decompressed));
142 EXPECT_EQ(in.size(), decompressed.size());
143 EXPECT_TRUE(!memcmp(in.data(), decompressed.data(), in.size()));
144 }
145
TYPED_TEST(ZipTest,PoorCompressionTest)146 TYPED_TEST(ZipTest, PoorCompressionTest) {
147 brillo::Blob in(std::begin(kRandomString), std::end(kRandomString));
148 brillo::Blob out;
149 EXPECT_TRUE(this->ZipCompress(in, &out));
150 EXPECT_GT(out.size(), in.size());
151 brillo::Blob decompressed;
152 EXPECT_TRUE(this->ZipDecompress(out, &decompressed));
153 EXPECT_EQ(in.size(), decompressed.size());
154 EXPECT_EQ(in, decompressed);
155 }
156
TYPED_TEST(ZipTest,MalformedZipTest)157 TYPED_TEST(ZipTest, MalformedZipTest) {
158 brillo::Blob in(std::begin(kRandomString), std::end(kRandomString));
159 brillo::Blob out;
160 EXPECT_FALSE(this->ZipDecompress(in, &out));
161 }
162
TYPED_TEST(ZipTest,EmptyInputsTest)163 TYPED_TEST(ZipTest, EmptyInputsTest) {
164 brillo::Blob in;
165 brillo::Blob out;
166 EXPECT_TRUE(this->ZipDecompress(in, &out));
167 EXPECT_EQ(0U, out.size());
168
169 EXPECT_TRUE(this->ZipCompress(in, &out));
170 EXPECT_EQ(0U, out.size());
171 }
172
173 } // namespace chromeos_update_engine
174