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