blob: 75f2e10142f3fddfbd0f52b64e363c1258d4b3ef [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
203TEST_F(ApplyPatchTest, CheckModeSingle) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700204 std::vector<std::string> sha1s = { old_sha1 };
205 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800206}
207
208TEST_F(ApplyPatchTest, CheckModeMultiple) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700209 std::vector<std::string> sha1s = {
210 bad_sha1_a,
211 old_sha1,
212 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800213 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700214 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800215}
216
217TEST_F(ApplyPatchTest, CheckModeFailure) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700218 std::vector<std::string> sha1s = {
219 bad_sha1_a,
220 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800221 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700222 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800223}
224
225TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) {
226 mangle_file(old_file);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700227 std::vector<std::string> sha1s = { old_sha1 };
228 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800229}
230
231TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) {
232 mangle_file(old_file);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700233 std::vector<std::string> sha1s = {
234 bad_sha1_a,
235 old_sha1,
236 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800237 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700238 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800239}
240
241TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) {
242 mangle_file(old_file);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700243 std::vector<std::string> sha1s = {
244 bad_sha1_a,
245 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800246 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700247 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800248}
249
250TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) {
251 unlink(&old_file[0]);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700252 std::vector<std::string> sha1s = { old_sha1 };
253 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800254}
255
256TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) {
257 unlink(&old_file[0]);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700258 std::vector<std::string> sha1s = {
259 bad_sha1_a,
260 old_sha1,
261 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800262 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700263 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800264}
265
266TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) {
267 unlink(&old_file[0]);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700268 std::vector<std::string> sha1s = {
269 bad_sha1_a,
270 bad_sha1_b
Jed Estepb8a693b2016-03-09 17:51:34 -0800271 };
Tianjie Xuaced5d92016-10-12 10:55:04 -0700272 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
Jed Estepb8a693b2016-03-09 17:51:34 -0800273}
274
275TEST_F(ApplyPatchFullTest, ApplyInPlace) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700276 std::vector<std::string> sha1s = {
277 bad_sha1_a,
278 old_sha1
279 };
Jed Estepb8a693b2016-03-09 17:51:34 -0800280 int ap_result = applypatch(&old_file[0],
281 "-",
282 &new_sha1[0],
283 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700284 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800285 patches.data(),
286 nullptr);
287 ASSERT_EQ(0, ap_result);
288 ASSERT_TRUE(file_cmp(old_file, new_file));
289 // reapply, applypatch is idempotent so it should succeed
290 ap_result = applypatch(&old_file[0],
291 "-",
292 &new_sha1[0],
293 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700294 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800295 patches.data(),
296 nullptr);
297 ASSERT_EQ(0, ap_result);
298 ASSERT_TRUE(file_cmp(old_file, new_file));
299}
300
301TEST_F(ApplyPatchFullTest, ApplyInNewLocation) {
Tianjie Xuaced5d92016-10-12 10:55:04 -0700302 std::vector<std::string> sha1s = {
303 bad_sha1_a,
304 old_sha1
305 };
Jed Estepb8a693b2016-03-09 17:51:34 -0800306 int ap_result = applypatch(&old_file[0],
307 &output_loc[0],
308 &new_sha1[0],
309 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700310 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800311 patches.data(),
312 nullptr);
313 ASSERT_EQ(0, ap_result);
314 ASSERT_TRUE(file_cmp(output_loc, new_file));
315 ap_result = applypatch(&old_file[0],
316 &output_loc[0],
317 &new_sha1[0],
318 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700319 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800320 patches.data(),
321 nullptr);
322 ASSERT_EQ(0, ap_result);
323 ASSERT_TRUE(file_cmp(output_loc, new_file));
324}
325
326TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) {
327 mangle_file(old_file);
Tianjie Xuaced5d92016-10-12 10:55:04 -0700328 std::vector<std::string> sha1s = {
329 bad_sha1_a,
330 old_sha1
331 };
Jed Estepb8a693b2016-03-09 17:51:34 -0800332 int ap_result = applypatch(&old_file[0],
333 &output_loc[0],
334 &new_sha1[0],
335 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700336 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800337 patches.data(),
338 nullptr);
339 ASSERT_EQ(0, ap_result);
340 ASSERT_TRUE(file_cmp(output_loc, new_file));
341 ap_result = applypatch(&old_file[0],
342 &output_loc[0],
343 &new_sha1[0],
344 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700345 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800346 patches.data(),
347 nullptr);
348 ASSERT_EQ(0, ap_result);
349 ASSERT_TRUE(file_cmp(output_loc, new_file));
350}
351
352TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) {
353 mangle_file(old_file);
354 mangle_file(cache_file);
355
Tianjie Xuaced5d92016-10-12 10:55:04 -0700356 std::vector<std::string> sha1s = {
357 bad_sha1_a,
358 old_sha1
359 };
Jed Estepb8a693b2016-03-09 17:51:34 -0800360 int ap_result = applypatch(&old_file[0],
361 &output_loc[0],
362 &new_sha1[0],
363 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700364 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800365 patches.data(),
366 nullptr);
367 ASSERT_NE(0, ap_result);
368 ASSERT_FALSE(file_cmp(output_loc, new_file));
369 ap_result = applypatch(&old_file[0],
370 &output_loc[0],
371 &new_sha1[0],
372 new_size,
Tianjie Xuaced5d92016-10-12 10:55:04 -0700373 sha1s,
Jed Estepb8a693b2016-03-09 17:51:34 -0800374 patches.data(),
375 nullptr);
376 ASSERT_NE(0, ap_result);
377 ASSERT_FALSE(file_cmp(output_loc, new_file));
378}