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