blob: 161d58d457d23546d43f1d8ef523fe9f509953d0 [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 Bao97555da2016-12-15 10:15:06 -080027#include <android-base/test_utils.h>
28#include <applypatch/imgdiff.h>
Tianjie Xu2903cdd2017-08-18 18:15:47 -070029#include <applypatch/imgdiff_image.h>
Tao Bao97555da2016-12-15 10:15:06 -080030#include <applypatch/imgpatch.h>
31#include <gtest/gtest.h>
32#include <ziparchive/zip_writer.h>
33
Tianjie Xu12b90552017-03-07 14:44:14 -080034using android::base::get_unaligned;
Tao Bao97555da2016-12-15 10:15:06 -080035
Tao Bao97555da2016-12-15 10:15:06 -080036// Sanity check for the given imgdiff patch header.
37static void verify_patch_header(const std::string& patch, size_t* num_normal, size_t* num_raw,
38 size_t* num_deflate) {
39 const size_t size = patch.size();
40 const char* data = patch.data();
41
42 ASSERT_GE(size, 12U);
43 ASSERT_EQ("IMGDIFF2", std::string(data, 8));
44
Tianjie Xu12b90552017-03-07 14:44:14 -080045 const int num_chunks = get_unaligned<int32_t>(data + 8);
Tao Bao97555da2016-12-15 10:15:06 -080046 ASSERT_GE(num_chunks, 0);
47
48 size_t normal = 0;
49 size_t raw = 0;
50 size_t deflate = 0;
51
52 size_t pos = 12;
53 for (int i = 0; i < num_chunks; ++i) {
54 ASSERT_LE(pos + 4, size);
Tianjie Xu12b90552017-03-07 14:44:14 -080055 int type = get_unaligned<int32_t>(data + pos);
Tao Bao97555da2016-12-15 10:15:06 -080056 pos += 4;
57 if (type == CHUNK_NORMAL) {
58 pos += 24;
59 ASSERT_LE(pos, size);
60 normal++;
61 } else if (type == CHUNK_RAW) {
62 ASSERT_LE(pos + 4, size);
Tianjie Xu12b90552017-03-07 14:44:14 -080063 ssize_t data_len = get_unaligned<int32_t>(data + pos);
Tao Bao97555da2016-12-15 10:15:06 -080064 ASSERT_GT(data_len, 0);
65 pos += 4 + data_len;
66 ASSERT_LE(pos, size);
67 raw++;
68 } else if (type == CHUNK_DEFLATE) {
69 pos += 60;
70 ASSERT_LE(pos, size);
71 deflate++;
72 } else {
73 FAIL() << "Invalid patch type: " << type;
74 }
75 }
76
77 if (num_normal != nullptr) *num_normal = normal;
78 if (num_raw != nullptr) *num_raw = raw;
79 if (num_deflate != nullptr) *num_deflate = deflate;
80}
81
Tianjie Xu2903cdd2017-08-18 18:15:47 -070082static void GenerateTarget(const std::string& src, const std::string& patch, std::string* patched) {
83 patched->clear();
84 ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
85 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
86 [&](const unsigned char* data, size_t len) {
87 patched->append(reinterpret_cast<const char*>(data), len);
88 return len;
89 }));
90}
91
Tao Baoc0e1c462017-02-01 10:20:10 -080092static void verify_patched_image(const std::string& src, const std::string& patch,
93 const std::string& tgt) {
94 std::string patched;
Tianjie Xu2903cdd2017-08-18 18:15:47 -070095 GenerateTarget(src, patch, &patched);
Tao Baoc0e1c462017-02-01 10:20:10 -080096 ASSERT_EQ(tgt, patched);
97}
98
Tao Bao97555da2016-12-15 10:15:06 -080099TEST(ImgdiffTest, invalid_args) {
100 // Insufficient inputs.
101 ASSERT_EQ(2, imgdiff(1, (const char* []){ "imgdiff" }));
102 ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-z" }));
103 ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-b" }));
104 ASSERT_EQ(2, imgdiff(3, (const char* []){ "imgdiff", "-z", "-b" }));
105
106 // Failed to read bonus file.
107 ASSERT_EQ(1, imgdiff(3, (const char* []){ "imgdiff", "-b", "doesntexist" }));
108
109 // Failed to read input files.
110 ASSERT_EQ(1, imgdiff(4, (const char* []){ "imgdiff", "doesntexist", "doesntexist", "output" }));
111 ASSERT_EQ(
112 1, imgdiff(5, (const char* []){ "imgdiff", "-z", "doesntexist", "doesntexist", "output" }));
113}
114
115TEST(ImgdiffTest, image_mode_smoke) {
116 // Random bytes.
117 const std::string src("abcdefg");
118 TemporaryFile src_file;
119 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
120
121 const std::string tgt("abcdefgxyz");
122 TemporaryFile tgt_file;
123 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
124
125 TemporaryFile patch_file;
126 std::vector<const char*> args = {
127 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
128 };
129 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
130
131 // Verify.
132 std::string patch;
133 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
134
135 // Expect one CHUNK_RAW entry.
136 size_t num_normal;
137 size_t num_raw;
138 size_t num_deflate;
139 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
140 ASSERT_EQ(0U, num_normal);
141 ASSERT_EQ(0U, num_deflate);
142 ASSERT_EQ(1U, num_raw);
143
Tao Baoc0e1c462017-02-01 10:20:10 -0800144 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800145}
146
147TEST(ImgdiffTest, zip_mode_smoke_store) {
148 // Construct src and tgt zip files.
149 TemporaryFile src_file;
150 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
151 ZipWriter src_writer(src_file_ptr);
152 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", 0)); // Store mode.
153 const std::string src_content("abcdefg");
154 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
155 ASSERT_EQ(0, src_writer.FinishEntry());
156 ASSERT_EQ(0, src_writer.Finish());
157 ASSERT_EQ(0, fclose(src_file_ptr));
158
159 TemporaryFile tgt_file;
160 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
161 ZipWriter tgt_writer(tgt_file_ptr);
162 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", 0)); // Store mode.
163 const std::string tgt_content("abcdefgxyz");
164 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
165 ASSERT_EQ(0, tgt_writer.FinishEntry());
166 ASSERT_EQ(0, tgt_writer.Finish());
167 ASSERT_EQ(0, fclose(tgt_file_ptr));
168
169 // Compute patch.
170 TemporaryFile patch_file;
171 std::vector<const char*> args = {
172 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
173 };
174 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
175
176 // Verify.
177 std::string tgt;
178 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
179 std::string src;
180 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
181 std::string patch;
182 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
183
184 // Expect one CHUNK_RAW entry.
185 size_t num_normal;
186 size_t num_raw;
187 size_t num_deflate;
188 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
189 ASSERT_EQ(0U, num_normal);
190 ASSERT_EQ(0U, num_deflate);
191 ASSERT_EQ(1U, num_raw);
192
Tao Baoc0e1c462017-02-01 10:20:10 -0800193 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800194}
195
196TEST(ImgdiffTest, zip_mode_smoke_compressed) {
197 // Construct src and tgt zip files.
198 TemporaryFile src_file;
199 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
200 ZipWriter src_writer(src_file_ptr);
201 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
202 const std::string src_content("abcdefg");
203 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
204 ASSERT_EQ(0, src_writer.FinishEntry());
205 ASSERT_EQ(0, src_writer.Finish());
206 ASSERT_EQ(0, fclose(src_file_ptr));
207
208 TemporaryFile tgt_file;
209 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
210 ZipWriter tgt_writer(tgt_file_ptr);
211 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
212 const std::string tgt_content("abcdefgxyz");
213 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
214 ASSERT_EQ(0, tgt_writer.FinishEntry());
215 ASSERT_EQ(0, tgt_writer.Finish());
216 ASSERT_EQ(0, fclose(tgt_file_ptr));
217
218 // Compute patch.
219 TemporaryFile patch_file;
220 std::vector<const char*> args = {
221 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
222 };
223 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
224
225 // Verify.
226 std::string tgt;
227 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
228 std::string src;
229 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
230 std::string patch;
231 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
232
233 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
234 size_t num_normal;
235 size_t num_raw;
236 size_t num_deflate;
237 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
238 ASSERT_EQ(0U, num_normal);
239 ASSERT_EQ(1U, num_deflate);
240 ASSERT_EQ(2U, num_raw);
241
Tao Baoc0e1c462017-02-01 10:20:10 -0800242 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800243}
244
Tianjie Xu1ea84d62017-02-22 18:23:58 -0800245TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) {
246 // Construct src and tgt zip files.
247 TemporaryFile src_file;
248 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
249 ZipWriter src_writer(src_file_ptr);
250 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
251 const std::string src_content("abcdefg");
252 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size()));
253 ASSERT_EQ(0, src_writer.FinishEntry());
254 ASSERT_EQ(0, src_writer.Finish());
255 ASSERT_EQ(0, fclose(src_file_ptr));
256
257 TemporaryFile tgt_file;
258 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
259 ZipWriter tgt_writer(tgt_file_ptr);
260 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
261 const std::string tgt_content("abcdefgxyz");
262 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size()));
263 ASSERT_EQ(0, tgt_writer.FinishEntry());
264 ASSERT_EQ(0, tgt_writer.Finish());
265 // Add trailing zeros to the target zip file.
266 std::vector<uint8_t> zeros(10);
267 ASSERT_EQ(zeros.size(), fwrite(zeros.data(), sizeof(uint8_t), zeros.size(), tgt_file_ptr));
268 ASSERT_EQ(0, fclose(tgt_file_ptr));
269
270 // Compute patch.
271 TemporaryFile patch_file;
272 std::vector<const char*> args = {
273 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path,
274 };
275 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
276
277 // Verify.
278 std::string tgt;
279 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
280 std::string src;
281 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src));
282 std::string patch;
283 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
284
285 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
286 size_t num_normal;
287 size_t num_raw;
288 size_t num_deflate;
289 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
290 ASSERT_EQ(0U, num_normal);
291 ASSERT_EQ(1U, num_deflate);
292 ASSERT_EQ(2U, num_raw);
293
Tao Baoc0e1c462017-02-01 10:20:10 -0800294 verify_patched_image(src, patch, tgt);
Tianjie Xu1ea84d62017-02-22 18:23:58 -0800295}
296
Tao Bao97555da2016-12-15 10:15:06 -0800297TEST(ImgdiffTest, image_mode_simple) {
298 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
299 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
300 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
301 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
302 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
303 '\x00', '\x00', '\x00' };
304 const std::string src(src_data.cbegin(), src_data.cend());
305 TemporaryFile src_file;
306 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
307
308 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
309 const std::vector<char> tgt_data = {
310 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
311 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
312 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
313 };
314 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
315 TemporaryFile tgt_file;
316 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
317
318 TemporaryFile patch_file;
319 std::vector<const char*> args = {
320 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
321 };
322 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
323
324 // Verify.
325 std::string patch;
326 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
327
328 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
329 size_t num_normal;
330 size_t num_raw;
331 size_t num_deflate;
332 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
333 ASSERT_EQ(0U, num_normal);
334 ASSERT_EQ(1U, num_deflate);
335 ASSERT_EQ(2U, num_raw);
336
Tao Baoc0e1c462017-02-01 10:20:10 -0800337 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800338}
339
Tianjie Xu14ebc1e2017-07-05 12:04:07 -0700340TEST(ImgdiffTest, image_mode_bad_gzip) {
341 // Modify the uncompressed length in the gzip footer.
342 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
343 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
344 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
345 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
346 '\xff', '\xff', '\xff' };
347 const std::string src(src_data.cbegin(), src_data.cend());
348 TemporaryFile src_file;
349 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
350
351 // Modify the uncompressed length in the gzip footer.
352 const std::vector<char> tgt_data = {
353 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
354 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
355 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\xff', '\xff', '\xff'
356 };
357 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
358 TemporaryFile tgt_file;
359 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
360
361 TemporaryFile patch_file;
362 std::vector<const char*> args = {
363 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
364 };
365 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
366
367 // Verify.
368 std::string patch;
369 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
370 verify_patched_image(src, patch, tgt);
371}
372
Tao Bao97555da2016-12-15 10:15:06 -0800373TEST(ImgdiffTest, image_mode_different_num_chunks) {
374 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd) + gzipped "test".
375 const std::vector<char> src_data = {
376 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\x1f', '\x8b', '\x08',
377 '\x00', '\xc4', '\x1e', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', '\x02',
378 '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', '\x00', '\x00', '\x00', '\x1f', '\x8b',
379 '\x08', '\x00', '\xb2', '\x3a', '\x53', '\x58', '\x00', '\x03', '\x2b', '\x49', '\x2d',
380 '\x2e', '\x01', '\x00', '\x0c', '\x7e', '\x7f', '\xd8', '\x04', '\x00', '\x00', '\x00'
381 };
382 const std::string src(src_data.cbegin(), src_data.cend());
383 TemporaryFile src_file;
384 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
385
386 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
387 const std::vector<char> tgt_data = {
388 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
389 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
390 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
391 };
392 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
393 TemporaryFile tgt_file;
394 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
395
396 TemporaryFile patch_file;
397 std::vector<const char*> args = {
398 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
399 };
400 ASSERT_EQ(1, imgdiff(args.size(), args.data()));
401}
402
403TEST(ImgdiffTest, image_mode_merge_chunks) {
404 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
405 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
406 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
407 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
408 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
409 '\x00', '\x00', '\x00' };
410 const std::string src(src_data.cbegin(), src_data.cend());
411 TemporaryFile src_file;
412 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
413
414 // tgt: gzipped "xyz" + "abcdefgh".
415 const std::vector<char> tgt_data = {
416 '\x1f', '\x8b', '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8',
417 '\xa8', '\xac', '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00',
418 '\x00', '\x00', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'
419 };
420 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
421 TemporaryFile tgt_file;
422 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
423
424 // Since a gzipped entry will become CHUNK_RAW (header) + CHUNK_DEFLATE (data) +
425 // CHUNK_RAW (footer), they both should contain the same chunk types after merging.
426
427 TemporaryFile patch_file;
428 std::vector<const char*> args = {
429 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
430 };
431 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
432
433 // Verify.
434 std::string patch;
435 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
436
437 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer).
438 size_t num_normal;
439 size_t num_raw;
440 size_t num_deflate;
441 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
442 ASSERT_EQ(0U, num_normal);
443 ASSERT_EQ(1U, num_deflate);
444 ASSERT_EQ(2U, num_raw);
445
Tao Baoc0e1c462017-02-01 10:20:10 -0800446 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800447}
448
449TEST(ImgdiffTest, image_mode_spurious_magic) {
450 // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
451 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
452 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
453 '\x53', '\x58', 't', 'e', 's', 't' };
454 const std::string src(src_data.cbegin(), src_data.cend());
455 TemporaryFile src_file;
456 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
457
458 // tgt: "abcdefgxyz".
459 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
460 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
461 TemporaryFile tgt_file;
462 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
463
464 TemporaryFile patch_file;
465 std::vector<const char*> args = {
466 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
467 };
468 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
469
470 // Verify.
471 std::string patch;
472 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
473
474 // Expect one CHUNK_RAW (header) entry.
475 size_t num_normal;
476 size_t num_raw;
477 size_t num_deflate;
478 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
479 ASSERT_EQ(0U, num_normal);
480 ASSERT_EQ(0U, num_deflate);
481 ASSERT_EQ(1U, num_raw);
482
Tao Baoc0e1c462017-02-01 10:20:10 -0800483 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800484}
485
Tao Baod37ce8f2016-12-17 17:10:04 -0800486TEST(ImgdiffTest, image_mode_short_input1) {
487 // src: "abcdefgh" + '0x1f8b0b'.
488 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
489 'g', 'h', '\x1f', '\x8b', '\x08' };
490 const std::string src(src_data.cbegin(), src_data.cend());
491 TemporaryFile src_file;
492 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
493
494 // tgt: "abcdefgxyz".
495 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
496 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
497 TemporaryFile tgt_file;
498 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
499
500 TemporaryFile patch_file;
501 std::vector<const char*> args = {
502 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
503 };
504 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
505
506 // Verify.
507 std::string patch;
508 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
509
510 // Expect one CHUNK_RAW (header) entry.
511 size_t num_normal;
512 size_t num_raw;
513 size_t num_deflate;
514 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
515 ASSERT_EQ(0U, num_normal);
516 ASSERT_EQ(0U, num_deflate);
517 ASSERT_EQ(1U, num_raw);
518
Tao Baoc0e1c462017-02-01 10:20:10 -0800519 verify_patched_image(src, patch, tgt);
Tao Baod37ce8f2016-12-17 17:10:04 -0800520}
521
522TEST(ImgdiffTest, image_mode_short_input2) {
523 // src: "abcdefgh" + '0x1f8b0b00'.
524 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f',
525 'g', 'h', '\x1f', '\x8b', '\x08', '\x00' };
526 const std::string src(src_data.cbegin(), src_data.cend());
527 TemporaryFile src_file;
528 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
529
530 // tgt: "abcdefgxyz".
531 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
532 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
533 TemporaryFile tgt_file;
534 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
535
536 TemporaryFile patch_file;
537 std::vector<const char*> args = {
538 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
539 };
540 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
541
542 // Verify.
543 std::string patch;
544 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
545
546 // Expect one CHUNK_RAW (header) entry.
547 size_t num_normal;
548 size_t num_raw;
549 size_t num_deflate;
550 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
551 ASSERT_EQ(0U, num_normal);
552 ASSERT_EQ(0U, num_deflate);
553 ASSERT_EQ(1U, num_raw);
554
Tao Baoc0e1c462017-02-01 10:20:10 -0800555 verify_patched_image(src, patch, tgt);
Tao Baod37ce8f2016-12-17 17:10:04 -0800556}
557
Tao Bao97555da2016-12-15 10:15:06 -0800558TEST(ImgdiffTest, image_mode_single_entry_long) {
559 // src: "abcdefgh" + '0x1f8b0b00' + some bytes.
560 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
561 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
562 '\x53', '\x58', 't', 'e', 's', 't' };
563 const std::string src(src_data.cbegin(), src_data.cend());
564 TemporaryFile src_file;
565 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
566
567 // tgt: "abcdefgxyz" + 200 bytes.
568 std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' };
569 tgt_data.resize(tgt_data.size() + 200);
570
571 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
572 TemporaryFile tgt_file;
573 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
574
575 TemporaryFile patch_file;
576 std::vector<const char*> args = {
577 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
578 };
579 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
580
581 // Verify.
582 std::string patch;
583 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
584
585 // Expect one CHUNK_NORMAL entry, since it's exceeding the 160-byte limit for RAW.
586 size_t num_normal;
587 size_t num_raw;
588 size_t num_deflate;
589 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate);
590 ASSERT_EQ(1U, num_normal);
591 ASSERT_EQ(0U, num_deflate);
592 ASSERT_EQ(0U, num_raw);
593
Tao Baoc0e1c462017-02-01 10:20:10 -0800594 verify_patched_image(src, patch, tgt);
Tao Bao97555da2016-12-15 10:15:06 -0800595}
Tianjie Xuce5fa5e2017-05-15 12:32:33 -0700596
597TEST(ImgpatchTest, image_mode_patch_corruption) {
598 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd).
599 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',
600 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e',
601 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac',
602 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03',
603 '\x00', '\x00', '\x00' };
604 const std::string src(src_data.cbegin(), src_data.cend());
605 TemporaryFile src_file;
606 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path));
607
608 // tgt: "abcdefgxyz" + gzipped "xxyyzz".
609 const std::vector<char> tgt_data = {
610 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b',
611 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac',
612 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00'
613 };
614 const std::string tgt(tgt_data.cbegin(), tgt_data.cend());
615 TemporaryFile tgt_file;
616 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path));
617
618 TemporaryFile patch_file;
619 std::vector<const char*> args = {
620 "imgdiff", src_file.path, tgt_file.path, patch_file.path,
621 };
622 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
623
624 // Verify.
625 std::string patch;
626 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch));
627 verify_patched_image(src, patch, tgt);
628
629 // Corrupt the end of the patch and expect the ApplyImagePatch to fail.
630 patch.insert(patch.end() - 10, 10, '0');
631 ASSERT_EQ(-1, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
632 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
633 [](const unsigned char* /*data*/, size_t len) { return len; }));
634}
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700635
636static void construct_store_entry(const std::vector<std::tuple<std::string, size_t, char>>& info,
637 ZipWriter* writer) {
638 for (auto& t : info) {
639 // Create t(1) blocks of t(2), and write the data to t(0)
640 ASSERT_EQ(0, writer->StartEntry(std::get<0>(t).c_str(), 0));
641 const std::string content(std::get<1>(t) * 4096, std::get<2>(t));
642 ASSERT_EQ(0, writer->WriteBytes(content.data(), content.size()));
643 ASSERT_EQ(0, writer->FinishEntry());
644 }
645}
646
647static void construct_deflate_entry(const std::vector<std::tuple<std::string, size_t, size_t>>& info,
648 ZipWriter* writer, const std::string& data) {
649 for (auto& t : info) {
650 // t(0): entry_name; t(1): block offset; t(2) length in blocks.
651 ASSERT_EQ(0, writer->StartEntry(std::get<0>(t).c_str(), ZipWriter::kCompress));
652 ASSERT_EQ(0, writer->WriteBytes(data.data() + std::get<1>(t) * 4096, std::get<2>(t) * 4096));
653 ASSERT_EQ(0, writer->FinishEntry());
654 }
655}
656
657// Look for the generated source and patch pieces in the debug_dir and generate the target on
658// each pair. Concatenate the split target and match against the orignal one.
659static void GenerateAndCheckSplitTarget(const std::string& debug_dir, size_t count,
660 const std::string& tgt) {
661 std::string patched;
662 for (size_t i = 0; i < count; i++) {
663 std::string split_src_path = android::base::StringPrintf("%s/src-%zu", debug_dir.c_str(), i);
664 std::string split_patch_path = android::base::StringPrintf("%s/patch-%zu", debug_dir.c_str(), i);
665
666 std::string split_src;
667 std::string split_patch;
668 ASSERT_TRUE(android::base::ReadFileToString(split_src_path, &split_src));
669 ASSERT_TRUE(android::base::ReadFileToString(split_patch_path, &split_patch));
670
671 std::string split_tgt;
672 GenerateTarget(split_src, split_patch, &split_tgt);
673 patched += split_tgt;
674 }
675
676 // Verify we can get back the original target image.
677 ASSERT_EQ(tgt, patched);
678}
679
680std::vector<ImageChunk> ConstructImageChunks(
681 const std::vector<uint8_t>& content, const std::vector<std::tuple<std::string, size_t>>& info) {
682 std::vector<ImageChunk> chunks;
683 size_t start = 0;
684 for (const auto& t : info) {
685 size_t length = std::get<1>(t);
686 chunks.emplace_back(CHUNK_NORMAL, start, &content, length, std::get<0>(t));
687 start += length;
688 }
689
690 return chunks;
691}
692
693TEST(ImgdiffTest, zip_mode_split_image_smoke) {
694 std::vector<uint8_t> content;
695 content.reserve(4096 * 50);
696 uint8_t n = 0;
697 generate_n(back_inserter(content), 4096 * 50, [&n]() { return n++ / 4096; });
698
699 ZipModeImage tgt_image(false, 4096 * 10);
700 std::vector<ImageChunk> tgt_chunks = ConstructImageChunks(content, { { "a", 100 },
701 { "b", 4096 * 2 },
702 { "c", 4096 * 3 },
703 { "d", 300 },
704 { "e-0", 4096 * 10 },
705 { "e-1", 4096 * 5 },
706 { "CD", 200 } });
707 tgt_image.Initialize(std::move(tgt_chunks),
708 std::vector<uint8_t>(content.begin(), content.begin() + 82520));
709
710 tgt_image.DumpChunks();
711
712 ZipModeImage src_image(true, 4096 * 10);
713 std::vector<ImageChunk> src_chunks = ConstructImageChunks(content, { { "b", 4096 * 3 },
714 { "c-0", 4096 * 10 },
715 { "c-1", 4096 * 2 },
716 { "a", 4096 * 5 },
717 { "e-0", 4096 * 10 },
718 { "e-1", 10000 },
719 { "CD", 5000 } });
720 src_image.Initialize(std::move(src_chunks),
721 std::vector<uint8_t>(content.begin(), content.begin() + 137880));
722
723 std::vector<ZipModeImage> split_tgt_images;
724 std::vector<ZipModeImage> split_src_images;
725 std::vector<SortedRangeSet> split_src_ranges;
726
727 ZipModeImage::SplitZipModeImageWithLimit(tgt_image, src_image, &split_tgt_images,
728 &split_src_images, &split_src_ranges);
729
730 // src_piece 1: a 5 blocks, b 3 blocks
731 // src_piece 2: c-0 10 blocks
732 // src_piece 3: d 0 block, e-0 10 blocks
733 // src_piece 4: e-1 2 blocks; CD 2 blocks
734 ASSERT_EQ(split_tgt_images.size(), split_src_images.size());
735 ASSERT_EQ(static_cast<size_t>(4), split_tgt_images.size());
736
737 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[0].NumOfChunks());
738 ASSERT_EQ(static_cast<size_t>(12288), split_tgt_images[0][0].DataLengthForPatch());
739 ASSERT_EQ("4,0,3,15,20", split_src_ranges[0].ToString());
740
741 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[1].NumOfChunks());
742 ASSERT_EQ(static_cast<size_t>(12288), split_tgt_images[1][0].DataLengthForPatch());
743 ASSERT_EQ("2,3,13", split_src_ranges[1].ToString());
744
745 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[2].NumOfChunks());
746 ASSERT_EQ(static_cast<size_t>(40960), split_tgt_images[2][0].DataLengthForPatch());
747 ASSERT_EQ("2,20,30", split_src_ranges[2].ToString());
748
749 ASSERT_EQ(static_cast<size_t>(1), split_tgt_images[3].NumOfChunks());
750 ASSERT_EQ(static_cast<size_t>(16984), split_tgt_images[3][0].DataLengthForPatch());
751 ASSERT_EQ("2,30,34", split_src_ranges[3].ToString());
752}
753
754TEST(ImgdiffTest, zip_mode_store_large_apk) {
755 // Construct src and tgt zip files with limit = 10 blocks.
756 // src tgt
757 // 12 blocks 'd' 3 blocks 'a'
758 // 8 blocks 'c' 3 blocks 'b'
759 // 3 blocks 'b' 8 blocks 'c' (exceeds limit)
760 // 3 blocks 'a' 12 blocks 'd' (exceeds limit)
761 // 3 blocks 'e'
762 TemporaryFile tgt_file;
763 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
764 ZipWriter tgt_writer(tgt_file_ptr);
765 construct_store_entry(
766 { { "a", 3, 'a' }, { "b", 3, 'b' }, { "c", 8, 'c' }, { "d", 12, 'd' }, { "e", 3, 'e' } },
767 &tgt_writer);
768 ASSERT_EQ(0, tgt_writer.Finish());
769 ASSERT_EQ(0, fclose(tgt_file_ptr));
770
771 TemporaryFile src_file;
772 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
773 ZipWriter src_writer(src_file_ptr);
774 construct_store_entry({ { "d", 12, 'd' }, { "c", 8, 'c' }, { "b", 3, 'b' }, { "a", 3, 'a' } },
775 &src_writer);
776 ASSERT_EQ(0, src_writer.Finish());
777 ASSERT_EQ(0, fclose(src_file_ptr));
778
779 // Compute patch.
780 TemporaryFile patch_file;
Tianjie Xu82582b42017-08-31 18:05:19 -0700781 TemporaryFile split_info_file;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700782 TemporaryDir debug_dir;
Tianjie Xu82582b42017-08-31 18:05:19 -0700783 std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
Tianjie Xu8ba7c452017-09-12 11:13:02 -0700784 std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700785 std::vector<const char*> args = {
Tianjie Xu82582b42017-08-31 18:05:19 -0700786 "imgdiff", "-z", "--block-limit=10", split_info_arg.c_str(), debug_dir_arg.c_str(),
787 src_file.path, tgt_file.path, patch_file.path,
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700788 };
789 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
790
791 std::string tgt;
792 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
793
794 // Expect 4 pieces of patch.(Rougly 3'a',3'b'; 8'c'; 10'd'; 2'd'3'e')
795 GenerateAndCheckSplitTarget(debug_dir.path, 4, tgt);
796}
797
798TEST(ImgdiffTest, zip_mode_deflate_large_apk) {
799 // Generate 50 blocks of random data.
800 std::string random_data;
801 random_data.reserve(4096 * 50);
802 generate_n(back_inserter(random_data), 4096 * 50, []() { return rand() % 256; });
803
804 // Construct src and tgt zip files with limit = 10 blocks.
805 // src tgt
806 // 22 blocks, "d" 4 blocks, "a"
807 // 5 blocks, "b" 4 blocks, "b"
808 // 3 blocks, "a" 7 blocks, "c" (exceeds limit)
809 // 8 blocks, "c" 20 blocks, "d" (exceeds limit)
810 // 1 block, "f" 2 blocks, "e"
811 TemporaryFile tgt_file;
812 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
813 ZipWriter tgt_writer(tgt_file_ptr);
814
815 construct_deflate_entry(
816 { { "a", 0, 4 }, { "b", 5, 4 }, { "c", 12, 8 }, { "d", 21, 20 }, { "e", 45, 2 },
817 { "f", 48, 1 } }, &tgt_writer, random_data);
818
819 ASSERT_EQ(0, tgt_writer.Finish());
820 ASSERT_EQ(0, fclose(tgt_file_ptr));
821
822 TemporaryFile src_file;
823 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
824 ZipWriter src_writer(src_file_ptr);
825
826 construct_deflate_entry(
827 { { "d", 21, 22 }, { "b", 5, 5 }, { "a", 0, 3 }, { "g", 9, 1 }, { "c", 11, 8 },
828 { "f", 45, 1 } }, &src_writer, random_data);
829
830 ASSERT_EQ(0, src_writer.Finish());
831 ASSERT_EQ(0, fclose(src_file_ptr));
832
833 ZipModeImage src_image(true, 10 * 4096);
834 ZipModeImage tgt_image(false, 10 * 4096);
835 ASSERT_TRUE(src_image.Initialize(src_file.path));
836 ASSERT_TRUE(tgt_image.Initialize(tgt_file.path));
837 ASSERT_TRUE(ZipModeImage::CheckAndProcessChunks(&tgt_image, &src_image));
838
839 src_image.DumpChunks();
840 tgt_image.DumpChunks();
841
842 std::vector<ZipModeImage> split_tgt_images;
843 std::vector<ZipModeImage> split_src_images;
844 std::vector<SortedRangeSet> split_src_ranges;
845 ZipModeImage::SplitZipModeImageWithLimit(tgt_image, src_image, &split_tgt_images,
846 &split_src_images, &split_src_ranges);
847
848 // src_piece 1: a 3 blocks, b 5 blocks
849 // src_piece 2: c 8 blocks
850 // src_piece 3: d-0 10 block
851 // src_piece 4: d-1 10 blocks
852 // src_piece 5: e 1 block, CD
853 ASSERT_EQ(split_tgt_images.size(), split_src_images.size());
854 ASSERT_EQ(static_cast<size_t>(5), split_tgt_images.size());
855
856 ASSERT_EQ(static_cast<size_t>(2), split_src_images[0].NumOfChunks());
857 ASSERT_EQ("a", split_src_images[0][0].GetEntryName());
858 ASSERT_EQ("b", split_src_images[0][1].GetEntryName());
859
860 ASSERT_EQ(static_cast<size_t>(1), split_src_images[1].NumOfChunks());
861 ASSERT_EQ("c", split_src_images[1][0].GetEntryName());
862
863 ASSERT_EQ(static_cast<size_t>(0), split_src_images[2].NumOfChunks());
864 ASSERT_EQ(static_cast<size_t>(0), split_src_images[3].NumOfChunks());
865 ASSERT_EQ(static_cast<size_t>(0), split_src_images[4].NumOfChunks());
866
867 // Compute patch.
868 TemporaryFile patch_file;
Tianjie Xu82582b42017-08-31 18:05:19 -0700869 TemporaryFile split_info_file;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700870 TemporaryDir debug_dir;
871 ASSERT_TRUE(ZipModeImage::GeneratePatches(split_tgt_images, split_src_images, split_src_ranges,
Tianjie Xu82582b42017-08-31 18:05:19 -0700872 patch_file.path, split_info_file.path, debug_dir.path));
873
874 // Verify the content of split info.
875 // Expect 5 pieces of patch. ["a","b"; "c"; "d-0"; "d-1"; "e"]
876 std::string split_info_string;
877 android::base::ReadFileToString(split_info_file.path, &split_info_string);
878 std::vector<std::string> info_list =
879 android::base::Split(android::base::Trim(split_info_string), "\n");
880
881 ASSERT_EQ(static_cast<size_t>(7), info_list.size());
882 ASSERT_EQ("2", android::base::Trim(info_list[0]));
883 ASSERT_EQ("5", android::base::Trim(info_list[1]));
884
885 std::vector<size_t> patch_size;
886 for (size_t i = 0; i < 5; i++) {
887 struct stat st = {};
888 std::string path = android::base::StringPrintf("%s/patch-%zu", debug_dir.path, i);
889 ASSERT_EQ(0, stat(path.c_str(), &st));
890 patch_size.push_back(st.st_size);
891 }
892
893 ASSERT_EQ(std::to_string(patch_size[0]) + " 36864 2,22,31", android::base::Trim(info_list[2]));
894 ASSERT_EQ(std::to_string(patch_size[1]) + " 32768 2,31,40", android::base::Trim(info_list[3]));
895 ASSERT_EQ(std::to_string(patch_size[2]) + " 40960 2,0,11", android::base::Trim(info_list[4]));
896 ASSERT_EQ(std::to_string(patch_size[3]) + " 40960 2,11,21", android::base::Trim(info_list[5]));
897 ASSERT_EQ(std::to_string(patch_size[4]) + " 8833 4,21,22,40,41",
898 android::base::Trim(info_list[6]));
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700899
900 std::string tgt;
901 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
902
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700903 GenerateAndCheckSplitTarget(debug_dir.path, 5, tgt);
904}
905
906TEST(ImgdiffTest, zip_mode_no_match_source) {
907 // Generate 20 blocks of random data.
908 std::string random_data;
909 random_data.reserve(4096 * 20);
910 generate_n(back_inserter(random_data), 4096 * 20, []() { return rand() % 256; });
911
912 TemporaryFile tgt_file;
913 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
914 ZipWriter tgt_writer(tgt_file_ptr);
915
916 construct_deflate_entry({ { "a", 0, 4 }, { "b", 5, 5 }, { "c", 11, 5 } }, &tgt_writer,
917 random_data);
918
919 ASSERT_EQ(0, tgt_writer.Finish());
920 ASSERT_EQ(0, fclose(tgt_file_ptr));
921
922 // We don't have a matching source entry.
923 TemporaryFile src_file;
924 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
925 ZipWriter src_writer(src_file_ptr);
926 construct_store_entry({ { "d", 1, 'd' } }, &src_writer);
927 ASSERT_EQ(0, src_writer.Finish());
928 ASSERT_EQ(0, fclose(src_file_ptr));
929
930 // Compute patch.
931 TemporaryFile patch_file;
Tianjie Xu82582b42017-08-31 18:05:19 -0700932 TemporaryFile split_info_file;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700933 TemporaryDir debug_dir;
Tianjie Xu82582b42017-08-31 18:05:19 -0700934 std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
Tianjie Xu8ba7c452017-09-12 11:13:02 -0700935 std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700936 std::vector<const char*> args = {
Tianjie Xu82582b42017-08-31 18:05:19 -0700937 "imgdiff", "-z", "--block-limit=10", debug_dir_arg.c_str(), split_info_arg.c_str(),
938 src_file.path, tgt_file.path, patch_file.path,
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700939 };
940 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
941
942 std::string tgt;
943 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
944
945 // Expect 1 pieces of patch due to no matching source entry.
946 GenerateAndCheckSplitTarget(debug_dir.path, 1, tgt);
947}
948
949TEST(ImgdiffTest, zip_mode_large_enough_limit) {
950 // Generate 20 blocks of random data.
951 std::string random_data;
952 random_data.reserve(4096 * 20);
953 generate_n(back_inserter(random_data), 4096 * 20, []() { return rand() % 256; });
954
955 TemporaryFile tgt_file;
956 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
957 ZipWriter tgt_writer(tgt_file_ptr);
958
959 construct_deflate_entry({ { "a", 0, 10 }, { "b", 10, 5 } }, &tgt_writer, random_data);
960
961 ASSERT_EQ(0, tgt_writer.Finish());
962 ASSERT_EQ(0, fclose(tgt_file_ptr));
963
964 // Construct 10 blocks of source.
965 TemporaryFile src_file;
966 FILE* src_file_ptr = fdopen(src_file.fd, "wb");
967 ZipWriter src_writer(src_file_ptr);
968 construct_deflate_entry({ { "a", 1, 10 } }, &src_writer, random_data);
969 ASSERT_EQ(0, src_writer.Finish());
970 ASSERT_EQ(0, fclose(src_file_ptr));
971
972 // Compute patch with a limit of 20 blocks.
973 TemporaryFile patch_file;
Tianjie Xu82582b42017-08-31 18:05:19 -0700974 TemporaryFile split_info_file;
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700975 TemporaryDir debug_dir;
Tianjie Xu82582b42017-08-31 18:05:19 -0700976 std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
Tianjie Xu8ba7c452017-09-12 11:13:02 -0700977 std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700978 std::vector<const char*> args = {
Tianjie Xu82582b42017-08-31 18:05:19 -0700979 "imgdiff", "-z", "--block-limit=20", split_info_arg.c_str(), debug_dir_arg.c_str(),
980 src_file.path, tgt_file.path, patch_file.path,
Tianjie Xu2903cdd2017-08-18 18:15:47 -0700981 };
982 ASSERT_EQ(0, imgdiff(args.size(), args.data()));
983
984 std::string tgt;
985 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
986
987 // Expect 1 pieces of patch since limit is larger than the zip file size.
988 GenerateAndCheckSplitTarget(debug_dir.path, 1, tgt);
989}