blob: 6de804e06cf76f7f9b063aea6be401963c077670 [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
660// Look for the generated source and patch pieces in the debug_dir and generate the target on
661// each pair. Concatenate the split target and match against the orignal one.
662static void GenerateAndCheckSplitTarget(const std::string& debug_dir, size_t count,
663 const std::string& tgt) {
664 std::string patched;
665 for (size_t i = 0; i < count; i++) {
666 std::string split_src_path = android::base::StringPrintf("%s/src-%zu", debug_dir.c_str(), i);
667 std::string split_patch_path = android::base::StringPrintf("%s/patch-%zu", debug_dir.c_str(), i);
668
669 std::string split_src;
670 std::string split_patch;
671 ASSERT_TRUE(android::base::ReadFileToString(split_src_path, &split_src));
672 ASSERT_TRUE(android::base::ReadFileToString(split_patch_path, &split_patch));
673
674 std::string split_tgt;
675 GenerateTarget(split_src, split_patch, &split_tgt);
676 patched += split_tgt;
677 }
678
679 // Verify we can get back the original target image.
680 ASSERT_EQ(tgt, patched);
681}
682
683std::vector<ImageChunk> ConstructImageChunks(
684 const std::vector<uint8_t>& content, const std::vector<std::tuple<std::string, size_t>>& info) {
685 std::vector<ImageChunk> chunks;
686 size_t start = 0;
687 for (const auto& t : info) {
688 size_t length = std::get<1>(t);
689 chunks.emplace_back(CHUNK_NORMAL, start, &content, length, std::get<0>(t));
690 start += length;
691 }
692
693 return chunks;
694}
695
696TEST(ImgdiffTest, zip_mode_split_image_smoke) {
697 std::vector<uint8_t> content;
698 content.reserve(4096 * 50);
699 uint8_t n = 0;
700 generate_n(back_inserter(content), 4096 * 50, [&n]() { return n++ / 4096; });
701
702 ZipModeImage tgt_image(false, 4096 * 10);
703 std::vector<ImageChunk> tgt_chunks = ConstructImageChunks(content, { { "a", 100 },
704 { "b", 4096 * 2 },
705 { "c", 4096 * 3 },
706 { "d", 300 },
707 { "e-0", 4096 * 10 },
708 { "e-1", 4096 * 5 },
709 { "CD", 200 } });
710 tgt_image.Initialize(std::move(tgt_chunks),
711 std::vector<uint8_t>(content.begin(), content.begin() + 82520));
712
713 tgt_image.DumpChunks();
714
715 ZipModeImage src_image(true, 4096 * 10);
716 std::vector<ImageChunk> src_chunks = ConstructImageChunks(content, { { "b", 4096 * 3 },
717 { "c-0", 4096 * 10 },
718 { "c-1", 4096 * 2 },
719 { "a", 4096 * 5 },
720 { "e-0", 4096 * 10 },
721 { "e-1", 10000 },
722 { "CD", 5000 } });
723 src_image.Initialize(std::move(src_chunks),
724 std::vector<uint8_t>(content.begin(), content.begin() + 137880));
725
726 std::vector<ZipModeImage> split_tgt_images;
727 std::vector<ZipModeImage> split_src_images;
728 std::vector<SortedRangeSet> split_src_ranges;
729
730 ZipModeImage::SplitZipModeImageWithLimit(tgt_image, src_image, &split_tgt_images,
731 &split_src_images, &split_src_ranges);
732
733 // src_piece 1: a 5 blocks, b 3 blocks
734 // src_piece 2: c-0 10 blocks
735 // src_piece 3: d 0 block, e-0 10 blocks
736 // src_piece 4: e-1 2 blocks; CD 2 blocks
737 ASSERT_EQ(split_tgt_images.size(), split_src_images.size());
738 ASSERT_EQ(static_cast<size_t>(4), split_tgt_images.size());
739
740 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[0].NumOfChunks());
741 ASSERT_EQ(static_cast<size_t>(12288), split_tgt_images[0][0].DataLengthForPatch());
742 ASSERT_EQ("4,0,3,15,20", split_src_ranges[0].ToString());
743
744 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[1].NumOfChunks());
745 ASSERT_EQ(static_cast<size_t>(12288), split_tgt_images[1][0].DataLengthForPatch());
746 ASSERT_EQ("2,3,13", split_src_ranges[1].ToString());
747
748 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[2].NumOfChunks());
749 ASSERT_EQ(static_cast<size_t>(40960), split_tgt_images[2][0].DataLengthForPatch());
750 ASSERT_EQ("2,20,30", split_src_ranges[2].ToString());
751
752 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[3].NumOfChunks());
753 ASSERT_EQ(static_cast<size_t>(16984), split_tgt_images[3][0].DataLengthForPatch());
754 ASSERT_EQ("2,30,34", split_src_ranges[3].ToString());
755}
756
757TEST(ImgdiffTest, zip_mode_store_large_apk) {
758 // Construct src and tgt zip files with limit = 10 blocks.
759 // src tgt
760 // 12 blocks 'd' 3 blocks 'a'
761 // 8 blocks 'c' 3 blocks 'b'
762 // 3 blocks 'b' 8 blocks 'c' (exceeds limit)
763 // 3 blocks 'a' 12 blocks 'd' (exceeds limit)
764 // 3 blocks 'e'
765 TemporaryFile tgt_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700766 FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700767 ZipWriter tgt_writer(tgt_file_ptr);
768 construct_store_entry(
769 { { "a", 3, 'a' }, { "b", 3, 'b' }, { "c", 8, 'c' }, { "d", 12, 'd' }, { "e", 3, 'e' } },
770 &tgt_writer);
771 ASSERT_EQ(0, tgt_writer.Finish());
772 ASSERT_EQ(0, fclose(tgt_file_ptr));
773
774 TemporaryFile src_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700775 FILE* src_file_ptr = fdopen(src_file.release(), "wb");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700776 ZipWriter src_writer(src_file_ptr);
777 construct_store_entry({ { "d", 12, 'd' }, { "c", 8, 'c' }, { "b", 3, 'b' }, { "a", 3, 'a' } },
778 &src_writer);
779 ASSERT_EQ(0, src_writer.Finish());
780 ASSERT_EQ(0, fclose(src_file_ptr));
781
782 // Compute patch.
783 TemporaryFile patch_file;
Tianjie Xu82582b42017-08-31 18:05:19 -0700784 TemporaryFile split_info_file;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700785 TemporaryDir debug_dir;
Tianjie Xu82582b42017-08-31 18:05:19 -0700786 std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
Tianjie Xu8ba7c452017-09-12 11:13:02 -0700787 std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700788 std::vector<const char*> args = {
Tianjie Xu82582b42017-08-31 18:05:19 -0700789 "imgdiff", "-z", "--block-limit=10", split_info_arg.c_str(), debug_dir_arg.c_str(),
790 src_file.path, tgt_file.path, patch_file.path,
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700791 };
792 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
793
794 std::string tgt;
795 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
796
Tao Baof29ed3e2017-10-24 16:48:32 -0700797 // 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 -0700798 GenerateAndCheckSplitTarget(debug_dir.path, 4, tgt);
799}
800
801TEST(ImgdiffTest, zip_mode_deflate_large_apk) {
Tianjie Xu113fe052017-10-24 16:12:35 -0700802 // Src and tgt zip files are constructed as follows.
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700803 // src tgt
804 // 22 blocks, "d" 4 blocks, "a"
805 // 5 blocks, "b" 4 blocks, "b"
Tianjie Xu113fe052017-10-24 16:12:35 -0700806 // 3 blocks, "a" 8 blocks, "c" (exceeds limit)
807 // 1 block, "g" 20 blocks, "d" (exceeds limit)
808 // 8 blocks, "c" 2 blocks, "e"
809 // 1 block, "f" 1 block , "f"
810 std::string tgt_path = from_testdata_base("deflate_tgt.zip");
811 std::string src_path = from_testdata_base("deflate_src.zip");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700812
813 ZipModeImage src_image(true, 10 * 4096);
814 ZipModeImage tgt_image(false, 10 * 4096);
Tianjie Xu113fe052017-10-24 16:12:35 -0700815 ASSERT_TRUE(src_image.Initialize(src_path));
816 ASSERT_TRUE(tgt_image.Initialize(tgt_path));
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700817 ASSERT_TRUE(ZipModeImage::CheckAndProcessChunks(&tgt_image, &src_image));
818
819 src_image.DumpChunks();
820 tgt_image.DumpChunks();
821
822 std::vector<ZipModeImage> split_tgt_images;
823 std::vector<ZipModeImage> split_src_images;
824 std::vector<SortedRangeSet> split_src_ranges;
825 ZipModeImage::SplitZipModeImageWithLimit(tgt_image, src_image, &split_tgt_images,
826 &split_src_images, &split_src_ranges);
827
Tianjie Xu113fe052017-10-24 16:12:35 -0700828 // Expected split images with limit = 10 blocks.
829 // src_piece 0: a 3 blocks, b 5 blocks
830 // src_piece 1: c 8 blocks
831 // src_piece 2: d-0 10 block
832 // src_piece 3: d-1 10 blocks
833 // src_piece 4: e 1 block, CD
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700834 ASSERT_EQ(split_tgt_images.size(), split_src_images.size());
835 ASSERT_EQ(static_cast<size_t>(5), split_tgt_images.size());
836
837 ASSERT_EQ(static_cast<size_t>(2), split_src_images[0].NumOfChunks());
838 ASSERT_EQ("a", split_src_images[0][0].GetEntryName());
839 ASSERT_EQ("b", split_src_images[0][1].GetEntryName());
840
841 ASSERT_EQ(static_cast<size_t>(1), split_src_images[1].NumOfChunks());
842 ASSERT_EQ("c", split_src_images[1][0].GetEntryName());
843
844 ASSERT_EQ(static_cast<size_t>(0), split_src_images[2].NumOfChunks());
845 ASSERT_EQ(static_cast<size_t>(0), split_src_images[3].NumOfChunks());
846 ASSERT_EQ(static_cast<size_t>(0), split_src_images[4].NumOfChunks());
847
848 // Compute patch.
849 TemporaryFile patch_file;
Tianjie Xu82582b42017-08-31 18:05:19 -0700850 TemporaryFile split_info_file;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700851 TemporaryDir debug_dir;
852 ASSERT_TRUE(ZipModeImage::GeneratePatches(split_tgt_images, split_src_images, split_src_ranges,
Tianjie Xu82582b42017-08-31 18:05:19 -0700853 patch_file.path, split_info_file.path, debug_dir.path));
854
855 // Verify the content of split info.
856 // Expect 5 pieces of patch. ["a","b"; "c"; "d-0"; "d-1"; "e"]
857 std::string split_info_string;
858 android::base::ReadFileToString(split_info_file.path, &split_info_string);
859 std::vector<std::string> info_list =
860 android::base::Split(android::base::Trim(split_info_string), "\n");
861
862 ASSERT_EQ(static_cast<size_t>(7), info_list.size());
863 ASSERT_EQ("2", android::base::Trim(info_list[0]));
864 ASSERT_EQ("5", android::base::Trim(info_list[1]));
865
Tianjie Xu113fe052017-10-24 16:12:35 -0700866 std::string tgt;
867 ASSERT_TRUE(android::base::ReadFileToString(tgt_path, &tgt));
868 ASSERT_EQ(static_cast<size_t>(160385), tgt.size());
869 std::vector<std::string> tgt_file_ranges = {
870 "36864 2,22,31", "32768 2,31,40", "40960 2,0,11", "40960 2,11,21", "8833 4,21,22,40,41",
871 };
872
Tianjie Xu82582b42017-08-31 18:05:19 -0700873 for (size_t i = 0; i < 5; i++) {
Tianjie Xu113fe052017-10-24 16:12:35 -0700874 struct stat st;
Tianjie Xu82582b42017-08-31 18:05:19 -0700875 std::string path = android::base::StringPrintf("%s/patch-%zu", debug_dir.path, i);
876 ASSERT_EQ(0, stat(path.c_str(), &st));
Tianjie Xu113fe052017-10-24 16:12:35 -0700877 ASSERT_EQ(std::to_string(st.st_size) + " " + tgt_file_ranges[i],
878 android::base::Trim(info_list[i + 2]));
Tianjie Xu82582b42017-08-31 18:05:19 -0700879 }
880
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700881 GenerateAndCheckSplitTarget(debug_dir.path, 5, tgt);
882}
883
884TEST(ImgdiffTest, zip_mode_no_match_source) {
885 // Generate 20 blocks of random data.
886 std::string random_data;
887 random_data.reserve(4096 * 20);
888 generate_n(back_inserter(random_data), 4096 * 20, []() { return rand() % 256; });
889
890 TemporaryFile tgt_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700891 FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700892 ZipWriter tgt_writer(tgt_file_ptr);
893
894 construct_deflate_entry({ { "a", 0, 4 }, { "b", 5, 5 }, { "c", 11, 5 } }, &tgt_writer,
895 random_data);
896
897 ASSERT_EQ(0, tgt_writer.Finish());
898 ASSERT_EQ(0, fclose(tgt_file_ptr));
899
900 // We don't have a matching source entry.
901 TemporaryFile src_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700902 FILE* src_file_ptr = fdopen(src_file.release(), "wb");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700903 ZipWriter src_writer(src_file_ptr);
904 construct_store_entry({ { "d", 1, 'd' } }, &src_writer);
905 ASSERT_EQ(0, src_writer.Finish());
906 ASSERT_EQ(0, fclose(src_file_ptr));
907
908 // Compute patch.
909 TemporaryFile patch_file;
Tianjie Xu82582b42017-08-31 18:05:19 -0700910 TemporaryFile split_info_file;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700911 TemporaryDir debug_dir;
Tianjie Xu82582b42017-08-31 18:05:19 -0700912 std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
Tianjie Xu8ba7c452017-09-12 11:13:02 -0700913 std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700914 std::vector<const char*> args = {
Tianjie Xu82582b42017-08-31 18:05:19 -0700915 "imgdiff", "-z", "--block-limit=10", debug_dir_arg.c_str(), split_info_arg.c_str(),
916 src_file.path, tgt_file.path, patch_file.path,
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700917 };
918 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
919
920 std::string tgt;
921 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
922
923 // Expect 1 pieces of patch due to no matching source entry.
924 GenerateAndCheckSplitTarget(debug_dir.path, 1, tgt);
925}
926
927TEST(ImgdiffTest, zip_mode_large_enough_limit) {
928 // Generate 20 blocks of random data.
929 std::string random_data;
930 random_data.reserve(4096 * 20);
931 generate_n(back_inserter(random_data), 4096 * 20, []() { return rand() % 256; });
932
933 TemporaryFile tgt_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700934 FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700935 ZipWriter tgt_writer(tgt_file_ptr);
936
937 construct_deflate_entry({ { "a", 0, 10 }, { "b", 10, 5 } }, &tgt_writer, random_data);
938
939 ASSERT_EQ(0, tgt_writer.Finish());
940 ASSERT_EQ(0, fclose(tgt_file_ptr));
941
942 // Construct 10 blocks of source.
943 TemporaryFile src_file;
Tao Baof29ed3e2017-10-24 16:48:32 -0700944 FILE* src_file_ptr = fdopen(src_file.release(), "wb");
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700945 ZipWriter src_writer(src_file_ptr);
946 construct_deflate_entry({ { "a", 1, 10 } }, &src_writer, random_data);
947 ASSERT_EQ(0, src_writer.Finish());
948 ASSERT_EQ(0, fclose(src_file_ptr));
949
950 // Compute patch with a limit of 20 blocks.
951 TemporaryFile patch_file;
Tianjie Xu82582b42017-08-31 18:05:19 -0700952 TemporaryFile split_info_file;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700953 TemporaryDir debug_dir;
Tianjie Xu82582b42017-08-31 18:05:19 -0700954 std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
Tianjie Xu8ba7c452017-09-12 11:13:02 -0700955 std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700956 std::vector<const char*> args = {
Tianjie Xu82582b42017-08-31 18:05:19 -0700957 "imgdiff", "-z", "--block-limit=20", split_info_arg.c_str(), debug_dir_arg.c_str(),
958 src_file.path, tgt_file.path, patch_file.path,
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700959 };
960 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
961
962 std::string tgt;
963 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
964
Tao Baof29ed3e2017-10-24 16:48:32 -0700965 // Expect 1 piece of patch since limit is larger than the zip file size.
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700966 GenerateAndCheckSplitTarget(debug_dir.path, 1, tgt);
967}