blob: 6c23def01d87ab89ad5aa7938185b14013596cce [file] [log] [blame]
Tao Bao97555da2016-12-15 10:15:06 -08001/*
2 * Copyright (C) 2016 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
Tao Baoc0e1c462017-02-01 10:20:10 -080017#include <stdio.h>
18
Tianjie Xu2903cdd2017-08-18 18:15:47 -070019#include <algorithm>
Tao Bao97555da2016-12-15 10:15:06 -080020#include <string>
Tianjie Xu2903cdd2017-08-18 18:15:47 -070021#include <tuple>
Tao Bao97555da2016-12-15 10:15:06 -080022#include <vector>
23
24#include <android-base/file.h>
Tianjie Xu12b90552017-03-07 14:44:14 -080025#include <android-base/memory.h>
Tianjie Xu2903cdd2017-08-18 18:15:47 -070026#include <android-base/stringprintf.h>
Tao Bao45685822017-10-13 14:54:12 -070027#include <android-base/strings.h>
Tao Bao97555da2016-12-15 10:15:06 -080028#include <android-base/test_utils.h>
29#include <applypatch/imgdiff.h>
Tianjie Xu2903cdd2017-08-18 18:15:47 -070030#include <applypatch/imgdiff_image.h>
Tao Bao97555da2016-12-15 10:15:06 -080031#include <applypatch/imgpatch.h>
32#include <gtest/gtest.h>
33#include <ziparchive/zip_writer.h>
34
Tianjie Xu113fe052017-10-24 16:12:35 -070035#include "common/test_constants.h"
36
Tianjie Xu12b90552017-03-07 14:44:14 -080037using android::base::get_unaligned;
Tao Bao97555da2016-12-15 10:15:06 -080038
Tao Bao97555da2016-12-15 10:15:06 -080039// Sanity check for the given imgdiff patch header.
40static void verify_patch_header(const std::string& patch, size_t* num_normal, size_t* num_raw,
41 size_t* num_deflate) {
42 const size_t size = patch.size();
43 const char* data = patch.data();
44
45 ASSERT_GE(size, 12U);
46 ASSERT_EQ("IMGDIFF2", std::string(data, 8));
47
Tianjie Xu12b90552017-03-07 14:44:14 -080048 const int num_chunks = get_unaligned<int32_t>(data + 8);
Tao Bao97555da2016-12-15 10:15:06 -080049 ASSERT_GE(num_chunks, 0);
50
51 size_t normal = 0;
52 size_t raw = 0;
53 size_t deflate = 0;
54
55 size_t pos = 12;
56 for (int i = 0; i < num_chunks; ++i) {
57 ASSERT_LE(pos + 4, size);
Tianjie Xu12b90552017-03-07 14:44:14 -080058 int type = get_unaligned<int32_t>(data + pos);
Tao Bao97555da2016-12-15 10:15:06 -080059 pos += 4;
60 if (type == CHUNK_NORMAL) {
61 pos += 24;
62 ASSERT_LE(pos, size);
63 normal++;
64 } else if (type == CHUNK_RAW) {
65 ASSERT_LE(pos + 4, size);
Tianjie Xu12b90552017-03-07 14:44:14 -080066 ssize_t data_len = get_unaligned<int32_t>(data + pos);
Tao Bao97555da2016-12-15 10:15:06 -080067 ASSERT_GT(data_len, 0);
68 pos += 4 + data_len;
69 ASSERT_LE(pos, size);
70 raw++;
71 } else if (type == CHUNK_DEFLATE) {
72 pos += 60;
73 ASSERT_LE(pos, size);
74 deflate++;
75 } else {
76 FAIL() << "Invalid patch type: " << type;
77 }
78 }
79
80 if (num_normal != nullptr) *num_normal = normal;
81 if (num_raw != nullptr) *num_raw = raw;
82 if (num_deflate != nullptr) *num_deflate = deflate;
83}
84
Tianjie Xu2903cdd2017-08-18 18:15:47 -070085static void GenerateTarget(const std::string& src, const std::string& patch, std::string* patched) {
86 patched->clear();
87 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
88 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
89 [&](const unsigned char* data, size_t len) {
90 patched->append(reinterpret_cast<const char*>(data), len);
91 return len;
92 }));
93}
94
Tao Baoc0e1c462017-02-01 10:20:10 -080095static void verify_patched_image(const std::string& src, const std::string& patch,
96 const std::string& tgt) {
97 std::string patched;
Tianjie Xu2903cdd2017-08-18 18:15:47 -070098 GenerateTarget(src, patch, &patched);
Tao Baoc0e1c462017-02-01 10:20:10 -080099 ASSERT_EQ(tgt, patched);
100}
101
Tao Bao97555da2016-12-15 10:15:06 -0800102TEST(ImgdiffTest, invalid_args) {
103 // Insufficient inputs.
104 ASSERT_EQ(2, imgdiff(1, (const char* []){ "imgdiff" }));
105 ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-z" }));
106 ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-b" }));
107 ASSERT_EQ(2, imgdiff(3, (const char* []){ "imgdiff", "-z", "-b" }));
108
109 // Failed to read bonus file.
110 ASSERT_EQ(1, imgdiff(3, (const char* []){ "imgdiff", "-b", "doesntexist" }));
111
112 // Failed to read input files.
113 ASSERT_EQ(1, imgdiff(4, (const char* []){ "imgdiff", "doesntexist", "doesntexist", "output" }));
114 ASSERT_EQ(
115 1, imgdiff(5, (const char* []){ "imgdiff", "-z", "doesntexist", "doesntexist", "output" }));
116}
117
118TEST(ImgdiffTest, image_mode_smoke) {
119 // Random bytes.
120 const std::string src("abcdefg");
121 TemporaryFile src_file;
122 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
123
124 const std::string tgt("abcdefgxyz");
125 TemporaryFile tgt_file;
126 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
127
128 TemporaryFile patch_file;
129 std::vector<const char*> args = {
130 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
131 };
132 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
133
134 // Verify.
135 std::string patch;
136 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
137
138 // Expect one CHUNK_RAW entry.
139 size_t num_normal;
140 size_t num_raw;
141 size_t num_deflate;
142 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
143 ASSERT_EQ(0U, num_normal);
144 ASSERT_EQ(0U, num_deflate);
145 ASSERT_EQ(1U, num_raw);
146
Tao Baoc0e1c462017-02-01 10:20:10 -0800147 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800148}
149
150TEST(ImgdiffTest, zip_mode_smoke_store) {
151 // Construct src and tgt zip files.
152 TemporaryFile src_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700153 FILE* src_file_ptr = fdopen(src_file.release(), "wb");
Tao Bao97555da2016-12-15 10:15:06 -0800154 ZipWriter src_writer(src_file_ptr);
155 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", 0)); // Store mode.
156 const std::string src_content("abcdefg");
157 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
158 ASSERT_EQ(0, src_writer.FinishEntry());
159 ASSERT_EQ(0, src_writer.Finish());
160 ASSERT_EQ(0, fclose(src_file_ptr));
161
162 TemporaryFile tgt_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700163 FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
Tao Bao97555da2016-12-15 10:15:06 -0800164 ZipWriter tgt_writer(tgt_file_ptr);
165 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", 0)); // Store mode.
166 const std::string tgt_content("abcdefgxyz");
167 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
168 ASSERT_EQ(0, tgt_writer.FinishEntry());
169 ASSERT_EQ(0, tgt_writer.Finish());
170 ASSERT_EQ(0, fclose(tgt_file_ptr));
171
172 // Compute patch.
173 TemporaryFile patch_file;
174 std::vector<const char*> args = {
175 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
176 };
177 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
178
179 // Verify.
180 std::string tgt;
181 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
182 std::string src;
183 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
184 std::string patch;
185 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
186
187 // Expect one CHUNK_RAW entry.
188 size_t num_normal;
189 size_t num_raw;
190 size_t num_deflate;
191 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
192 ASSERT_EQ(0U, num_normal);
193 ASSERT_EQ(0U, num_deflate);
194 ASSERT_EQ(1U, num_raw);
195
Tao Baoc0e1c462017-02-01 10:20:10 -0800196 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800197}
198
199TEST(ImgdiffTest, zip_mode_smoke_compressed) {
200 // Construct src and tgt zip files.
201 TemporaryFile src_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700202 FILE* src_file_ptr = fdopen(src_file.release(), "wb");
Tao Bao97555da2016-12-15 10:15:06 -0800203 ZipWriter src_writer(src_file_ptr);
204 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
205 const std::string src_content("abcdefg");
206 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
207 ASSERT_EQ(0, src_writer.FinishEntry());
208 ASSERT_EQ(0, src_writer.Finish());
209 ASSERT_EQ(0, fclose(src_file_ptr));
210
211 TemporaryFile tgt_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700212 FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
Tao Bao97555da2016-12-15 10:15:06 -0800213 ZipWriter tgt_writer(tgt_file_ptr);
214 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
215 const std::string tgt_content("abcdefgxyz");
216 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
217 ASSERT_EQ(0, tgt_writer.FinishEntry());
218 ASSERT_EQ(0, tgt_writer.Finish());
219 ASSERT_EQ(0, fclose(tgt_file_ptr));
220
221 // Compute patch.
222 TemporaryFile patch_file;
223 std::vector<const char*> args = {
224 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
225 };
226 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
227
228 // Verify.
229 std::string tgt;
230 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
231 std::string src;
232 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
233 std::string patch;
234 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
235
236 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
237 size_t num_normal;
238 size_t num_raw;
239 size_t num_deflate;
240 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
241 ASSERT_EQ(0U, num_normal);
242 ASSERT_EQ(1U, num_deflate);
243 ASSERT_EQ(2U, num_raw);
244
Tao Baoc0e1c462017-02-01 10:20:10 -0800245 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800246}
247
Tianjie Xu1ea84d62017-02-22 18:23:58 -0800248TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) {
249 // Construct src and tgt zip files.
250 TemporaryFile src_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700251 FILE* src_file_ptr = fdopen(src_file.release(), "wb");
Tianjie Xu1ea84d62017-02-22 18:23:58 -0800252 ZipWriter src_writer(src_file_ptr);
253 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
254 const std::string src_content("abcdefg");
255 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
256 ASSERT_EQ(0, src_writer.FinishEntry());
257 ASSERT_EQ(0, src_writer.Finish());
258 ASSERT_EQ(0, fclose(src_file_ptr));
259
260 TemporaryFile tgt_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700261 FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
Tianjie Xu1ea84d62017-02-22 18:23:58 -0800262 ZipWriter tgt_writer(tgt_file_ptr);
263 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
264 const std::string tgt_content("abcdefgxyz");
265 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
266 ASSERT_EQ(0, tgt_writer.FinishEntry());
267 ASSERT_EQ(0, tgt_writer.Finish());
268 // Add trailing zeros to the target zip file.
269 std::vector<uint8_t> zeros(10);
270 ASSERT_EQ(zeros.size(), fwrite(zeros.data(), sizeof(uint8_t), zeros.size(), tgt_file_ptr));
271 ASSERT_EQ(0, fclose(tgt_file_ptr));
272
273 // Compute patch.
274 TemporaryFile patch_file;
275 std::vector<const char*> args = {
276 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
277 };
278 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
279
280 // Verify.
281 std::string tgt;
282 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
283 std::string src;
284 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
285 std::string patch;
286 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
287
288 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
289 size_t num_normal;
290 size_t num_raw;
291 size_t num_deflate;
292 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
293 ASSERT_EQ(0U, num_normal);
294 ASSERT_EQ(1U, num_deflate);
295 ASSERT_EQ(2U, num_raw);
296
Tao Baoc0e1c462017-02-01 10:20:10 -0800297 verify_patched_image(src, patch, tgt);
Tianjie Xu1ea84d62017-02-22 18:23:58 -0800298}
299
Tao Bao97555da2016-12-15 10:15:06 -0800300TEST(ImgdiffTest, image_mode_simple) {
301 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
302 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
303 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
304 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
305 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
306 '\x00', '\x00', '\x00' };
307 const std::string src(src_data.cbegin(), src_data.cend());
308 TemporaryFile src_file;
309 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
310
311 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
312 const std::vector<char> tgt_data = {
313 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
314 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
315 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
316 };
317 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
318 TemporaryFile tgt_file;
319 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
320
321 TemporaryFile patch_file;
322 std::vector<const char*> args = {
323 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
324 };
325 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
326
327 // Verify.
328 std::string patch;
329 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
330
331 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
332 size_t num_normal;
333 size_t num_raw;
334 size_t num_deflate;
335 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
336 ASSERT_EQ(0U, num_normal);
337 ASSERT_EQ(1U, num_deflate);
338 ASSERT_EQ(2U, num_raw);
339
Tao Baoc0e1c462017-02-01 10:20:10 -0800340 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800341}
342
Tianjie Xu14ebc1e2017-07-05 12:04:07 -0700343TEST(ImgdiffTest, image_mode_bad_gzip) {
344 // Modify the uncompressed length in the gzip footer.
345 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
346 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
347 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
348 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
349 '\xff', '\xff', '\xff' };
350 const std::string src(src_data.cbegin(), src_data.cend());
351 TemporaryFile src_file;
352 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
353
354 // Modify the uncompressed length in the gzip footer.
355 const std::vector<char> tgt_data = {
356 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
357 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
358 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\xff', '\xff', '\xff'
359 };
360 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
361 TemporaryFile tgt_file;
362 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
363
364 TemporaryFile patch_file;
365 std::vector<const char*> args = {
366 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
367 };
368 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
369
370 // Verify.
371 std::string patch;
372 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
373 verify_patched_image(src, patch, tgt);
374}
375
Tao Bao97555da2016-12-15 10:15:06 -0800376TEST(ImgdiffTest, image_mode_different_num_chunks) {
377 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd) + gzipped "test".
378 const std::vector<char> src_data = {
379 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\x1f', '\x8b', '\x08',
380 '\x00', '\xc4', '\x1e', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', '\x02',
381 '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', '\x00', '\x00', '\x00', '\x1f', '\x8b',
382 '\x08', '\x00', '\xb2', '\x3a', '\x53', '\x58', '\x00', '\x03', '\x2b', '\x49', '\x2d',
383 '\x2e', '\x01', '\x00', '\x0c', '\x7e', '\x7f', '\xd8', '\x04', '\x00', '\x00', '\x00'
384 };
385 const std::string src(src_data.cbegin(), src_data.cend());
386 TemporaryFile src_file;
387 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
388
389 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
390 const std::vector<char> tgt_data = {
391 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
392 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
393 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
394 };
395 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
396 TemporaryFile tgt_file;
397 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
398
399 TemporaryFile patch_file;
400 std::vector<const char*> args = {
401 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
402 };
403 ASSERT_EQ(1, imgdiff(args.size(), args.data()));
404}
405
406TEST(ImgdiffTest, image_mode_merge_chunks) {
407 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
408 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
409 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
410 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
411 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
412 '\x00', '\x00', '\x00' };
413 const std::string src(src_data.cbegin(), src_data.cend());
414 TemporaryFile src_file;
415 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
416
417 // tgt: gzipped "xyz" + "abcdefgh".
418 const std::vector<char> tgt_data = {
419 '\x1f', '\x8b', '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8',
420 '\xa8', '\xac', '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00',
421 '\x00', '\x00', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'
422 };
423 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
424 TemporaryFile tgt_file;
425 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
426
427 // Since a gzipped entry will become CHUNK_RAW (header) + CHUNK_DEFLATE (data) +
428 // CHUNK_RAW (footer), they both should contain the same chunk types after merging.
429
430 TemporaryFile patch_file;
431 std::vector<const char*> args = {
432 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
433 };
434 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
435
436 // Verify.
437 std::string patch;
438 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
439
440 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
441 size_t num_normal;
442 size_t num_raw;
443 size_t num_deflate;
444 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
445 ASSERT_EQ(0U, num_normal);
446 ASSERT_EQ(1U, num_deflate);
447 ASSERT_EQ(2U, num_raw);
448
Tao Baoc0e1c462017-02-01 10:20:10 -0800449 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800450}
451
452TEST(ImgdiffTest, image_mode_spurious_magic) {
453 // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
454 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
455 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
456 '\x53', '\x58', 't', 'e', 's', 't' };
457 const std::string src(src_data.cbegin(), src_data.cend());
458 TemporaryFile src_file;
459 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
460
461 // tgt: "abcdefgxyz".
462 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
463 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
464 TemporaryFile tgt_file;
465 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
466
467 TemporaryFile patch_file;
468 std::vector<const char*> args = {
469 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
470 };
471 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
472
473 // Verify.
474 std::string patch;
475 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
476
477 // Expect one CHUNK_RAW (header) entry.
478 size_t num_normal;
479 size_t num_raw;
480 size_t num_deflate;
481 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
482 ASSERT_EQ(0U, num_normal);
483 ASSERT_EQ(0U, num_deflate);
484 ASSERT_EQ(1U, num_raw);
485
Tao Baoc0e1c462017-02-01 10:20:10 -0800486 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800487}
488
Tao Baod37ce8f2016-12-17 17:10:04 -0800489TEST(ImgdiffTest, image_mode_short_input1) {
490 // src: "abcdefgh" + '0x1f8b0b'.
491 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
492 'g', 'h', '\x1f', '\x8b', '\x08' };
493 const std::string src(src_data.cbegin(), src_data.cend());
494 TemporaryFile src_file;
495 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
496
497 // tgt: "abcdefgxyz".
498 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
499 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
500 TemporaryFile tgt_file;
501 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
502
503 TemporaryFile patch_file;
504 std::vector<const char*> args = {
505 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
506 };
507 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
508
509 // Verify.
510 std::string patch;
511 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
512
513 // Expect one CHUNK_RAW (header) entry.
514 size_t num_normal;
515 size_t num_raw;
516 size_t num_deflate;
517 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
518 ASSERT_EQ(0U, num_normal);
519 ASSERT_EQ(0U, num_deflate);
520 ASSERT_EQ(1U, num_raw);
521
Tao Baoc0e1c462017-02-01 10:20:10 -0800522 verify_patched_image(src, patch, tgt);
Tao Baod37ce8f2016-12-17 17:10:04 -0800523}
524
525TEST(ImgdiffTest, image_mode_short_input2) {
526 // src: "abcdefgh" + '0x1f8b0b00'.
527 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
528 'g', 'h', '\x1f', '\x8b', '\x08', '\x00' };
529 const std::string src(src_data.cbegin(), src_data.cend());
530 TemporaryFile src_file;
531 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
532
533 // tgt: "abcdefgxyz".
534 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
535 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
536 TemporaryFile tgt_file;
537 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
538
539 TemporaryFile patch_file;
540 std::vector<const char*> args = {
541 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
542 };
543 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
544
545 // Verify.
546 std::string patch;
547 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
548
549 // Expect one CHUNK_RAW (header) entry.
550 size_t num_normal;
551 size_t num_raw;
552 size_t num_deflate;
553 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
554 ASSERT_EQ(0U, num_normal);
555 ASSERT_EQ(0U, num_deflate);
556 ASSERT_EQ(1U, num_raw);
557
Tao Baoc0e1c462017-02-01 10:20:10 -0800558 verify_patched_image(src, patch, tgt);
Tao Baod37ce8f2016-12-17 17:10:04 -0800559}
560
Tao Bao97555da2016-12-15 10:15:06 -0800561TEST(ImgdiffTest, image_mode_single_entry_long) {
562 // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
563 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
564 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
565 '\x53', '\x58', 't', 'e', 's', 't' };
566 const std::string src(src_data.cbegin(), src_data.cend());
567 TemporaryFile src_file;
568 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
569
570 // tgt: "abcdefgxyz" + 200 bytes.
571 std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
572 tgt_data.resize(tgt_data.size() + 200);
573
574 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
575 TemporaryFile tgt_file;
576 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
577
578 TemporaryFile patch_file;
579 std::vector<const char*> args = {
580 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
581 };
582 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
583
584 // Verify.
585 std::string patch;
586 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
587
588 // Expect one CHUNK_NORMAL entry, since it's exceeding the 160-byte limit for RAW.
589 size_t num_normal;
590 size_t num_raw;
591 size_t num_deflate;
592 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
593 ASSERT_EQ(1U, num_normal);
594 ASSERT_EQ(0U, num_deflate);
595 ASSERT_EQ(0U, num_raw);
596
Tao Baoc0e1c462017-02-01 10:20:10 -0800597 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800598}
Tianjie Xuce5fa5e2017-05-15 12:32:33 -0700599
600TEST(ImgpatchTest, image_mode_patch_corruption) {
601 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
602 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
603 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
604 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
605 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
606 '\x00', '\x00', '\x00' };
607 const std::string src(src_data.cbegin(), src_data.cend());
608 TemporaryFile src_file;
609 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
610
611 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
612 const std::vector<char> tgt_data = {
613 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
614 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
615 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
616 };
617 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
618 TemporaryFile tgt_file;
619 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
620
621 TemporaryFile patch_file;
622 std::vector<const char*> args = {
623 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
624 };
625 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
626
627 // Verify.
628 std::string patch;
629 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
630 verify_patched_image(src, patch, tgt);
631
632 // Corrupt the end of the patch and expect the ApplyImagePatch to fail.
633 patch.insert(patch.end() - 10, 10, '0');
634 ASSERT_EQ(-1, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
635 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
636 [](const unsigned char* /*data*/, size_t len) { return len; }));
637}
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700638
639static void construct_store_entry(const std::vector<std::tuple<std::string, size_t, char>>& info,
640 ZipWriter* writer) {
641 for (auto& t : info) {
642 // Create t(1) blocks of t(2), and write the data to t(0)
643 ASSERT_EQ(0, writer->StartEntry(std::get<0>(t).c_str(), 0));
644 const std::string content(std::get<1>(t) * 4096, std::get<2>(t));
645 ASSERT_EQ(0, writer->WriteBytes(content.data(), content.size()));
646 ASSERT_EQ(0, writer->FinishEntry());
647 }
648}
649
650static void construct_deflate_entry(const std::vector<std::tuple<std::string, size_t, size_t>>& info,
651 ZipWriter* writer, const std::string& data) {
652 for (auto& t : info) {
653 // t(0): entry_name; t(1): block offset; t(2) length in blocks.
654 ASSERT_EQ(0, writer->StartEntry(std::get<0>(t).c_str(), ZipWriter::kCompress));
655 ASSERT_EQ(0, writer->WriteBytes(data.data() + std::get<1>(t) * 4096, std::get<2>(t) * 4096));
656 ASSERT_EQ(0, writer->FinishEntry());
657 }
658}
659
Tao Bao54c1db42017-11-01 22:21:55 -0700660// Look for the source and patch pieces in debug_dir. Generate a target piece from each pair.
661// Concatenate all the target pieces and match against the orignal one. Used pieces in debug_dir
662// will be cleaned up.
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700663static void GenerateAndCheckSplitTarget(const std::string& debug_dir, size_t count,
664 const std::string& tgt) {
665 std::string patched;
666 for (size_t i = 0; i < count; i++) {
667 std::string split_src_path = android::base::StringPrintf("%s/src-%zu", debug_dir.c_str(), i);
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700668 std::string split_src;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700669 ASSERT_TRUE(android::base::ReadFileToString(split_src_path, &split_src));
Tao Bao54c1db42017-11-01 22:21:55 -0700670 ASSERT_EQ(0, unlink(split_src_path.c_str()));
671
672 std::string split_patch_path =
673 android::base::StringPrintf("%s/patch-%zu", debug_dir.c_str(), i);
674 std::string split_patch;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700675 ASSERT_TRUE(android::base::ReadFileToString(split_patch_path, &split_patch));
Tao Bao54c1db42017-11-01 22:21:55 -0700676 ASSERT_EQ(0, unlink(split_patch_path.c_str()));
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700677
678 std::string split_tgt;
679 GenerateTarget(split_src, split_patch, &split_tgt);
680 patched += split_tgt;
681 }
682
683 // Verify we can get back the original target image.
684 ASSERT_EQ(tgt, patched);
685}
686
687std::vector<ImageChunk> ConstructImageChunks(
688 const std::vector<uint8_t>& content, const std::vector<std::tuple<std::string, size_t>>& info) {
689 std::vector<ImageChunk> chunks;
690 size_t start = 0;
691 for (const auto& t : info) {
692 size_t length = std::get<1>(t);
693 chunks.emplace_back(CHUNK_NORMAL, start, &content, length, std::get<0>(t));
694 start += length;
695 }
696
697 return chunks;
698}
699
700TEST(ImgdiffTest, zip_mode_split_image_smoke) {
701 std::vector<uint8_t> content;
702 content.reserve(4096 * 50);
703 uint8_t n = 0;
704 generate_n(back_inserter(content), 4096 * 50, [&n]() { return n++ / 4096; });
705
706 ZipModeImage tgt_image(false, 4096 * 10);
707 std::vector<ImageChunk> tgt_chunks = ConstructImageChunks(content, { { "a", 100 },
708 { "b", 4096 * 2 },
709 { "c", 4096 * 3 },
710 { "d", 300 },
711 { "e-0", 4096 * 10 },
712 { "e-1", 4096 * 5 },
713 { "CD", 200 } });
714 tgt_image.Initialize(std::move(tgt_chunks),
715 std::vector<uint8_t>(content.begin(), content.begin() + 82520));
716
717 tgt_image.DumpChunks();
718
719 ZipModeImage src_image(true, 4096 * 10);
720 std::vector<ImageChunk> src_chunks = ConstructImageChunks(content, { { "b", 4096 * 3 },
721 { "c-0", 4096 * 10 },
722 { "c-1", 4096 * 2 },
723 { "a", 4096 * 5 },
724 { "e-0", 4096 * 10 },
725 { "e-1", 10000 },
726 { "CD", 5000 } });
727 src_image.Initialize(std::move(src_chunks),
728 std::vector<uint8_t>(content.begin(), content.begin() + 137880));
729
730 std::vector<ZipModeImage> split_tgt_images;
731 std::vector<ZipModeImage> split_src_images;
732 std::vector<SortedRangeSet> split_src_ranges;
733
734 ZipModeImage::SplitZipModeImageWithLimit(tgt_image, src_image, &split_tgt_images,
735 &split_src_images, &split_src_ranges);
736
737 // src_piece 1: a 5 blocks, b 3 blocks
738 // src_piece 2: c-0 10 blocks
739 // src_piece 3: d 0 block, e-0 10 blocks
740 // src_piece 4: e-1 2 blocks; CD 2 blocks
741 ASSERT_EQ(split_tgt_images.size(), split_src_images.size());
742 ASSERT_EQ(static_cast<size_t>(4), split_tgt_images.size());
743
744 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[0].NumOfChunks());
745 ASSERT_EQ(static_cast<size_t>(12288), split_tgt_images[0][0].DataLengthForPatch());
746 ASSERT_EQ("4,0,3,15,20", split_src_ranges[0].ToString());
747
748 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[1].NumOfChunks());
749 ASSERT_EQ(static_cast<size_t>(12288), split_tgt_images[1][0].DataLengthForPatch());
750 ASSERT_EQ("2,3,13", split_src_ranges[1].ToString());
751
752 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[2].NumOfChunks());
753 ASSERT_EQ(static_cast<size_t>(40960), split_tgt_images[2][0].DataLengthForPatch());
754 ASSERT_EQ("2,20,30", split_src_ranges[2].ToString());
755
756 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[3].NumOfChunks());
757 ASSERT_EQ(static_cast<size_t>(16984), split_tgt_images[3][0].DataLengthForPatch());
758 ASSERT_EQ("2,30,34", split_src_ranges[3].ToString());
759}
760
761TEST(ImgdiffTest, zip_mode_store_large_apk) {
762 // Construct src and tgt zip files with limit = 10 blocks.
763 // src tgt
764 // 12 blocks 'd' 3 blocks 'a'
765 // 8 blocks 'c' 3 blocks 'b'
766 // 3 blocks 'b' 8 blocks 'c' (exceeds limit)
767 // 3 blocks 'a' 12 blocks 'd' (exceeds limit)
768 // 3 blocks 'e'
769 TemporaryFile tgt_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700770 FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700771 ZipWriter tgt_writer(tgt_file_ptr);
772 construct_store_entry(
773 { { "a", 3, 'a' }, { "b", 3, 'b' }, { "c", 8, 'c' }, { "d", 12, 'd' }, { "e", 3, 'e' } },
774 &tgt_writer);
775 ASSERT_EQ(0, tgt_writer.Finish());
776 ASSERT_EQ(0, fclose(tgt_file_ptr));
777
778 TemporaryFile src_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700779 FILE* src_file_ptr = fdopen(src_file.release(), "wb");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700780 ZipWriter src_writer(src_file_ptr);
781 construct_store_entry({ { "d", 12, 'd' }, { "c", 8, 'c' }, { "b", 3, 'b' }, { "a", 3, 'a' } },
782 &src_writer);
783 ASSERT_EQ(0, src_writer.Finish());
784 ASSERT_EQ(0, fclose(src_file_ptr));
785
786 // Compute patch.
787 TemporaryFile patch_file;
Tianjie Xu82582b42017-08-31 18:05:19 -0700788 TemporaryFile split_info_file;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700789 TemporaryDir debug_dir;
Tianjie Xu82582b42017-08-31 18:05:19 -0700790 std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
Tianjie Xu8ba7c452017-09-12 11:13:02 -0700791 std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700792 std::vector<const char*> args = {
Tianjie Xu82582b42017-08-31 18:05:19 -0700793 "imgdiff", "-z", "--block-limit=10", split_info_arg.c_str(), debug_dir_arg.c_str(),
794 src_file.path, tgt_file.path, patch_file.path,
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700795 };
796 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
797
798 std::string tgt;
799 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
800
Tao Baof29ed3e2017-10-24 16:48:32 -0700801 // Expect 4 pieces of patch. (Roughly 3'a',3'b'; 8'c'; 10'd'; 2'd'3'e')
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700802 GenerateAndCheckSplitTarget(debug_dir.path, 4, tgt);
803}
804
805TEST(ImgdiffTest, zip_mode_deflate_large_apk) {
Tianjie Xu113fe052017-10-24 16:12:35 -0700806 // Src and tgt zip files are constructed as follows.
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700807 // src tgt
808 // 22 blocks, "d" 4 blocks, "a"
809 // 5 blocks, "b" 4 blocks, "b"
Tianjie Xu113fe052017-10-24 16:12:35 -0700810 // 3 blocks, "a" 8 blocks, "c" (exceeds limit)
811 // 1 block, "g" 20 blocks, "d" (exceeds limit)
812 // 8 blocks, "c" 2 blocks, "e"
813 // 1 block, "f" 1 block , "f"
814 std::string tgt_path = from_testdata_base("deflate_tgt.zip");
815 std::string src_path = from_testdata_base("deflate_src.zip");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700816
817 ZipModeImage src_image(true, 10 * 4096);
818 ZipModeImage tgt_image(false, 10 * 4096);
Tianjie Xu113fe052017-10-24 16:12:35 -0700819 ASSERT_TRUE(src_image.Initialize(src_path));
820 ASSERT_TRUE(tgt_image.Initialize(tgt_path));
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700821 ASSERT_TRUE(ZipModeImage::CheckAndProcessChunks(&tgt_image, &src_image));
822
823 src_image.DumpChunks();
824 tgt_image.DumpChunks();
825
826 std::vector<ZipModeImage> split_tgt_images;
827 std::vector<ZipModeImage> split_src_images;
828 std::vector<SortedRangeSet> split_src_ranges;
829 ZipModeImage::SplitZipModeImageWithLimit(tgt_image, src_image, &split_tgt_images,
830 &split_src_images, &split_src_ranges);
831
Tianjie Xu113fe052017-10-24 16:12:35 -0700832 // Expected split images with limit = 10 blocks.
833 // src_piece 0: a 3 blocks, b 5 blocks
834 // src_piece 1: c 8 blocks
835 // src_piece 2: d-0 10 block
836 // src_piece 3: d-1 10 blocks
837 // src_piece 4: e 1 block, CD
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700838 ASSERT_EQ(split_tgt_images.size(), split_src_images.size());
839 ASSERT_EQ(static_cast<size_t>(5), split_tgt_images.size());
840
841 ASSERT_EQ(static_cast<size_t>(2), split_src_images[0].NumOfChunks());
842 ASSERT_EQ("a", split_src_images[0][0].GetEntryName());
843 ASSERT_EQ("b", split_src_images[0][1].GetEntryName());
844
845 ASSERT_EQ(static_cast<size_t>(1), split_src_images[1].NumOfChunks());
846 ASSERT_EQ("c", split_src_images[1][0].GetEntryName());
847
848 ASSERT_EQ(static_cast<size_t>(0), split_src_images[2].NumOfChunks());
849 ASSERT_EQ(static_cast<size_t>(0), split_src_images[3].NumOfChunks());
850 ASSERT_EQ(static_cast<size_t>(0), split_src_images[4].NumOfChunks());
851
852 // Compute patch.
853 TemporaryFile patch_file;
Tianjie Xu82582b42017-08-31 18:05:19 -0700854 TemporaryFile split_info_file;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700855 TemporaryDir debug_dir;
856 ASSERT_TRUE(ZipModeImage::GeneratePatches(split_tgt_images, split_src_images, split_src_ranges,
Tianjie Xu82582b42017-08-31 18:05:19 -0700857 patch_file.path, split_info_file.path, debug_dir.path));
858
859 // Verify the content of split info.
860 // Expect 5 pieces of patch. ["a","b"; "c"; "d-0"; "d-1"; "e"]
861 std::string split_info_string;
862 android::base::ReadFileToString(split_info_file.path, &split_info_string);
863 std::vector<std::string> info_list =
864 android::base::Split(android::base::Trim(split_info_string), "\n");
865
866 ASSERT_EQ(static_cast<size_t>(7), info_list.size());
867 ASSERT_EQ("2", android::base::Trim(info_list[0]));
868 ASSERT_EQ("5", android::base::Trim(info_list[1]));
869
Tianjie Xu113fe052017-10-24 16:12:35 -0700870 std::string tgt;
871 ASSERT_TRUE(android::base::ReadFileToString(tgt_path, &tgt));
872 ASSERT_EQ(static_cast<size_t>(160385), tgt.size());
873 std::vector<std::string> tgt_file_ranges = {
874 "36864 2,22,31", "32768 2,31,40", "40960 2,0,11", "40960 2,11,21", "8833 4,21,22,40,41",
875 };
876
Tianjie Xu82582b42017-08-31 18:05:19 -0700877 for (size_t i = 0; i < 5; i++) {
Tianjie Xu113fe052017-10-24 16:12:35 -0700878 struct stat st;
Tianjie Xu82582b42017-08-31 18:05:19 -0700879 std::string path = android::base::StringPrintf("%s/patch-%zu", debug_dir.path, i);
880 ASSERT_EQ(0, stat(path.c_str(), &st));
Tianjie Xu113fe052017-10-24 16:12:35 -0700881 ASSERT_EQ(std::to_string(st.st_size) + " " + tgt_file_ranges[i],
882 android::base::Trim(info_list[i + 2]));
Tianjie Xu82582b42017-08-31 18:05:19 -0700883 }
884
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700885 GenerateAndCheckSplitTarget(debug_dir.path, 5, tgt);
886}
887
888TEST(ImgdiffTest, zip_mode_no_match_source) {
889 // Generate 20 blocks of random data.
890 std::string random_data;
891 random_data.reserve(4096 * 20);
892 generate_n(back_inserter(random_data), 4096 * 20, []() { return rand() % 256; });
893
894 TemporaryFile tgt_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700895 FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700896 ZipWriter tgt_writer(tgt_file_ptr);
897
898 construct_deflate_entry({ { "a", 0, 4 }, { "b", 5, 5 }, { "c", 11, 5 } }, &tgt_writer,
899 random_data);
900
901 ASSERT_EQ(0, tgt_writer.Finish());
902 ASSERT_EQ(0, fclose(tgt_file_ptr));
903
904 // We don't have a matching source entry.
905 TemporaryFile src_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700906 FILE* src_file_ptr = fdopen(src_file.release(), "wb");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700907 ZipWriter src_writer(src_file_ptr);
908 construct_store_entry({ { "d", 1, 'd' } }, &src_writer);
909 ASSERT_EQ(0, src_writer.Finish());
910 ASSERT_EQ(0, fclose(src_file_ptr));
911
912 // Compute patch.
913 TemporaryFile patch_file;
Tianjie Xu82582b42017-08-31 18:05:19 -0700914 TemporaryFile split_info_file;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700915 TemporaryDir debug_dir;
Tianjie Xu82582b42017-08-31 18:05:19 -0700916 std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
Tianjie Xu8ba7c452017-09-12 11:13:02 -0700917 std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700918 std::vector<const char*> args = {
Tianjie Xu82582b42017-08-31 18:05:19 -0700919 "imgdiff", "-z", "--block-limit=10", debug_dir_arg.c_str(), split_info_arg.c_str(),
920 src_file.path, tgt_file.path, patch_file.path,
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700921 };
922 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
923
924 std::string tgt;
925 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
926
927 // Expect 1 pieces of patch due to no matching source entry.
928 GenerateAndCheckSplitTarget(debug_dir.path, 1, tgt);
929}
930
931TEST(ImgdiffTest, zip_mode_large_enough_limit) {
932 // Generate 20 blocks of random data.
933 std::string random_data;
934 random_data.reserve(4096 * 20);
935 generate_n(back_inserter(random_data), 4096 * 20, []() { return rand() % 256; });
936
937 TemporaryFile tgt_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700938 FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700939 ZipWriter tgt_writer(tgt_file_ptr);
940
941 construct_deflate_entry({ { "a", 0, 10 }, { "b", 10, 5 } }, &tgt_writer, random_data);
942
943 ASSERT_EQ(0, tgt_writer.Finish());
944 ASSERT_EQ(0, fclose(tgt_file_ptr));
945
946 // Construct 10 blocks of source.
947 TemporaryFile src_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700948 FILE* src_file_ptr = fdopen(src_file.release(), "wb");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700949 ZipWriter src_writer(src_file_ptr);
950 construct_deflate_entry({ { "a", 1, 10 } }, &src_writer, random_data);
951 ASSERT_EQ(0, src_writer.Finish());
952 ASSERT_EQ(0, fclose(src_file_ptr));
953
954 // Compute patch with a limit of 20 blocks.
955 TemporaryFile patch_file;
Tianjie Xu82582b42017-08-31 18:05:19 -0700956 TemporaryFile split_info_file;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700957 TemporaryDir debug_dir;
Tianjie Xu82582b42017-08-31 18:05:19 -0700958 std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
Tianjie Xu8ba7c452017-09-12 11:13:02 -0700959 std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700960 std::vector<const char*> args = {
Tianjie Xu82582b42017-08-31 18:05:19 -0700961 "imgdiff", "-z", "--block-limit=20", split_info_arg.c_str(), debug_dir_arg.c_str(),
962 src_file.path, tgt_file.path, patch_file.path,
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700963 };
964 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
965
966 std::string tgt;
967 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
968
Tao Baof29ed3e2017-10-24 16:48:32 -0700969 // Expect 1 piece of patch since limit is larger than the zip file size.
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700970 GenerateAndCheckSplitTarget(debug_dir.path, 1, tgt);
971}
Tianjie Xu572abbb2018-02-22 15:40:39 -0800972
973TEST(ImgdiffTest, zip_mode_large_apk_small_target_chunk) {
974 TemporaryFile tgt_file;
975 FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
976 ZipWriter tgt_writer(tgt_file_ptr);
977
978 // The first entry is less than 4096 bytes, followed immediately by an entry that has a very
979 // large counterpart in the source file. Therefore the first entry will be patched separately.
980 std::string small_chunk("a", 2000);
981 ASSERT_EQ(0, tgt_writer.StartEntry("a", 0));
982 ASSERT_EQ(0, tgt_writer.WriteBytes(small_chunk.data(), small_chunk.size()));
983 ASSERT_EQ(0, tgt_writer.FinishEntry());
984 construct_store_entry(
985 {
986 { "b", 12, 'b' }, { "c", 3, 'c' },
987 },
988 &tgt_writer);
989 ASSERT_EQ(0, tgt_writer.Finish());
990 ASSERT_EQ(0, fclose(tgt_file_ptr));
991
992 TemporaryFile src_file;
993 FILE* src_file_ptr = fdopen(src_file.release(), "wb");
994 ZipWriter src_writer(src_file_ptr);
995 construct_store_entry({ { "a", 1, 'a' }, { "b", 13, 'b' }, { "c", 1, 'c' } }, &src_writer);
996 ASSERT_EQ(0, src_writer.Finish());
997 ASSERT_EQ(0, fclose(src_file_ptr));
998
999 // Compute patch.
1000 TemporaryFile patch_file;
1001 TemporaryFile split_info_file;
1002 TemporaryDir debug_dir;
1003 std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
1004 std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
1005 std::vector<const char*> args = {
1006 "imgdiff", "-z", "--block-limit=10", split_info_arg.c_str(), debug_dir_arg.c_str(),
1007 src_file.path, tgt_file.path, patch_file.path,
1008 };
1009 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
1010
1011 std::string tgt;
1012 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
1013
1014 // Expect three split src images:
1015 // src_piece 0: a 1 blocks
1016 // src_piece 1: b-0 10 blocks
1017 // src_piece 2: b-1 3 blocks, c 1 blocks, CD
1018 GenerateAndCheckSplitTarget(debug_dir.path, 3, tgt);
1019}
1020
1021TEST(ImgdiffTest, zip_mode_large_apk_skipped_small_target_chunk) {
1022 TemporaryFile tgt_file;
1023 FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
1024 ZipWriter tgt_writer(tgt_file_ptr);
1025
1026 construct_store_entry(
1027 {
1028 { "a", 11, 'a' },
1029 },
1030 &tgt_writer);
1031
1032 // Construct a tiny target entry of 1 byte, which will be skipped due to the tail alignment of
1033 // the previous entry.
1034 std::string small_chunk("b", 1);
1035 ASSERT_EQ(0, tgt_writer.StartEntry("b", 0));
1036 ASSERT_EQ(0, tgt_writer.WriteBytes(small_chunk.data(), small_chunk.size()));
1037 ASSERT_EQ(0, tgt_writer.FinishEntry());
1038
1039 ASSERT_EQ(0, tgt_writer.Finish());
1040 ASSERT_EQ(0, fclose(tgt_file_ptr));
1041
1042 TemporaryFile src_file;
1043 FILE* src_file_ptr = fdopen(src_file.release(), "wb");
1044 ZipWriter src_writer(src_file_ptr);
1045 construct_store_entry(
1046 {
1047 { "a", 11, 'a' }, { "b", 11, 'b' },
1048 },
1049 &src_writer);
1050 ASSERT_EQ(0, src_writer.Finish());
1051 ASSERT_EQ(0, fclose(src_file_ptr));
1052
1053 // Compute patch.
1054 TemporaryFile patch_file;
1055 TemporaryFile split_info_file;
1056 TemporaryDir debug_dir;
1057 std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
1058 std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
1059 std::vector<const char*> args = {
1060 "imgdiff", "-z", "--block-limit=10", split_info_arg.c_str(), debug_dir_arg.c_str(),
1061 src_file.path, tgt_file.path, patch_file.path,
1062 };
1063 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
1064
1065 std::string tgt;
1066 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
1067
1068 // Expect two split src images:
1069 // src_piece 0: a-0 10 blocks
1070 // src_piece 1: a-0 1 block, CD
1071 GenerateAndCheckSplitTarget(debug_dir.path, 2, tgt);
1072}