1 /*
2 * Copyright (C) 2018 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
17 #include <algorithm>
18 #include <string>
19
20 #include <android-base/strings.h>
21 #include <gtest/gtest.h>
22 #include <openssl/sha.h>
23
24 #include "otautil/print_sha1.h"
25 #include "otautil/rangeset.h"
26 #include "private/commands.h"
27
TEST(CommandsTest,ParseType)28 TEST(CommandsTest, ParseType) {
29 ASSERT_EQ(Command::Type::ZERO, Command::ParseType("zero"));
30 ASSERT_EQ(Command::Type::NEW, Command::ParseType("new"));
31 ASSERT_EQ(Command::Type::ERASE, Command::ParseType("erase"));
32 ASSERT_EQ(Command::Type::MOVE, Command::ParseType("move"));
33 ASSERT_EQ(Command::Type::BSDIFF, Command::ParseType("bsdiff"));
34 ASSERT_EQ(Command::Type::IMGDIFF, Command::ParseType("imgdiff"));
35 ASSERT_EQ(Command::Type::STASH, Command::ParseType("stash"));
36 ASSERT_EQ(Command::Type::FREE, Command::ParseType("free"));
37 ASSERT_EQ(Command::Type::COMPUTE_HASH_TREE, Command::ParseType("compute_hash_tree"));
38 }
39
TEST(CommandsTest,ParseType_InvalidCommand)40 TEST(CommandsTest, ParseType_InvalidCommand) {
41 ASSERT_EQ(Command::Type::LAST, Command::ParseType("foo"));
42 ASSERT_EQ(Command::Type::LAST, Command::ParseType("bar"));
43 }
44
TEST(CommandsTest,ParseTargetInfoAndSourceInfo_SourceBlocksOnly)45 TEST(CommandsTest, ParseTargetInfoAndSourceInfo_SourceBlocksOnly) {
46 const std::vector<std::string> tokens{
47 "4,569884,569904,591946,592043",
48 "117",
49 "4,566779,566799,591946,592043",
50 };
51 TargetInfo target;
52 SourceInfo source;
53 std::string err;
54 ASSERT_TRUE(Command::ParseTargetInfoAndSourceInfo(
55 tokens, "1d74d1a60332fd38cf9405f1bae67917888da6cb", &target,
56 "1d74d1a60332fd38cf9405f1bae67917888da6cb", &source, &err));
57 ASSERT_EQ(TargetInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
58 RangeSet({ { 569884, 569904 }, { 591946, 592043 } })),
59 target);
60 ASSERT_EQ(SourceInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
61 RangeSet({ { 566779, 566799 }, { 591946, 592043 } }), {}, {}),
62 source);
63 ASSERT_EQ(117, source.blocks());
64 }
65
TEST(CommandsTest,ParseTargetInfoAndSourceInfo_StashesOnly)66 TEST(CommandsTest, ParseTargetInfoAndSourceInfo_StashesOnly) {
67 const std::vector<std::string> tokens{
68 "2,350729,350731",
69 "2",
70 "-",
71 "6ebcf8cf1f6be0bc49e7d4a864214251925d1d15:2,0,2",
72 };
73 TargetInfo target;
74 SourceInfo source;
75 std::string err;
76 ASSERT_TRUE(Command::ParseTargetInfoAndSourceInfo(
77 tokens, "6ebcf8cf1f6be0bc49e7d4a864214251925d1d15", &target,
78 "1c25ba04d3278d6b65a1b9f17abac78425ec8b8d", &source, &err));
79 ASSERT_EQ(
80 TargetInfo("6ebcf8cf1f6be0bc49e7d4a864214251925d1d15", RangeSet({ { 350729, 350731 } })),
81 target);
82 ASSERT_EQ(
83 SourceInfo("1c25ba04d3278d6b65a1b9f17abac78425ec8b8d", {}, {},
84 {
85 StashInfo("6ebcf8cf1f6be0bc49e7d4a864214251925d1d15", RangeSet({ { 0, 2 } })),
86 }),
87 source);
88 ASSERT_EQ(2, source.blocks());
89 }
90
TEST(CommandsTest,ParseTargetInfoAndSourceInfo_SourceBlocksAndStashes)91 TEST(CommandsTest, ParseTargetInfoAndSourceInfo_SourceBlocksAndStashes) {
92 const std::vector<std::string> tokens{
93 "4,611641,611643,636981,637075",
94 "96",
95 "4,636981,637075,770665,770666",
96 "4,0,94,95,96",
97 "9eedf00d11061549e32503cadf054ec6fbfa7a23:2,94,95",
98 };
99 TargetInfo target;
100 SourceInfo source;
101 std::string err;
102 ASSERT_TRUE(Command::ParseTargetInfoAndSourceInfo(
103 tokens, "4734d1b241eb3d0f993714aaf7d665fae43772b6", &target,
104 "a6cbdf3f416960f02189d3a814ec7e9e95c44a0d", &source, &err));
105 ASSERT_EQ(TargetInfo("4734d1b241eb3d0f993714aaf7d665fae43772b6",
106 RangeSet({ { 611641, 611643 }, { 636981, 637075 } })),
107 target);
108 ASSERT_EQ(SourceInfo(
109 "a6cbdf3f416960f02189d3a814ec7e9e95c44a0d",
110 RangeSet({ { 636981, 637075 }, { 770665, 770666 } }), // source ranges
111 RangeSet({ { 0, 94 }, { 95, 96 } }), // source location
112 {
113 StashInfo("9eedf00d11061549e32503cadf054ec6fbfa7a23", RangeSet({ { 94, 95 } })),
114 }),
115 source);
116 ASSERT_EQ(96, source.blocks());
117 }
118
TEST(CommandsTest,ParseTargetInfoAndSourceInfo_InvalidInput)119 TEST(CommandsTest, ParseTargetInfoAndSourceInfo_InvalidInput) {
120 const std::vector<std::string> tokens{
121 "4,611641,611643,636981,637075",
122 "96",
123 "4,636981,637075,770665,770666",
124 "4,0,94,95,96",
125 "9eedf00d11061549e32503cadf054ec6fbfa7a23:2,94,95",
126 };
127 TargetInfo target;
128 SourceInfo source;
129 std::string err;
130
131 // Mismatching block count.
132 {
133 std::vector<std::string> tokens_copy(tokens);
134 tokens_copy[1] = "97";
135 ASSERT_FALSE(Command::ParseTargetInfoAndSourceInfo(
136 tokens_copy, "1d74d1a60332fd38cf9405f1bae67917888da6cb", &target,
137 "1d74d1a60332fd38cf9405f1bae67917888da6cb", &source, &err));
138 }
139
140 // Excess stashes (causing block count mismatch).
141 {
142 std::vector<std::string> tokens_copy(tokens);
143 tokens_copy.push_back("e145a2f83a33334714ac65e34969c1f115e54a6f:2,0,22");
144 ASSERT_FALSE(Command::ParseTargetInfoAndSourceInfo(
145 tokens_copy, "1d74d1a60332fd38cf9405f1bae67917888da6cb", &target,
146 "1d74d1a60332fd38cf9405f1bae67917888da6cb", &source, &err));
147 }
148
149 // Invalid args.
150 for (size_t i = 0; i < tokens.size(); i++) {
151 TargetInfo target;
152 SourceInfo source;
153 std::string err;
154 ASSERT_FALSE(Command::ParseTargetInfoAndSourceInfo(
155 std::vector<std::string>(tokens.cbegin() + i + 1, tokens.cend()),
156 "1d74d1a60332fd38cf9405f1bae67917888da6cb", &target,
157 "1d74d1a60332fd38cf9405f1bae67917888da6cb", &source, &err));
158 }
159 }
160
TEST(CommandsTest,Parse_EmptyInput)161 TEST(CommandsTest, Parse_EmptyInput) {
162 std::string err;
163 ASSERT_FALSE(Command::Parse("", 0, &err));
164 ASSERT_EQ("invalid type", err);
165 }
166
TEST(CommandsTest,Parse_ABORT_Allowed)167 TEST(CommandsTest, Parse_ABORT_Allowed) {
168 Command::abort_allowed_ = true;
169
170 const std::string input{ "abort" };
171 std::string err;
172 Command command = Command::Parse(input, 0, &err);
173 ASSERT_TRUE(command);
174
175 ASSERT_EQ(TargetInfo(), command.target());
176 ASSERT_EQ(SourceInfo(), command.source());
177 ASSERT_EQ(StashInfo(), command.stash());
178 ASSERT_EQ(PatchInfo(), command.patch());
179 }
180
TEST(CommandsTest,Parse_ABORT_NotAllowed)181 TEST(CommandsTest, Parse_ABORT_NotAllowed) {
182 const std::string input{ "abort" };
183 std::string err;
184 Command command = Command::Parse(input, 0, &err);
185 ASSERT_FALSE(command);
186 }
187
TEST(CommandsTest,Parse_BSDIFF)188 TEST(CommandsTest, Parse_BSDIFF) {
189 const std::string input{
190 "bsdiff 0 148 "
191 "f201a4e04bd3860da6ad47b957ef424d58a58f8c 9d5d223b4bc5c45dbd25a799c4f1a98466731599 "
192 "4,565704,565752,566779,566799 "
193 "68 4,64525,64545,565704,565752"
194 };
195 std::string err;
196 Command command = Command::Parse(input, 1, &err);
197 ASSERT_TRUE(command);
198
199 ASSERT_EQ(Command::Type::BSDIFF, command.type());
200 ASSERT_EQ(1, command.index());
201 ASSERT_EQ(input, command.cmdline());
202
203 ASSERT_EQ(TargetInfo("9d5d223b4bc5c45dbd25a799c4f1a98466731599",
204 RangeSet({ { 565704, 565752 }, { 566779, 566799 } })),
205 command.target());
206 ASSERT_EQ(SourceInfo("f201a4e04bd3860da6ad47b957ef424d58a58f8c",
207 RangeSet({ { 64525, 64545 }, { 565704, 565752 } }), RangeSet(), {}),
208 command.source());
209 ASSERT_EQ(StashInfo(), command.stash());
210 ASSERT_EQ(PatchInfo(0, 148), command.patch());
211 }
212
TEST(CommandsTest,Parse_ERASE)213 TEST(CommandsTest, Parse_ERASE) {
214 const std::string input{ "erase 2,5,10" };
215 std::string err;
216 Command command = Command::Parse(input, 2, &err);
217 ASSERT_TRUE(command);
218
219 ASSERT_EQ(Command::Type::ERASE, command.type());
220 ASSERT_EQ(2, command.index());
221 ASSERT_EQ(input, command.cmdline());
222
223 ASSERT_EQ(TargetInfo("unknown-hash", RangeSet({ { 5, 10 } })), command.target());
224 ASSERT_EQ(SourceInfo(), command.source());
225 ASSERT_EQ(StashInfo(), command.stash());
226 ASSERT_EQ(PatchInfo(), command.patch());
227 }
228
TEST(CommandsTest,Parse_FREE)229 TEST(CommandsTest, Parse_FREE) {
230 const std::string input{ "free hash1" };
231 std::string err;
232 Command command = Command::Parse(input, 3, &err);
233 ASSERT_TRUE(command);
234
235 ASSERT_EQ(Command::Type::FREE, command.type());
236 ASSERT_EQ(3, command.index());
237 ASSERT_EQ(input, command.cmdline());
238
239 ASSERT_EQ(TargetInfo(), command.target());
240 ASSERT_EQ(SourceInfo(), command.source());
241 ASSERT_EQ(StashInfo("hash1", RangeSet()), command.stash());
242 ASSERT_EQ(PatchInfo(), command.patch());
243 }
244
TEST(CommandsTest,Parse_IMGDIFF)245 TEST(CommandsTest, Parse_IMGDIFF) {
246 const std::string input{
247 "imgdiff 29629269 185 "
248 "a6b1c49aed1b57a2aab1ec3e1505b945540cd8db 51978f65035f584a8ef7afa941dacb6d5e862164 "
249 "2,90851,90852 "
250 "1 2,90851,90852"
251 };
252 std::string err;
253 Command command = Command::Parse(input, 4, &err);
254 ASSERT_TRUE(command);
255
256 ASSERT_EQ(Command::Type::IMGDIFF, command.type());
257 ASSERT_EQ(4, command.index());
258 ASSERT_EQ(input, command.cmdline());
259
260 ASSERT_EQ(TargetInfo("51978f65035f584a8ef7afa941dacb6d5e862164", RangeSet({ { 90851, 90852 } })),
261 command.target());
262 ASSERT_EQ(SourceInfo("a6b1c49aed1b57a2aab1ec3e1505b945540cd8db", RangeSet({ { 90851, 90852 } }),
263 RangeSet(), {}),
264 command.source());
265 ASSERT_EQ(StashInfo(), command.stash());
266 ASSERT_EQ(PatchInfo(29629269, 185), command.patch());
267 }
268
TEST(CommandsTest,Parse_MOVE)269 TEST(CommandsTest, Parse_MOVE) {
270 const std::string input{
271 "move 1d74d1a60332fd38cf9405f1bae67917888da6cb "
272 "4,569884,569904,591946,592043 117 4,566779,566799,591946,592043"
273 };
274 std::string err;
275 Command command = Command::Parse(input, 5, &err);
276 ASSERT_TRUE(command);
277
278 ASSERT_EQ(Command::Type::MOVE, command.type());
279 ASSERT_EQ(5, command.index());
280 ASSERT_EQ(input, command.cmdline());
281
282 ASSERT_EQ(TargetInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
283 RangeSet({ { 569884, 569904 }, { 591946, 592043 } })),
284 command.target());
285 ASSERT_EQ(SourceInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
286 RangeSet({ { 566779, 566799 }, { 591946, 592043 } }), RangeSet(), {}),
287 command.source());
288 ASSERT_EQ(StashInfo(), command.stash());
289 ASSERT_EQ(PatchInfo(), command.patch());
290 }
291
TEST(CommandsTest,Parse_NEW)292 TEST(CommandsTest, Parse_NEW) {
293 const std::string input{ "new 4,3,5,10,12" };
294 std::string err;
295 Command command = Command::Parse(input, 6, &err);
296 ASSERT_TRUE(command);
297
298 ASSERT_EQ(Command::Type::NEW, command.type());
299 ASSERT_EQ(6, command.index());
300 ASSERT_EQ(input, command.cmdline());
301
302 ASSERT_EQ(TargetInfo("unknown-hash", RangeSet({ { 3, 5 }, { 10, 12 } })), command.target());
303 ASSERT_EQ(SourceInfo(), command.source());
304 ASSERT_EQ(StashInfo(), command.stash());
305 ASSERT_EQ(PatchInfo(), command.patch());
306 }
307
TEST(CommandsTest,Parse_STASH)308 TEST(CommandsTest, Parse_STASH) {
309 const std::string input{ "stash hash1 2,5,10" };
310 std::string err;
311 Command command = Command::Parse(input, 7, &err);
312 ASSERT_TRUE(command);
313
314 ASSERT_EQ(Command::Type::STASH, command.type());
315 ASSERT_EQ(7, command.index());
316 ASSERT_EQ(input, command.cmdline());
317
318 ASSERT_EQ(TargetInfo(), command.target());
319 ASSERT_EQ(SourceInfo(), command.source());
320 ASSERT_EQ(StashInfo("hash1", RangeSet({ { 5, 10 } })), command.stash());
321 ASSERT_EQ(PatchInfo(), command.patch());
322 }
323
TEST(CommandsTest,Parse_ZERO)324 TEST(CommandsTest, Parse_ZERO) {
325 const std::string input{ "zero 2,1,5" };
326 std::string err;
327 Command command = Command::Parse(input, 8, &err);
328 ASSERT_TRUE(command);
329
330 ASSERT_EQ(Command::Type::ZERO, command.type());
331 ASSERT_EQ(8, command.index());
332 ASSERT_EQ(input, command.cmdline());
333
334 ASSERT_EQ(TargetInfo("unknown-hash", RangeSet({ { 1, 5 } })), command.target());
335 ASSERT_EQ(SourceInfo(), command.source());
336 ASSERT_EQ(StashInfo(), command.stash());
337 ASSERT_EQ(PatchInfo(), command.patch());
338 }
339
TEST(CommandsTest,Parse_COMPUTE_HASH_TREE)340 TEST(CommandsTest, Parse_COMPUTE_HASH_TREE) {
341 const std::string input{ "compute_hash_tree 2,0,1 2,3,4 sha1 unknown-salt unknown-root-hash" };
342 std::string err;
343 Command command = Command::Parse(input, 9, &err);
344 ASSERT_TRUE(command);
345
346 ASSERT_EQ(Command::Type::COMPUTE_HASH_TREE, command.type());
347 ASSERT_EQ(9, command.index());
348 ASSERT_EQ(input, command.cmdline());
349
350 HashTreeInfo expected_info(RangeSet({ { 0, 1 } }), RangeSet({ { 3, 4 } }), "sha1", "unknown-salt",
351 "unknown-root-hash");
352 ASSERT_EQ(expected_info, command.hash_tree_info());
353 ASSERT_EQ(TargetInfo(), command.target());
354 ASSERT_EQ(SourceInfo(), command.source());
355 ASSERT_EQ(StashInfo(), command.stash());
356 ASSERT_EQ(PatchInfo(), command.patch());
357 }
358
TEST(CommandsTest,Parse_InvalidNumberOfArgs)359 TEST(CommandsTest, Parse_InvalidNumberOfArgs) {
360 Command::abort_allowed_ = true;
361
362 // Note that the case of having excess args in BSDIFF, IMGDIFF and MOVE is covered by
363 // ParseTargetInfoAndSourceInfo_InvalidInput.
364 std::vector<std::string> inputs{
365 "abort foo",
366 "bsdiff",
367 "compute_hash_tree, 2,0,1 2,0,1 unknown-algorithm unknown-salt",
368 "erase",
369 "erase 4,3,5,10,12 hash1",
370 "free",
371 "free id1 id2",
372 "imgdiff",
373 "move",
374 "new",
375 "new 4,3,5,10,12 hash1",
376 "stash",
377 "stash id1",
378 "stash id1 4,3,5,10,12 id2",
379 "zero",
380 "zero 4,3,5,10,12 hash2",
381 };
382 for (const auto& input : inputs) {
383 std::string err;
384 ASSERT_FALSE(Command::Parse(input, 0, &err));
385 }
386 }
387
TEST(SourceInfoTest,Overlaps)388 TEST(SourceInfoTest, Overlaps) {
389 ASSERT_TRUE(SourceInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
390 RangeSet({ { 7, 9 }, { 16, 20 } }), {}, {})
391 .Overlaps(TargetInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
392 RangeSet({ { 7, 9 }, { 16, 20 } }))));
393
394 ASSERT_TRUE(SourceInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
395 RangeSet({ { 7, 9 }, { 16, 20 } }), {}, {})
396 .Overlaps(TargetInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
397 RangeSet({ { 4, 7 }, { 16, 23 } }))));
398
399 ASSERT_FALSE(SourceInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
400 RangeSet({ { 7, 9 }, { 16, 20 } }), {}, {})
401 .Overlaps(TargetInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
402 RangeSet({ { 9, 16 } }))));
403 }
404
TEST(SourceInfoTest,Overlaps_EmptySourceOrTarget)405 TEST(SourceInfoTest, Overlaps_EmptySourceOrTarget) {
406 ASSERT_FALSE(SourceInfo().Overlaps(TargetInfo()));
407
408 ASSERT_FALSE(SourceInfo().Overlaps(
409 TargetInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb", RangeSet({ { 7, 9 }, { 16, 20 } }))));
410
411 ASSERT_FALSE(SourceInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
412 RangeSet({ { 7, 9 }, { 16, 20 } }), {}, {})
413 .Overlaps(TargetInfo()));
414 }
415
TEST(SourceInfoTest,Overlaps_WithStashes)416 TEST(SourceInfoTest, Overlaps_WithStashes) {
417 ASSERT_FALSE(SourceInfo("a6cbdf3f416960f02189d3a814ec7e9e95c44a0d",
418 RangeSet({ { 81, 175 }, { 265, 266 } }), // source ranges
419 RangeSet({ { 0, 94 }, { 95, 96 } }), // source location
420 { StashInfo("9eedf00d11061549e32503cadf054ec6fbfa7a23",
421 RangeSet({ { 94, 95 } })) })
422 .Overlaps(TargetInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
423 RangeSet({ { 175, 265 } }))));
424
425 ASSERT_TRUE(SourceInfo("a6cbdf3f416960f02189d3a814ec7e9e95c44a0d",
426 RangeSet({ { 81, 175 }, { 265, 266 } }), // source ranges
427 RangeSet({ { 0, 94 }, { 95, 96 } }), // source location
428 { StashInfo("9eedf00d11061549e32503cadf054ec6fbfa7a23",
429 RangeSet({ { 94, 95 } })) })
430 .Overlaps(TargetInfo("1d74d1a60332fd38cf9405f1bae67917888da6cb",
431 RangeSet({ { 265, 266 } }))));
432 }
433
434 // The block size should be specified by the caller of ReadAll (i.e. from Command instance during
435 // normal run).
436 constexpr size_t kBlockSize = 4096;
437
TEST(SourceInfoTest,ReadAll)438 TEST(SourceInfoTest, ReadAll) {
439 // "2727756cfee3fbfe24bf5650123fd7743d7b3465" is the SHA-1 hex digest of 8192 * 'a'.
440 const SourceInfo source("2727756cfee3fbfe24bf5650123fd7743d7b3465", RangeSet({ { 0, 2 } }), {},
441 {});
442 auto block_reader = [](const RangeSet& src, std::vector<uint8_t>* block_buffer) -> int {
443 std::fill_n(block_buffer->begin(), src.blocks() * kBlockSize, 'a');
444 return 0;
445 };
446 auto stash_reader = [](const std::string&, std::vector<uint8_t>*) -> int { return 0; };
447 std::vector<uint8_t> buffer(source.blocks() * kBlockSize);
448 ASSERT_TRUE(source.ReadAll(&buffer, kBlockSize, block_reader, stash_reader));
449 ASSERT_EQ(source.blocks() * kBlockSize, buffer.size());
450
451 uint8_t digest[SHA_DIGEST_LENGTH];
452 SHA1(buffer.data(), buffer.size(), digest);
453 ASSERT_EQ(source.hash(), print_sha1(digest));
454 }
455
TEST(SourceInfoTest,ReadAll_WithStashes)456 TEST(SourceInfoTest, ReadAll_WithStashes) {
457 const SourceInfo source(
458 // SHA-1 hex digest of 8192 * 'a' + 4096 * 'b'.
459 "ee3ebea26130769c10ad13604712100346d48660", RangeSet({ { 0, 2 } }), RangeSet({ { 0, 2 } }),
460 { StashInfo("1e41f7a59e80c6eb4dc043caae80d273f130bed8", RangeSet({ { 2, 3 } })) });
461 auto block_reader = [](const RangeSet& src, std::vector<uint8_t>* block_buffer) -> int {
462 std::fill_n(block_buffer->begin(), src.blocks() * kBlockSize, 'a');
463 return 0;
464 };
465 auto stash_reader = [](const std::string&, std::vector<uint8_t>* stash_buffer) -> int {
466 std::fill_n(stash_buffer->begin(), kBlockSize, 'b');
467 return 0;
468 };
469 std::vector<uint8_t> buffer(source.blocks() * kBlockSize);
470 ASSERT_TRUE(source.ReadAll(&buffer, kBlockSize, block_reader, stash_reader));
471 ASSERT_EQ(source.blocks() * kBlockSize, buffer.size());
472
473 uint8_t digest[SHA_DIGEST_LENGTH];
474 SHA1(buffer.data(), buffer.size(), digest);
475 ASSERT_EQ(source.hash(), print_sha1(digest));
476 }
477
TEST(SourceInfoTest,ReadAll_BufferTooSmall)478 TEST(SourceInfoTest, ReadAll_BufferTooSmall) {
479 const SourceInfo source("2727756cfee3fbfe24bf5650123fd7743d7b3465", RangeSet({ { 0, 2 } }), {},
480 {});
481 auto block_reader = [](const RangeSet&, std::vector<uint8_t>*) -> int { return 0; };
482 auto stash_reader = [](const std::string&, std::vector<uint8_t>*) -> int { return 0; };
483 std::vector<uint8_t> buffer(source.blocks() * kBlockSize - 1);
484 ASSERT_FALSE(source.ReadAll(&buffer, kBlockSize, block_reader, stash_reader));
485 }
486
TEST(SourceInfoTest,ReadAll_FailingReader)487 TEST(SourceInfoTest, ReadAll_FailingReader) {
488 const SourceInfo source(
489 "ee3ebea26130769c10ad13604712100346d48660", RangeSet({ { 0, 2 } }), RangeSet({ { 0, 2 } }),
490 { StashInfo("1e41f7a59e80c6eb4dc043caae80d273f130bed8", RangeSet({ { 2, 3 } })) });
491 std::vector<uint8_t> buffer(source.blocks() * kBlockSize);
492 auto failing_block_reader = [](const RangeSet&, std::vector<uint8_t>*) -> int { return -1; };
493 auto stash_reader = [](const std::string&, std::vector<uint8_t>*) -> int { return 0; };
494 ASSERT_FALSE(source.ReadAll(&buffer, kBlockSize, failing_block_reader, stash_reader));
495
496 auto block_reader = [](const RangeSet&, std::vector<uint8_t>*) -> int { return 0; };
497 auto failing_stash_reader = [](const std::string&, std::vector<uint8_t>*) -> int { return -1; };
498 ASSERT_FALSE(source.ReadAll(&buffer, kBlockSize, block_reader, failing_stash_reader));
499 }
500
TEST(TransferListTest,Parse)501 TEST(TransferListTest, Parse) {
502 std::vector<std::string> input_lines{
503 "4", // version
504 "2", // total blocks
505 "1", // max stashed entries
506 "1", // max stashed blocks
507 "stash 1d74d1a60332fd38cf9405f1bae67917888da6cb 2,0,1",
508 "move 1d74d1a60332fd38cf9405f1bae67917888da6cb 2,0,1 1 2,0,1",
509 };
510
511 std::string err;
512 TransferList transfer_list = TransferList::Parse(android::base::Join(input_lines, '\n'), &err);
513 ASSERT_TRUE(static_cast<bool>(transfer_list));
514 ASSERT_EQ(4, transfer_list.version());
515 ASSERT_EQ(2, transfer_list.total_blocks());
516 ASSERT_EQ(1, transfer_list.stash_max_entries());
517 ASSERT_EQ(1, transfer_list.stash_max_blocks());
518 ASSERT_EQ(2U, transfer_list.commands().size());
519 ASSERT_EQ(Command::Type::STASH, transfer_list.commands()[0].type());
520 ASSERT_EQ(Command::Type::MOVE, transfer_list.commands()[1].type());
521 }
522
TEST(TransferListTest,Parse_InvalidCommand)523 TEST(TransferListTest, Parse_InvalidCommand) {
524 std::vector<std::string> input_lines{
525 "4", // version
526 "2", // total blocks
527 "1", // max stashed entries
528 "1", // max stashed blocks
529 "stash 1d74d1a60332fd38cf9405f1bae67917888da6cb 2,0,1",
530 "move 1d74d1a60332fd38cf9405f1bae67917888da6cb 2,0,1 1",
531 };
532
533 std::string err;
534 TransferList transfer_list = TransferList::Parse(android::base::Join(input_lines, '\n'), &err);
535 ASSERT_FALSE(static_cast<bool>(transfer_list));
536 }
537
TEST(TransferListTest,Parse_ZeroTotalBlocks)538 TEST(TransferListTest, Parse_ZeroTotalBlocks) {
539 std::vector<std::string> input_lines{
540 "4", // version
541 "0", // total blocks
542 "0", // max stashed entries
543 "0", // max stashed blocks
544 };
545
546 std::string err;
547 TransferList transfer_list = TransferList::Parse(android::base::Join(input_lines, '\n'), &err);
548 ASSERT_TRUE(static_cast<bool>(transfer_list));
549 ASSERT_EQ(4, transfer_list.version());
550 ASSERT_EQ(0, transfer_list.total_blocks());
551 ASSERT_EQ(0, transfer_list.stash_max_entries());
552 ASSERT_EQ(0, transfer_list.stash_max_blocks());
553 ASSERT_TRUE(transfer_list.commands().empty());
554 }
555