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