blob: 908a9f5f5ca3aaca0dd97b2e1d227f5e30925e97 [file] [log] [blame]
Jed Estepb8a693b2016-03-09 17:51:34 -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 agree to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <fcntl.h>
18#include <gtest/gtest.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <sys/stat.h>
22#include <sys/statvfs.h>
23#include <sys/types.h>
24#include <time.h>
25
26#include <string>
27
28#include <android-base/file.h>
29#include <android-base/stringprintf.h>
30#include <android-base/test_utils.h>
31
32#include "applypatch/applypatch.h"
33#include "common/test_constants.h"
34#include "openssl/sha.h"
35#include "print_sha1.h"
36
37static const std::string DATA_PATH = getenv("ANDROID_DATA");
38static const std::string TESTDATA_PATH = "/recovery/testdata";
39static const std::string WORK_FS = "/data";
40
41static std::string sha1sum(const std::string& fname) {
42 uint8_t digest[SHA_DIGEST_LENGTH];
43 std::string data;
44 android::base::ReadFileToString(fname, &data);
45
46 SHA1((const uint8_t*)data.c_str(), data.size(), digest);
47 return print_sha1(digest);
48}
49
50static void mangle_file(const std::string& fname) {
51 FILE* fh = fopen(&fname[0], "w");
52 int r;
53 for (int i=0; i < 1024; i++) {
54 r = rand();
55 fwrite(&r, sizeof(short), 1, fh);
56 }
57 fclose(fh);
58}
59
60static bool file_cmp(std::string& f1, std::string& f2) {
61 std::string c1;
62 std::string c2;
63 android::base::ReadFileToString(f1, &c1);
64 android::base::ReadFileToString(f2, &c2);
65 return c1 == c2;
66}
67
Chih-Hung Hsieh8b238112016-08-26 14:54:29 -070068static std::string from_testdata_base(const std::string& fname) {
Jed Estepb8a693b2016-03-09 17:51:34 -080069 return android::base::StringPrintf("%s%s%s/%s",
70 &DATA_PATH[0],
71 &NATIVE_TEST_PATH[0],
72 &TESTDATA_PATH[0],
73 &fname[0]);
74}
75
76class ApplyPatchTest : public ::testing::Test {
77 public:
78 static void SetUpTestCase() {
79 // set up files
80 old_file = from_testdata_base("old.file");
81 new_file = from_testdata_base("new.file");
82 patch_file = from_testdata_base("patch.bsdiff");
83 rand_file = "/cache/applypatch_test_rand.file";
84 cache_file = "/cache/saved.file";
85
86 // write stuff to rand_file
87 android::base::WriteStringToFile("hello", rand_file);
88
89 // set up SHA constants
90 old_sha1 = sha1sum(old_file);
91 new_sha1 = sha1sum(new_file);
92 srand(time(NULL));
93 bad_sha1_a = android::base::StringPrintf("%040x", rand());
94 bad_sha1_b = android::base::StringPrintf("%040x", rand());
95
96 struct stat st;
97 stat(&new_file[0], &st);
98 new_size = st.st_size;
99 }
100
101 static std::string old_file;
102 static std::string new_file;
103 static std::string rand_file;
104 static std::string cache_file;
105 static std::string patch_file;
106
107 static std::string old_sha1;
108 static std::string new_sha1;
109 static std::string bad_sha1_a;
110 static std::string bad_sha1_b;
111
112 static size_t new_size;
113};
114
115std::string ApplyPatchTest::old_file;
116std::string ApplyPatchTest::new_file;
117
118static void cp(std::string src, std::string tgt) {
119 std::string cmd = android::base::StringPrintf("cp %s %s",
120 &src[0],
121 &tgt[0]);
122 system(&cmd[0]);
123}
124
125static void backup_old() {
126 cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file);
127}
128
129static void restore_old() {
130 cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file);
131}
132
133class ApplyPatchCacheTest : public ApplyPatchTest {
134 public:
135 virtual void SetUp() {
136 backup_old();
137 }
138
139 virtual void TearDown() {
140 restore_old();
141 }
142};
143
144class ApplyPatchFullTest : public ApplyPatchCacheTest {
145 public:
146 static void SetUpTestCase() {
147 ApplyPatchTest::SetUpTestCase();
148 unsigned long free_kb = FreeSpaceForFile(&WORK_FS[0]);
149 ASSERT_GE(free_kb * 1024, new_size * 3 / 2);
150 output_f = new TemporaryFile();
151 output_loc = std::string(output_f->path);
152
153 struct FileContents fc;
154
155 ASSERT_EQ(0, LoadFileContents(&rand_file[0], &fc));
Tianjie Xuaced5d92016-10-12 10:55:04 -0700156 Value* patch1 = new Value(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()));
Jed Estepb8a693b2016-03-09 17:51:34 -0800157 patches.push_back(patch1);
158
159 ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc));
Tianjie Xuaced5d92016-10-12 10:55:04 -0700160 Value* patch2 = new Value(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()));
Jed Estepb8a693b2016-03-09 17:51:34 -0800161 patches.push_back(patch2);
162 }
163 static void TearDownTestCase() {
164 delete output_f;
165 for (auto it = patches.begin(); it != patches.end(); ++it) {
Jed Estepb8a693b2016-03-09 17:51:34 -0800166 delete *it;
167 }
168 patches.clear();
169 }
170
171 static std::vector<Value*> patches;
172 static TemporaryFile* output_f;
173 static std::string output_loc;
174};
175
176class ApplyPatchDoubleCacheTest : public ApplyPatchFullTest {
177 public:
178 virtual void SetUp() {
179 ApplyPatchCacheTest::SetUp();
180 cp(cache_file, "/cache/reallysaved.file");
181 }
182
183 virtual void TearDown() {
184 cp("/cache/reallysaved.file", cache_file);
185 ApplyPatchCacheTest::TearDown();
186 }
187};
188
189std::string ApplyPatchTest::rand_file;
190std::string ApplyPatchTest::patch_file;
191std::string ApplyPatchTest::cache_file;
192std::string ApplyPatchTest::old_sha1;
193std::string ApplyPatchTest::new_sha1;
194std::string ApplyPatchTest::bad_sha1_a;
195std::string ApplyPatchTest::bad_sha1_b;
196
197size_t ApplyPatchTest::new_size;
198
199std::vector<Value*> ApplyPatchFullTest::patches;
200TemporaryFile* ApplyPatchFullTest::output_f;
201std::string ApplyPatchFullTest::output_loc;
202
Tianjie Xua5fd5ab2016-10-18 15:18:22 -0700203TEST_F(ApplyPatchTest, CheckModeSkip) {
204 std::vector<std::string> sha1s;
205 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
206}
207
Jed Estepb8a693b2016-03-09 17:51:34 -0800208TEST_F(ApplyPatchTest, CheckModeSingle) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700209 std::vector<std::string> sha1s = { old_sha1 };
210 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800211}
212
213TEST_F(ApplyPatchTest, CheckModeMultiple) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700214 std::vector<std::string> sha1s = {
215 bad_sha1_a,
216 old_sha1,
217 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800218 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700219 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800220}
221
222TEST_F(ApplyPatchTest, CheckModeFailure) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700223 std::vector<std::string> sha1s = {
224 bad_sha1_a,
225 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800226 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700227 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800228}
229
230TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) {
231 mangle_file(old_file);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700232 std::vector<std::string> sha1s = { old_sha1 };
233 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800234}
235
236TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) {
237 mangle_file(old_file);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700238 std::vector<std::string> sha1s = {
239 bad_sha1_a,
240 old_sha1,
241 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800242 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700243 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800244}
245
246TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) {
247 mangle_file(old_file);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700248 std::vector<std::string> sha1s = {
249 bad_sha1_a,
250 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800251 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700252 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800253}
254
255TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) {
256 unlink(&old_file[0]);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700257 std::vector<std::string> sha1s = { old_sha1 };
258 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800259}
260
261TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) {
262 unlink(&old_file[0]);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700263 std::vector<std::string> sha1s = {
264 bad_sha1_a,
265 old_sha1,
266 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800267 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700268 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800269}
270
271TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) {
272 unlink(&old_file[0]);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700273 std::vector<std::string> sha1s = {
274 bad_sha1_a,
275 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800276 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700277 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800278}
279
280TEST_F(ApplyPatchFullTest, ApplyInPlace) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700281 std::vector<std::string> sha1s = {
282 bad_sha1_a,
283 old_sha1
284 };
Jed Estepb8a693b2016-03-09 17:51:34 -0800285 int ap_result = applypatch(&old_file[0],
286 "-",
287 &new_sha1[0],
288 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700289 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800290 patches.data(),
291 nullptr);
292 ASSERT_EQ(0, ap_result);
293 ASSERT_TRUE(file_cmp(old_file, new_file));
294 // reapply, applypatch is idempotent so it should succeed
295 ap_result = applypatch(&old_file[0],
296 "-",
297 &new_sha1[0],
298 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700299 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800300 patches.data(),
301 nullptr);
302 ASSERT_EQ(0, ap_result);
303 ASSERT_TRUE(file_cmp(old_file, new_file));
304}
305
306TEST_F(ApplyPatchFullTest, ApplyInNewLocation) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700307 std::vector<std::string> sha1s = {
308 bad_sha1_a,
309 old_sha1
310 };
Jed Estepb8a693b2016-03-09 17:51:34 -0800311 int ap_result = applypatch(&old_file[0],
312 &output_loc[0],
313 &new_sha1[0],
314 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700315 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800316 patches.data(),
317 nullptr);
318 ASSERT_EQ(0, ap_result);
319 ASSERT_TRUE(file_cmp(output_loc, new_file));
320 ap_result = applypatch(&old_file[0],
321 &output_loc[0],
322 &new_sha1[0],
323 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700324 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800325 patches.data(),
326 nullptr);
327 ASSERT_EQ(0, ap_result);
328 ASSERT_TRUE(file_cmp(output_loc, new_file));
329}
330
331TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) {
332 mangle_file(old_file);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700333 std::vector<std::string> sha1s = {
334 bad_sha1_a,
335 old_sha1
336 };
Jed Estepb8a693b2016-03-09 17:51:34 -0800337 int ap_result = applypatch(&old_file[0],
338 &output_loc[0],
339 &new_sha1[0],
340 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700341 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800342 patches.data(),
343 nullptr);
344 ASSERT_EQ(0, ap_result);
345 ASSERT_TRUE(file_cmp(output_loc, new_file));
346 ap_result = applypatch(&old_file[0],
347 &output_loc[0],
348 &new_sha1[0],
349 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700350 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800351 patches.data(),
352 nullptr);
353 ASSERT_EQ(0, ap_result);
354 ASSERT_TRUE(file_cmp(output_loc, new_file));
355}
356
357TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) {
358 mangle_file(old_file);
359 mangle_file(cache_file);
360
Tianjie Xuaced5d92016-10-12 10:55:04 -0700361 std::vector<std::string> sha1s = {
362 bad_sha1_a,
363 old_sha1
364 };
Jed Estepb8a693b2016-03-09 17:51:34 -0800365 int ap_result = applypatch(&old_file[0],
366 &output_loc[0],
367 &new_sha1[0],
368 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700369 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800370 patches.data(),
371 nullptr);
372 ASSERT_NE(0, ap_result);
373 ASSERT_FALSE(file_cmp(output_loc, new_file));
374 ap_result = applypatch(&old_file[0],
375 &output_loc[0],
376 &new_sha1[0],
377 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700378 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800379 patches.data(),
380 nullptr);
381 ASSERT_NE(0, ap_result);
382 ASSERT_FALSE(file_cmp(output_loc, new_file));
383}