blob: b44ddd17cffc9a418c626023a9edb14c301686b7 [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
68static std::string from_testdata_base(const std::string fname) {
69 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));
156 Value* patch1 = new Value();
157 patch1->type = VAL_BLOB;
158 patch1->size = fc.data.size();
159 patch1->data = static_cast<char*>(malloc(fc.data.size()));
160 memcpy(patch1->data, fc.data.data(), fc.data.size());
161 patches.push_back(patch1);
162
163 ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc));
164 Value* patch2 = new Value();
165 patch2->type = VAL_BLOB;
166 patch2->size = fc.st.st_size;
167 patch2->data = static_cast<char*>(malloc(fc.data.size()));
168 memcpy(patch2->data, fc.data.data(), fc.data.size());
169 patches.push_back(patch2);
170 }
171 static void TearDownTestCase() {
172 delete output_f;
173 for (auto it = patches.begin(); it != patches.end(); ++it) {
174 free((*it)->data);
175 delete *it;
176 }
177 patches.clear();
178 }
179
180 static std::vector<Value*> patches;
181 static TemporaryFile* output_f;
182 static std::string output_loc;
183};
184
185class ApplyPatchDoubleCacheTest : public ApplyPatchFullTest {
186 public:
187 virtual void SetUp() {
188 ApplyPatchCacheTest::SetUp();
189 cp(cache_file, "/cache/reallysaved.file");
190 }
191
192 virtual void TearDown() {
193 cp("/cache/reallysaved.file", cache_file);
194 ApplyPatchCacheTest::TearDown();
195 }
196};
197
198std::string ApplyPatchTest::rand_file;
199std::string ApplyPatchTest::patch_file;
200std::string ApplyPatchTest::cache_file;
201std::string ApplyPatchTest::old_sha1;
202std::string ApplyPatchTest::new_sha1;
203std::string ApplyPatchTest::bad_sha1_a;
204std::string ApplyPatchTest::bad_sha1_b;
205
206size_t ApplyPatchTest::new_size;
207
208std::vector<Value*> ApplyPatchFullTest::patches;
209TemporaryFile* ApplyPatchFullTest::output_f;
210std::string ApplyPatchFullTest::output_loc;
211
212TEST_F(ApplyPatchTest, CheckModeSingle) {
213 char* s = &old_sha1[0];
214 ASSERT_EQ(0, applypatch_check(&old_file[0], 1, &s));
215}
216
217TEST_F(ApplyPatchTest, CheckModeMultiple) {
218 char* argv[3] = {
219 &bad_sha1_a[0],
220 &old_sha1[0],
221 &bad_sha1_b[0]
222 };
223 ASSERT_EQ(0, applypatch_check(&old_file[0], 3, argv));
224}
225
226TEST_F(ApplyPatchTest, CheckModeFailure) {
227 char* argv[2] = {
228 &bad_sha1_a[0],
229 &bad_sha1_b[0]
230 };
231 ASSERT_NE(0, applypatch_check(&old_file[0], 2, argv));
232}
233
234TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) {
235 mangle_file(old_file);
236 char* s = &old_sha1[0];
237 ASSERT_EQ(0, applypatch_check(&old_file[0], 1, &s));
238}
239
240TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) {
241 mangle_file(old_file);
242 char* argv[3] = {
243 &bad_sha1_a[0],
244 &old_sha1[0],
245 &bad_sha1_b[0]
246 };
247 ASSERT_EQ(0, applypatch_check(&old_file[0], 3, argv));
248}
249
250TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) {
251 mangle_file(old_file);
252 char* argv[2] = {
253 &bad_sha1_a[0],
254 &bad_sha1_b[0]
255 };
256 ASSERT_NE(0, applypatch_check(&old_file[0], 2, argv));
257}
258
259TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) {
260 unlink(&old_file[0]);
261 char* s = &old_sha1[0];
262 ASSERT_EQ(0, applypatch_check(&old_file[0], 1, &s));
263}
264
265TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) {
266 unlink(&old_file[0]);
267 char* argv[3] = {
268 &bad_sha1_a[0],
269 &old_sha1[0],
270 &bad_sha1_b[0]
271 };
272 ASSERT_EQ(0, applypatch_check(&old_file[0], 3, argv));
273}
274
275TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) {
276 unlink(&old_file[0]);
277 char* argv[2] = {
278 &bad_sha1_a[0],
279 &bad_sha1_b[0]
280 };
281 ASSERT_NE(0, applypatch_check(&old_file[0], 2, argv));
282}
283
284TEST_F(ApplyPatchFullTest, ApplyInPlace) {
285 std::vector<char*> sha1s;
286 sha1s.push_back(&bad_sha1_a[0]);
287 sha1s.push_back(&old_sha1[0]);
288
289 int ap_result = applypatch(&old_file[0],
290 "-",
291 &new_sha1[0],
292 new_size,
293 2,
294 sha1s.data(),
295 patches.data(),
296 nullptr);
297 ASSERT_EQ(0, ap_result);
298 ASSERT_TRUE(file_cmp(old_file, new_file));
299 // reapply, applypatch is idempotent so it should succeed
300 ap_result = applypatch(&old_file[0],
301 "-",
302 &new_sha1[0],
303 new_size,
304 2,
305 sha1s.data(),
306 patches.data(),
307 nullptr);
308 ASSERT_EQ(0, ap_result);
309 ASSERT_TRUE(file_cmp(old_file, new_file));
310}
311
312TEST_F(ApplyPatchFullTest, ApplyInNewLocation) {
313 std::vector<char*> sha1s;
314 sha1s.push_back(&bad_sha1_a[0]);
315 sha1s.push_back(&old_sha1[0]);
316 int ap_result = applypatch(&old_file[0],
317 &output_loc[0],
318 &new_sha1[0],
319 new_size,
320 2,
321 sha1s.data(),
322 patches.data(),
323 nullptr);
324 ASSERT_EQ(0, ap_result);
325 ASSERT_TRUE(file_cmp(output_loc, new_file));
326 ap_result = applypatch(&old_file[0],
327 &output_loc[0],
328 &new_sha1[0],
329 new_size,
330 2,
331 sha1s.data(),
332 patches.data(),
333 nullptr);
334 ASSERT_EQ(0, ap_result);
335 ASSERT_TRUE(file_cmp(output_loc, new_file));
336}
337
338TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) {
339 mangle_file(old_file);
340 std::vector<char*> sha1s;
341 sha1s.push_back(&bad_sha1_a[0]);
342 sha1s.push_back(&old_sha1[0]);
343 int ap_result = applypatch(&old_file[0],
344 &output_loc[0],
345 &new_sha1[0],
346 new_size,
347 2,
348 sha1s.data(),
349 patches.data(),
350 nullptr);
351 ASSERT_EQ(0, ap_result);
352 ASSERT_TRUE(file_cmp(output_loc, new_file));
353 ap_result = applypatch(&old_file[0],
354 &output_loc[0],
355 &new_sha1[0],
356 new_size,
357 2,
358 sha1s.data(),
359 patches.data(),
360 nullptr);
361 ASSERT_EQ(0, ap_result);
362 ASSERT_TRUE(file_cmp(output_loc, new_file));
363}
364
365TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) {
366 mangle_file(old_file);
367 mangle_file(cache_file);
368
369 std::vector<char*> sha1s;
370 sha1s.push_back(&bad_sha1_a[0]);
371 sha1s.push_back(&old_sha1[0]);
372 int ap_result = applypatch(&old_file[0],
373 &output_loc[0],
374 &new_sha1[0],
375 new_size,
376 2,
377 sha1s.data(),
378 patches.data(),
379 nullptr);
380 ASSERT_NE(0, ap_result);
381 ASSERT_FALSE(file_cmp(output_loc, new_file));
382 ap_result = applypatch(&old_file[0],
383 &output_loc[0],
384 &new_sha1[0],
385 new_size,
386 2,
387 sha1s.data(),
388 patches.data(),
389 nullptr);
390 ASSERT_NE(0, ap_result);
391 ASSERT_FALSE(file_cmp(output_loc, new_file));
392}