1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <fcntl.h>
16 #include <linux/fs.h>
17 #include <linux/memfd.h>
18 #include <sys/ioctl.h>
19 #include <sys/stat.h>
20 #include <sys/syscall.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include <chrono>
25 #include <iostream>
26 #include <memory>
27 #include <string_view>
28
29 #include <android-base/file.h>
30 #include <android-base/unique_fd.h>
31 #include <fs_mgr/file_wait.h>
32 #include <gtest/gtest.h>
33 #include <libdm/dm.h>
34 #include <libdm/loop_control.h>
35 #include <libsnapshot/cow_writer.h>
36 #include <libsnapshot/snapuserd_client.h>
37 #include <storage_literals/storage_literals.h>
38
39 #include "snapuserd.h"
40
41 namespace android {
42 namespace snapshot {
43
44 using namespace android::storage_literals;
45 using android::base::unique_fd;
46 using LoopDevice = android::dm::LoopDevice;
47 using namespace std::chrono_literals;
48 using namespace android::dm;
49 using namespace std;
50
51 static constexpr char kSnapuserdSocketTest[] = "snapuserdTest";
52
53 class TempDevice {
54 public:
TempDevice(const std::string & name,const DmTable & table)55 TempDevice(const std::string& name, const DmTable& table)
56 : dm_(DeviceMapper::Instance()), name_(name), valid_(false) {
57 valid_ = dm_.CreateDevice(name, table, &path_, std::chrono::seconds(5));
58 }
TempDevice(TempDevice && other)59 TempDevice(TempDevice&& other) noexcept
60 : dm_(other.dm_), name_(other.name_), path_(other.path_), valid_(other.valid_) {
61 other.valid_ = false;
62 }
~TempDevice()63 ~TempDevice() {
64 if (valid_) {
65 dm_.DeleteDevice(name_);
66 }
67 }
Destroy()68 bool Destroy() {
69 if (!valid_) {
70 return false;
71 }
72 valid_ = false;
73 return dm_.DeleteDevice(name_);
74 }
path() const75 const std::string& path() const { return path_; }
name() const76 const std::string& name() const { return name_; }
valid() const77 bool valid() const { return valid_; }
78
79 TempDevice(const TempDevice&) = delete;
80 TempDevice& operator=(const TempDevice&) = delete;
81
operator =(TempDevice && other)82 TempDevice& operator=(TempDevice&& other) noexcept {
83 name_ = other.name_;
84 valid_ = other.valid_;
85 other.valid_ = false;
86 return *this;
87 }
88
89 private:
90 DeviceMapper& dm_;
91 std::string name_;
92 std::string path_;
93 bool valid_;
94 };
95
96 class CowSnapuserdTest final {
97 public:
98 bool Setup();
99 bool SetupOrderedOps();
100 bool SetupOrderedOpsInverted();
101 bool SetupCopyOverlap_1();
102 bool SetupCopyOverlap_2();
103 bool Merge();
104 void ValidateMerge();
105 void ReadSnapshotDeviceAndValidate();
106 void Shutdown();
107 void MergeInterrupt();
108 void MergeInterruptFixed(int duration);
109 void MergeInterruptRandomly(int max_duration);
110 void ReadDmUserBlockWithoutDaemon();
111 void ReadLastBlock();
112
snapshot_dev() const113 std::string snapshot_dev() const { return snapshot_dev_->path(); }
114
115 static const uint64_t kSectorSize = 512;
116
117 private:
118 void SetupImpl();
119
120 void MergeImpl();
121 void SimulateDaemonRestart();
122 void StartMerge();
123
124 void CreateCowDevice();
125 void CreateCowDeviceOrderedOps();
126 void CreateCowDeviceOrderedOpsInverted();
127 void CreateCowDeviceWithCopyOverlap_1();
128 void CreateCowDeviceWithCopyOverlap_2();
129 bool SetupDaemon();
130 void CreateBaseDevice();
131 void InitCowDevice();
132 void SetDeviceControlName();
133 void InitDaemon();
134 void CreateDmUserDevice();
135 void StartSnapuserdDaemon();
136 void CreateSnapshotDevice();
137
138 unique_ptr<LoopDevice> base_loop_;
139 unique_ptr<TempDevice> dmuser_dev_;
140 unique_ptr<TempDevice> snapshot_dev_;
141
142 std::string system_device_ctrl_name_;
143 std::string system_device_name_;
144
145 unique_fd base_fd_;
146 std::unique_ptr<TemporaryFile> cow_system_;
147 std::unique_ptr<SnapuserdClient> client_;
148 std::unique_ptr<uint8_t[]> orig_buffer_;
149 std::unique_ptr<uint8_t[]> merged_buffer_;
150 bool setup_ok_ = false;
151 bool merge_ok_ = false;
152 size_t size_ = 50_MiB;
153 int cow_num_sectors_;
154 int total_base_size_;
155 };
156
157 class CowSnapuserdMetadataTest final {
158 public:
159 void Setup();
160 void SetupPartialArea();
161 void ValidateMetadata();
162 void ValidatePartialFilledArea();
163
164 private:
165 void InitMetadata();
166 void CreateCowDevice();
167 void CreateCowPartialFilledArea();
168
169 std::unique_ptr<Snapuserd> snapuserd_;
170 std::unique_ptr<TemporaryFile> cow_system_;
171 size_t size_ = 1_MiB;
172 };
173
CreateTempFile(const std::string & name,size_t size)174 static unique_fd CreateTempFile(const std::string& name, size_t size) {
175 unique_fd fd(syscall(__NR_memfd_create, name.c_str(), MFD_ALLOW_SEALING));
176 if (fd < 0) {
177 return {};
178 }
179 if (size) {
180 if (ftruncate(fd, size) < 0) {
181 perror("ftruncate");
182 return {};
183 }
184 if (fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) < 0) {
185 perror("fcntl");
186 return {};
187 }
188 }
189 return fd;
190 }
191
Shutdown()192 void CowSnapuserdTest::Shutdown() {
193 ASSERT_TRUE(snapshot_dev_->Destroy());
194 ASSERT_TRUE(dmuser_dev_->Destroy());
195
196 auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
197 ASSERT_TRUE(client_->WaitForDeviceDelete(system_device_ctrl_name_));
198 ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted(misc_device, 10s));
199 ASSERT_TRUE(client_->DetachSnapuserd());
200 }
201
Setup()202 bool CowSnapuserdTest::Setup() {
203 SetupImpl();
204 return setup_ok_;
205 }
206
SetupOrderedOps()207 bool CowSnapuserdTest::SetupOrderedOps() {
208 CreateBaseDevice();
209 CreateCowDeviceOrderedOps();
210 return SetupDaemon();
211 }
212
SetupOrderedOpsInverted()213 bool CowSnapuserdTest::SetupOrderedOpsInverted() {
214 CreateBaseDevice();
215 CreateCowDeviceOrderedOpsInverted();
216 return SetupDaemon();
217 }
218
SetupCopyOverlap_1()219 bool CowSnapuserdTest::SetupCopyOverlap_1() {
220 CreateBaseDevice();
221 CreateCowDeviceWithCopyOverlap_1();
222 return SetupDaemon();
223 }
224
SetupCopyOverlap_2()225 bool CowSnapuserdTest::SetupCopyOverlap_2() {
226 CreateBaseDevice();
227 CreateCowDeviceWithCopyOverlap_2();
228 return SetupDaemon();
229 }
230
SetupDaemon()231 bool CowSnapuserdTest::SetupDaemon() {
232 SetDeviceControlName();
233
234 StartSnapuserdDaemon();
235 InitCowDevice();
236
237 CreateDmUserDevice();
238 InitDaemon();
239
240 CreateSnapshotDevice();
241 setup_ok_ = true;
242
243 return setup_ok_;
244 }
245
StartSnapuserdDaemon()246 void CowSnapuserdTest::StartSnapuserdDaemon() {
247 pid_t pid = fork();
248 ASSERT_GE(pid, 0);
249 if (pid == 0) {
250 std::string arg0 = "/system/bin/snapuserd";
251 std::string arg1 = "-socket="s + kSnapuserdSocketTest;
252 char* const argv[] = {arg0.data(), arg1.data(), nullptr};
253 ASSERT_GE(execv(arg0.c_str(), argv), 0);
254 } else {
255 client_ = SnapuserdClient::Connect(kSnapuserdSocketTest, 10s);
256 ASSERT_NE(client_, nullptr);
257 }
258 }
259
ReadLastBlock()260 void CowSnapuserdTest::ReadLastBlock() {
261 unique_fd rnd_fd;
262 total_base_size_ = BLOCK_SZ * 2;
263
264 base_fd_ = CreateTempFile("base_device", total_base_size_);
265 ASSERT_GE(base_fd_, 0);
266
267 rnd_fd.reset(open("/dev/random", O_RDONLY));
268 ASSERT_TRUE(rnd_fd > 0);
269
270 std::unique_ptr<uint8_t[]> random_buffer = std::make_unique<uint8_t[]>(BLOCK_SZ);
271
272 for (size_t j = 0; j < ((total_base_size_) / BLOCK_SZ); j++) {
273 ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), BLOCK_SZ, 0), true);
274 ASSERT_EQ(android::base::WriteFully(base_fd_, random_buffer.get(), BLOCK_SZ), true);
275 }
276
277 ASSERT_EQ(lseek(base_fd_, 0, SEEK_SET), 0);
278
279 base_loop_ = std::make_unique<LoopDevice>(base_fd_, 10s);
280 ASSERT_TRUE(base_loop_->valid());
281
282 std::string path = android::base::GetExecutableDirectory();
283 cow_system_ = std::make_unique<TemporaryFile>(path);
284
285 std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(total_base_size_);
286 loff_t offset = 0;
287
288 // Fill random data
289 for (size_t j = 0; j < (total_base_size_ / BLOCK_SZ); j++) {
290 ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, BLOCK_SZ, 0),
291 true);
292
293 offset += BLOCK_SZ;
294 }
295
296 CowOptions options;
297 options.compression = "gz";
298 CowWriter writer(options);
299
300 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
301
302 ASSERT_TRUE(writer.AddRawBlocks(0, random_buffer_1_.get(), BLOCK_SZ));
303 ASSERT_TRUE(writer.AddRawBlocks(1, (char*)random_buffer_1_.get() + BLOCK_SZ, BLOCK_SZ));
304
305 ASSERT_TRUE(writer.Finalize());
306
307 SetDeviceControlName();
308
309 StartSnapuserdDaemon();
310 InitCowDevice();
311
312 CreateDmUserDevice();
313 InitDaemon();
314
315 CreateSnapshotDevice();
316
317 unique_fd snapshot_fd(open(snapshot_dev_->path().c_str(), O_RDONLY));
318 ASSERT_TRUE(snapshot_fd > 0);
319
320 std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(BLOCK_SZ);
321
322 offset = 7680;
323 ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), 512, offset), true);
324 ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)random_buffer_1_.get() + offset, 512), 0);
325 }
326
CreateBaseDevice()327 void CowSnapuserdTest::CreateBaseDevice() {
328 unique_fd rnd_fd;
329
330 total_base_size_ = (size_ * 4);
331 base_fd_ = CreateTempFile("base_device", total_base_size_);
332 ASSERT_GE(base_fd_, 0);
333
334 rnd_fd.reset(open("/dev/random", O_RDONLY));
335 ASSERT_TRUE(rnd_fd > 0);
336
337 std::unique_ptr<uint8_t[]> random_buffer = std::make_unique<uint8_t[]>(1_MiB);
338
339 for (size_t j = 0; j < ((total_base_size_) / 1_MiB); j++) {
340 ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true);
341 ASSERT_EQ(android::base::WriteFully(base_fd_, random_buffer.get(), 1_MiB), true);
342 }
343
344 ASSERT_EQ(lseek(base_fd_, 0, SEEK_SET), 0);
345
346 base_loop_ = std::make_unique<LoopDevice>(base_fd_, 10s);
347 ASSERT_TRUE(base_loop_->valid());
348 }
349
ReadSnapshotDeviceAndValidate()350 void CowSnapuserdTest::ReadSnapshotDeviceAndValidate() {
351 unique_fd snapshot_fd(open(snapshot_dev_->path().c_str(), O_RDONLY));
352 ASSERT_TRUE(snapshot_fd > 0);
353
354 std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size_);
355
356 // COPY
357 loff_t offset = 0;
358 ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
359 ASSERT_EQ(memcmp(snapuserd_buffer.get(), orig_buffer_.get(), size_), 0);
360
361 // REPLACE
362 offset += size_;
363 ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
364 ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + size_, size_), 0);
365
366 // ZERO
367 offset += size_;
368 ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
369 ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 2), size_), 0);
370
371 // REPLACE
372 offset += size_;
373 ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
374 ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 3), size_), 0);
375 }
376
CreateCowDeviceWithCopyOverlap_2()377 void CowSnapuserdTest::CreateCowDeviceWithCopyOverlap_2() {
378 std::string path = android::base::GetExecutableDirectory();
379 cow_system_ = std::make_unique<TemporaryFile>(path);
380
381 CowOptions options;
382 options.compression = "gz";
383 CowWriter writer(options);
384
385 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
386
387 size_t num_blocks = size_ / options.block_size;
388 size_t x = num_blocks;
389 size_t blk_src_copy = 0;
390
391 // Create overlapping copy operations
392 while (1) {
393 ASSERT_TRUE(writer.AddCopy(blk_src_copy, blk_src_copy + 1));
394 x -= 1;
395 if (x == 1) {
396 break;
397 }
398 blk_src_copy += 1;
399 }
400
401 // Flush operations
402 ASSERT_TRUE(writer.Finalize());
403
404 // Construct the buffer required for validation
405 orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
406
407 // Read the entire base device
408 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
409 true);
410
411 // Merged operations required for validation
412 int block_size = 4096;
413 x = num_blocks;
414 loff_t src_offset = block_size;
415 loff_t dest_offset = 0;
416
417 while (1) {
418 memmove((char*)orig_buffer_.get() + dest_offset, (char*)orig_buffer_.get() + src_offset,
419 block_size);
420 x -= 1;
421 if (x == 1) {
422 break;
423 }
424 src_offset += block_size;
425 dest_offset += block_size;
426 }
427 }
428
CreateCowDeviceWithCopyOverlap_1()429 void CowSnapuserdTest::CreateCowDeviceWithCopyOverlap_1() {
430 std::string path = android::base::GetExecutableDirectory();
431 cow_system_ = std::make_unique<TemporaryFile>(path);
432
433 CowOptions options;
434 options.compression = "gz";
435 CowWriter writer(options);
436
437 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
438
439 size_t num_blocks = size_ / options.block_size;
440 size_t x = num_blocks;
441 size_t blk_src_copy = num_blocks - 1;
442
443 // Create overlapping copy operations
444 while (1) {
445 ASSERT_TRUE(writer.AddCopy(blk_src_copy + 1, blk_src_copy));
446 x -= 1;
447 if (x == 0) {
448 ASSERT_EQ(blk_src_copy, 0);
449 break;
450 }
451 blk_src_copy -= 1;
452 }
453
454 // Flush operations
455 ASSERT_TRUE(writer.Finalize());
456
457 // Construct the buffer required for validation
458 orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
459
460 // Read the entire base device
461 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
462 true);
463
464 // Merged operations
465 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), options.block_size, 0),
466 true);
467 ASSERT_EQ(android::base::ReadFullyAtOffset(
468 base_fd_, (char*)orig_buffer_.get() + options.block_size, size_, 0),
469 true);
470 }
471
CreateCowDeviceOrderedOpsInverted()472 void CowSnapuserdTest::CreateCowDeviceOrderedOpsInverted() {
473 unique_fd rnd_fd;
474 loff_t offset = 0;
475
476 std::string path = android::base::GetExecutableDirectory();
477 cow_system_ = std::make_unique<TemporaryFile>(path);
478
479 rnd_fd.reset(open("/dev/random", O_RDONLY));
480 ASSERT_TRUE(rnd_fd > 0);
481
482 std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
483
484 // Fill random data
485 for (size_t j = 0; j < (size_ / 1_MiB); j++) {
486 ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
487 true);
488
489 offset += 1_MiB;
490 }
491
492 CowOptions options;
493 options.compression = "gz";
494 CowWriter writer(options);
495
496 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
497
498 size_t num_blocks = size_ / options.block_size;
499 size_t blk_end_copy = num_blocks * 2;
500 size_t source_blk = num_blocks - 1;
501 size_t blk_src_copy = blk_end_copy - 1;
502
503 size_t x = num_blocks;
504 while (1) {
505 ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
506 x -= 1;
507 if (x == 0) {
508 break;
509 }
510 source_blk -= 1;
511 blk_src_copy -= 1;
512 }
513
514 // Flush operations
515 ASSERT_TRUE(writer.Finalize());
516 // Construct the buffer required for validation
517 orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
518 // Read the entire base device
519 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
520 true);
521 // Merged Buffer
522 memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + size_, size_);
523 }
524
CreateCowDeviceOrderedOps()525 void CowSnapuserdTest::CreateCowDeviceOrderedOps() {
526 unique_fd rnd_fd;
527 loff_t offset = 0;
528
529 std::string path = android::base::GetExecutableDirectory();
530 cow_system_ = std::make_unique<TemporaryFile>(path);
531
532 rnd_fd.reset(open("/dev/random", O_RDONLY));
533 ASSERT_TRUE(rnd_fd > 0);
534
535 std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
536
537 // Fill random data
538 for (size_t j = 0; j < (size_ / 1_MiB); j++) {
539 ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
540 true);
541
542 offset += 1_MiB;
543 }
544
545 CowOptions options;
546 options.compression = "gz";
547 CowWriter writer(options);
548
549 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
550
551 size_t num_blocks = size_ / options.block_size;
552 size_t x = num_blocks;
553 size_t source_blk = 0;
554 size_t blk_src_copy = num_blocks;
555
556 while (1) {
557 ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
558
559 x -= 1;
560 if (x == 0) {
561 break;
562 }
563 source_blk += 1;
564 blk_src_copy += 1;
565 }
566
567 // Flush operations
568 ASSERT_TRUE(writer.Finalize());
569 // Construct the buffer required for validation
570 orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
571 // Read the entire base device
572 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
573 true);
574 // Merged Buffer
575 memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + size_, size_);
576 }
577
CreateCowDevice()578 void CowSnapuserdTest::CreateCowDevice() {
579 unique_fd rnd_fd;
580 loff_t offset = 0;
581
582 std::string path = android::base::GetExecutableDirectory();
583 cow_system_ = std::make_unique<TemporaryFile>(path);
584
585 rnd_fd.reset(open("/dev/random", O_RDONLY));
586 ASSERT_TRUE(rnd_fd > 0);
587
588 std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
589
590 // Fill random data
591 for (size_t j = 0; j < (size_ / 1_MiB); j++) {
592 ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
593 true);
594
595 offset += 1_MiB;
596 }
597
598 CowOptions options;
599 options.compression = "gz";
600 CowWriter writer(options);
601
602 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
603
604 size_t num_blocks = size_ / options.block_size;
605 size_t blk_end_copy = num_blocks * 2;
606 size_t source_blk = num_blocks - 1;
607 size_t blk_src_copy = blk_end_copy - 1;
608
609 size_t x = num_blocks;
610 while (1) {
611 ASSERT_TRUE(writer.AddCopy(source_blk, blk_src_copy));
612 x -= 1;
613 if (x == 0) {
614 break;
615 }
616 source_blk -= 1;
617 blk_src_copy -= 1;
618 }
619
620 source_blk = num_blocks;
621 blk_src_copy = blk_end_copy;
622
623 ASSERT_TRUE(writer.AddRawBlocks(source_blk, random_buffer_1_.get(), size_));
624
625 size_t blk_zero_copy_start = source_blk + num_blocks;
626 size_t blk_zero_copy_end = blk_zero_copy_start + num_blocks;
627
628 ASSERT_TRUE(writer.AddZeroBlocks(blk_zero_copy_start, num_blocks));
629
630 size_t blk_random2_replace_start = blk_zero_copy_end;
631
632 ASSERT_TRUE(writer.AddRawBlocks(blk_random2_replace_start, random_buffer_1_.get(), size_));
633
634 // Flush operations
635 ASSERT_TRUE(writer.Finalize());
636 // Construct the buffer required for validation
637 orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
638 std::string zero_buffer(size_, 0);
639 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), size_, size_), true);
640 memcpy((char*)orig_buffer_.get() + size_, random_buffer_1_.get(), size_);
641 memcpy((char*)orig_buffer_.get() + (size_ * 2), (void*)zero_buffer.c_str(), size_);
642 memcpy((char*)orig_buffer_.get() + (size_ * 3), random_buffer_1_.get(), size_);
643 }
644
InitCowDevice()645 void CowSnapuserdTest::InitCowDevice() {
646 cow_num_sectors_ = client_->InitDmUserCow(system_device_ctrl_name_, cow_system_->path,
647 base_loop_->device());
648 ASSERT_NE(cow_num_sectors_, 0);
649 }
650
SetDeviceControlName()651 void CowSnapuserdTest::SetDeviceControlName() {
652 system_device_name_.clear();
653 system_device_ctrl_name_.clear();
654
655 std::string str(cow_system_->path);
656 std::size_t found = str.find_last_of("/\\");
657 ASSERT_NE(found, std::string::npos);
658 system_device_name_ = str.substr(found + 1);
659
660 system_device_ctrl_name_ = system_device_name_ + "-ctrl";
661 }
662
CreateDmUserDevice()663 void CowSnapuserdTest::CreateDmUserDevice() {
664 DmTable dmuser_table;
665 ASSERT_TRUE(dmuser_table.AddTarget(
666 std::make_unique<DmTargetUser>(0, cow_num_sectors_, system_device_ctrl_name_)));
667 ASSERT_TRUE(dmuser_table.valid());
668
669 dmuser_dev_ = std::make_unique<TempDevice>(system_device_name_, dmuser_table);
670 ASSERT_TRUE(dmuser_dev_->valid());
671 ASSERT_FALSE(dmuser_dev_->path().empty());
672
673 auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
674 ASSERT_TRUE(android::fs_mgr::WaitForFile(misc_device, 10s));
675 }
676
ReadDmUserBlockWithoutDaemon()677 void CowSnapuserdTest::ReadDmUserBlockWithoutDaemon() {
678 DmTable dmuser_table;
679 std::string dm_user_name = "dm-test-device";
680 unique_fd fd;
681
682 // Create a dm-user block device
683 ASSERT_TRUE(dmuser_table.AddTarget(std::make_unique<DmTargetUser>(0, 123456, dm_user_name)));
684 ASSERT_TRUE(dmuser_table.valid());
685
686 dmuser_dev_ = std::make_unique<TempDevice>(dm_user_name, dmuser_table);
687 ASSERT_TRUE(dmuser_dev_->valid());
688 ASSERT_FALSE(dmuser_dev_->path().empty());
689
690 fd.reset(open(dmuser_dev_->path().c_str(), O_RDONLY));
691 ASSERT_GE(fd, 0);
692
693 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(1_MiB);
694
695 loff_t offset = 0;
696 // Every IO should fail as there is no daemon to process the IO
697 for (size_t j = 0; j < 10; j++) {
698 ASSERT_EQ(ReadFullyAtOffset(fd, (char*)buffer.get() + offset, BLOCK_SZ, offset), false);
699
700 offset += BLOCK_SZ;
701 }
702
703 fd = {};
704 ASSERT_TRUE(dmuser_dev_->Destroy());
705 }
706
InitDaemon()707 void CowSnapuserdTest::InitDaemon() {
708 bool ok = client_->AttachDmUser(system_device_ctrl_name_);
709 ASSERT_TRUE(ok);
710 }
711
CreateSnapshotDevice()712 void CowSnapuserdTest::CreateSnapshotDevice() {
713 DmTable snap_table;
714 ASSERT_TRUE(snap_table.AddTarget(std::make_unique<DmTargetSnapshot>(
715 0, total_base_size_ / kSectorSize, base_loop_->device(), dmuser_dev_->path(),
716 SnapshotStorageMode::Persistent, 8)));
717 ASSERT_TRUE(snap_table.valid());
718
719 snap_table.set_readonly(true);
720
721 snapshot_dev_ = std::make_unique<TempDevice>("cowsnapuserd-test-dm-snapshot", snap_table);
722 ASSERT_TRUE(snapshot_dev_->valid());
723 ASSERT_FALSE(snapshot_dev_->path().empty());
724 }
725
SetupImpl()726 void CowSnapuserdTest::SetupImpl() {
727 CreateBaseDevice();
728 CreateCowDevice();
729
730 SetDeviceControlName();
731
732 StartSnapuserdDaemon();
733 InitCowDevice();
734
735 CreateDmUserDevice();
736 InitDaemon();
737
738 CreateSnapshotDevice();
739 setup_ok_ = true;
740 }
741
Merge()742 bool CowSnapuserdTest::Merge() {
743 MergeImpl();
744 return merge_ok_;
745 }
746
StartMerge()747 void CowSnapuserdTest::StartMerge() {
748 DmTable merge_table;
749 ASSERT_TRUE(merge_table.AddTarget(std::make_unique<DmTargetSnapshot>(
750 0, total_base_size_ / kSectorSize, base_loop_->device(), dmuser_dev_->path(),
751 SnapshotStorageMode::Merge, 8)));
752 ASSERT_TRUE(merge_table.valid());
753 ASSERT_EQ(total_base_size_ / kSectorSize, merge_table.num_sectors());
754
755 DeviceMapper& dm = DeviceMapper::Instance();
756 ASSERT_TRUE(dm.LoadTableAndActivate("cowsnapuserd-test-dm-snapshot", merge_table));
757 }
758
MergeImpl()759 void CowSnapuserdTest::MergeImpl() {
760 StartMerge();
761 DeviceMapper& dm = DeviceMapper::Instance();
762
763 while (true) {
764 vector<DeviceMapper::TargetInfo> status;
765 ASSERT_TRUE(dm.GetTableStatus("cowsnapuserd-test-dm-snapshot", &status));
766 ASSERT_EQ(status.size(), 1);
767 ASSERT_EQ(strncmp(status[0].spec.target_type, "snapshot-merge", strlen("snapshot-merge")),
768 0);
769
770 DmTargetSnapshot::Status merge_status;
771 ASSERT_TRUE(DmTargetSnapshot::ParseStatusText(status[0].data, &merge_status));
772 ASSERT_TRUE(merge_status.error.empty());
773 if (merge_status.sectors_allocated == merge_status.metadata_sectors) {
774 break;
775 }
776
777 std::this_thread::sleep_for(250ms);
778 }
779
780 merge_ok_ = true;
781 }
782
ValidateMerge()783 void CowSnapuserdTest::ValidateMerge() {
784 merged_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
785 ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, merged_buffer_.get(), total_base_size_, 0),
786 true);
787 ASSERT_EQ(memcmp(merged_buffer_.get(), orig_buffer_.get(), total_base_size_), 0);
788 }
789
SimulateDaemonRestart()790 void CowSnapuserdTest::SimulateDaemonRestart() {
791 Shutdown();
792 std::this_thread::sleep_for(500ms);
793 SetDeviceControlName();
794 StartSnapuserdDaemon();
795 InitCowDevice();
796 CreateDmUserDevice();
797 InitDaemon();
798 CreateSnapshotDevice();
799 }
800
MergeInterruptRandomly(int max_duration)801 void CowSnapuserdTest::MergeInterruptRandomly(int max_duration) {
802 std::srand(std::time(nullptr));
803 StartMerge();
804
805 for (int i = 0; i < 20; i++) {
806 int duration = std::rand() % max_duration;
807 std::this_thread::sleep_for(std::chrono::milliseconds(duration));
808 SimulateDaemonRestart();
809 StartMerge();
810 }
811
812 SimulateDaemonRestart();
813 ASSERT_TRUE(Merge());
814 }
815
MergeInterruptFixed(int duration)816 void CowSnapuserdTest::MergeInterruptFixed(int duration) {
817 StartMerge();
818
819 for (int i = 0; i < 25; i++) {
820 std::this_thread::sleep_for(std::chrono::milliseconds(duration));
821 SimulateDaemonRestart();
822 StartMerge();
823 }
824
825 SimulateDaemonRestart();
826 ASSERT_TRUE(Merge());
827 }
828
MergeInterrupt()829 void CowSnapuserdTest::MergeInterrupt() {
830 // Interrupt merge at various intervals
831 StartMerge();
832 std::this_thread::sleep_for(250ms);
833 SimulateDaemonRestart();
834
835 StartMerge();
836 std::this_thread::sleep_for(250ms);
837 SimulateDaemonRestart();
838
839 StartMerge();
840 std::this_thread::sleep_for(150ms);
841 SimulateDaemonRestart();
842
843 StartMerge();
844 std::this_thread::sleep_for(100ms);
845 SimulateDaemonRestart();
846
847 StartMerge();
848 std::this_thread::sleep_for(800ms);
849 SimulateDaemonRestart();
850
851 StartMerge();
852 std::this_thread::sleep_for(600ms);
853 SimulateDaemonRestart();
854
855 ASSERT_TRUE(Merge());
856 }
857
CreateCowPartialFilledArea()858 void CowSnapuserdMetadataTest::CreateCowPartialFilledArea() {
859 std::string path = android::base::GetExecutableDirectory();
860 cow_system_ = std::make_unique<TemporaryFile>(path);
861
862 CowOptions options;
863 options.compression = "gz";
864 CowWriter writer(options);
865
866 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
867
868 // Area 0 is completely filled with 256 exceptions
869 for (int i = 0; i < 256; i++) {
870 ASSERT_TRUE(writer.AddCopy(i, 256 + i));
871 }
872
873 // Area 1 is partially filled with 2 copy ops and 10 zero ops
874 ASSERT_TRUE(writer.AddCopy(500, 1000));
875 ASSERT_TRUE(writer.AddCopy(501, 1001));
876
877 ASSERT_TRUE(writer.AddZeroBlocks(300, 10));
878
879 // Flush operations
880 ASSERT_TRUE(writer.Finalize());
881 }
882
ValidatePartialFilledArea()883 void CowSnapuserdMetadataTest::ValidatePartialFilledArea() {
884 int area_sz = snapuserd_->GetMetadataAreaSize();
885
886 ASSERT_EQ(area_sz, 2);
887
888 size_t new_chunk = 263;
889 // Verify the partially filled area
890 void* buffer = snapuserd_->GetExceptionBuffer(1);
891 loff_t offset = 0;
892 struct disk_exception* de;
893 for (int i = 11; i >= 0; i--) {
894 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
895 ASSERT_EQ(de->old_chunk, i);
896 offset += sizeof(struct disk_exception);
897 new_chunk += 1;
898 }
899
900 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
901 ASSERT_EQ(de->old_chunk, 0);
902 ASSERT_EQ(de->new_chunk, 0);
903 }
904
SetupPartialArea()905 void CowSnapuserdMetadataTest::SetupPartialArea() {
906 CreateCowPartialFilledArea();
907 InitMetadata();
908 }
909
CreateCowDevice()910 void CowSnapuserdMetadataTest::CreateCowDevice() {
911 unique_fd rnd_fd;
912 loff_t offset = 0;
913
914 std::string path = android::base::GetExecutableDirectory();
915 cow_system_ = std::make_unique<TemporaryFile>(path);
916
917 rnd_fd.reset(open("/dev/random", O_RDONLY));
918 ASSERT_TRUE(rnd_fd > 0);
919
920 std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
921
922 // Fill random data
923 for (size_t j = 0; j < (size_ / 1_MiB); j++) {
924 ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
925 true);
926
927 offset += 1_MiB;
928 }
929
930 CowOptions options;
931 options.compression = "gz";
932 CowWriter writer(options);
933
934 ASSERT_TRUE(writer.Initialize(cow_system_->fd));
935
936 size_t num_blocks = size_ / options.block_size;
937
938 // Overlapping region. This has to be split
939 // into two batch operations
940 ASSERT_TRUE(writer.AddCopy(23, 20));
941 ASSERT_TRUE(writer.AddCopy(22, 19));
942 ASSERT_TRUE(writer.AddCopy(21, 18));
943 ASSERT_TRUE(writer.AddCopy(20, 17));
944 ASSERT_TRUE(writer.AddCopy(19, 16));
945 ASSERT_TRUE(writer.AddCopy(18, 15));
946
947 // Contiguous region but blocks in ascending order
948 // Daemon has to ensure that these blocks are merged
949 // in a batch
950 ASSERT_TRUE(writer.AddCopy(50, 75));
951 ASSERT_TRUE(writer.AddCopy(51, 76));
952 ASSERT_TRUE(writer.AddCopy(52, 77));
953 ASSERT_TRUE(writer.AddCopy(53, 78));
954
955 // Dis-contiguous region
956 ASSERT_TRUE(writer.AddCopy(110, 130));
957 ASSERT_TRUE(writer.AddCopy(105, 125));
958 ASSERT_TRUE(writer.AddCopy(100, 120));
959
960 // Overlap
961 ASSERT_TRUE(writer.AddCopy(25, 30));
962 ASSERT_TRUE(writer.AddCopy(30, 31));
963
964 size_t source_blk = num_blocks;
965
966 ASSERT_TRUE(writer.AddRawBlocks(source_blk, random_buffer_1_.get(), size_));
967
968 size_t blk_zero_copy_start = source_blk + num_blocks;
969
970 ASSERT_TRUE(writer.AddZeroBlocks(blk_zero_copy_start, num_blocks));
971
972 // Flush operations
973 ASSERT_TRUE(writer.Finalize());
974 }
975
InitMetadata()976 void CowSnapuserdMetadataTest::InitMetadata() {
977 snapuserd_ = std::make_unique<Snapuserd>("", cow_system_->path, "");
978 ASSERT_TRUE(snapuserd_->InitCowDevice());
979 }
980
Setup()981 void CowSnapuserdMetadataTest::Setup() {
982 CreateCowDevice();
983 InitMetadata();
984 }
985
ValidateMetadata()986 void CowSnapuserdMetadataTest::ValidateMetadata() {
987 int area_sz = snapuserd_->GetMetadataAreaSize();
988 ASSERT_EQ(area_sz, 3);
989
990 size_t old_chunk;
991 size_t new_chunk;
992
993 for (int i = 0; i < area_sz; i++) {
994 void* buffer = snapuserd_->GetExceptionBuffer(i);
995 loff_t offset = 0;
996 if (i == 0) {
997 old_chunk = 256;
998 new_chunk = 2;
999 } else if (i == 1) {
1000 old_chunk = 512;
1001 new_chunk = 259;
1002 }
1003 for (int j = 0; j < 256; j++) {
1004 struct disk_exception* de =
1005 reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1006
1007 if (i != 2) {
1008 ASSERT_EQ(de->old_chunk, old_chunk);
1009 ASSERT_EQ(de->new_chunk, new_chunk);
1010 old_chunk += 1;
1011 new_chunk += 1;
1012 } else {
1013 break;
1014 }
1015 offset += sizeof(struct disk_exception);
1016 }
1017
1018 if (i == 2) {
1019 // The first 5 copy operation is not batch merged
1020 // as the sequence is discontiguous
1021 struct disk_exception* de =
1022 reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1023 ASSERT_EQ(de->old_chunk, 30);
1024 ASSERT_EQ(de->new_chunk, 518);
1025 offset += sizeof(struct disk_exception);
1026
1027 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1028 ASSERT_EQ(de->old_chunk, 25);
1029 ASSERT_EQ(de->new_chunk, 520);
1030 offset += sizeof(struct disk_exception);
1031
1032 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1033 ASSERT_EQ(de->old_chunk, 100);
1034 ASSERT_EQ(de->new_chunk, 521);
1035 offset += sizeof(struct disk_exception);
1036
1037 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1038 ASSERT_EQ(de->old_chunk, 105);
1039 ASSERT_EQ(de->new_chunk, 522);
1040 offset += sizeof(struct disk_exception);
1041
1042 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1043 ASSERT_EQ(de->old_chunk, 110);
1044 ASSERT_EQ(de->new_chunk, 523);
1045 offset += sizeof(struct disk_exception);
1046
1047 // The next 4 operations are batch merged as
1048 // both old and new chunk are contiguous
1049 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1050 ASSERT_EQ(de->old_chunk, 53);
1051 ASSERT_EQ(de->new_chunk, 524);
1052 offset += sizeof(struct disk_exception);
1053
1054 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1055 ASSERT_EQ(de->old_chunk, 52);
1056 ASSERT_EQ(de->new_chunk, 525);
1057 offset += sizeof(struct disk_exception);
1058
1059 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1060 ASSERT_EQ(de->old_chunk, 51);
1061 ASSERT_EQ(de->new_chunk, 526);
1062 offset += sizeof(struct disk_exception);
1063
1064 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1065 ASSERT_EQ(de->old_chunk, 50);
1066 ASSERT_EQ(de->new_chunk, 527);
1067 offset += sizeof(struct disk_exception);
1068
1069 // This is handling overlap operation with
1070 // two batch merge operations.
1071 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1072 ASSERT_EQ(de->old_chunk, 18);
1073 ASSERT_EQ(de->new_chunk, 528);
1074 offset += sizeof(struct disk_exception);
1075
1076 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1077 ASSERT_EQ(de->old_chunk, 19);
1078 ASSERT_EQ(de->new_chunk, 529);
1079 offset += sizeof(struct disk_exception);
1080
1081 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1082 ASSERT_EQ(de->old_chunk, 20);
1083 ASSERT_EQ(de->new_chunk, 530);
1084 offset += sizeof(struct disk_exception);
1085
1086 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1087 ASSERT_EQ(de->old_chunk, 21);
1088 ASSERT_EQ(de->new_chunk, 532);
1089 offset += sizeof(struct disk_exception);
1090
1091 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1092 ASSERT_EQ(de->old_chunk, 22);
1093 ASSERT_EQ(de->new_chunk, 533);
1094 offset += sizeof(struct disk_exception);
1095
1096 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1097 ASSERT_EQ(de->old_chunk, 23);
1098 ASSERT_EQ(de->new_chunk, 534);
1099 offset += sizeof(struct disk_exception);
1100
1101 // End of metadata
1102 de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
1103 ASSERT_EQ(de->old_chunk, 0);
1104 ASSERT_EQ(de->new_chunk, 0);
1105 offset += sizeof(struct disk_exception);
1106 }
1107 }
1108 }
1109
TEST(Snapuserd_Test,Snapshot_Metadata)1110 TEST(Snapuserd_Test, Snapshot_Metadata) {
1111 CowSnapuserdMetadataTest harness;
1112 harness.Setup();
1113 harness.ValidateMetadata();
1114 }
1115
TEST(Snapuserd_Test,Snapshot_Metadata_Overlap)1116 TEST(Snapuserd_Test, Snapshot_Metadata_Overlap) {
1117 CowSnapuserdMetadataTest harness;
1118 harness.SetupPartialArea();
1119 harness.ValidatePartialFilledArea();
1120 }
1121
TEST(Snapuserd_Test,Snapshot_Merge_Resume)1122 TEST(Snapuserd_Test, Snapshot_Merge_Resume) {
1123 CowSnapuserdTest harness;
1124 ASSERT_TRUE(harness.Setup());
1125 harness.MergeInterrupt();
1126 harness.ValidateMerge();
1127 harness.Shutdown();
1128 }
1129
TEST(Snapuserd_Test,Snapshot_IO_TEST)1130 TEST(Snapuserd_Test, Snapshot_IO_TEST) {
1131 CowSnapuserdTest harness;
1132 ASSERT_TRUE(harness.Setup());
1133 harness.ReadSnapshotDeviceAndValidate();
1134 ASSERT_TRUE(harness.Merge());
1135 harness.ValidateMerge();
1136 harness.Shutdown();
1137 }
1138
TEST(Snapuserd_Test,Snapshot_END_IO_TEST)1139 TEST(Snapuserd_Test, Snapshot_END_IO_TEST) {
1140 CowSnapuserdTest harness;
1141 harness.ReadLastBlock();
1142 harness.Shutdown();
1143 }
1144
TEST(Snapuserd_Test,Snapshot_COPY_Overlap_TEST_1)1145 TEST(Snapuserd_Test, Snapshot_COPY_Overlap_TEST_1) {
1146 CowSnapuserdTest harness;
1147 ASSERT_TRUE(harness.SetupCopyOverlap_1());
1148 ASSERT_TRUE(harness.Merge());
1149 harness.ValidateMerge();
1150 harness.Shutdown();
1151 }
1152
TEST(Snapuserd_Test,Snapshot_COPY_Overlap_TEST_2)1153 TEST(Snapuserd_Test, Snapshot_COPY_Overlap_TEST_2) {
1154 CowSnapuserdTest harness;
1155 ASSERT_TRUE(harness.SetupCopyOverlap_2());
1156 ASSERT_TRUE(harness.Merge());
1157 harness.ValidateMerge();
1158 harness.Shutdown();
1159 }
1160
TEST(Snapuserd_Test,Snapshot_COPY_Overlap_Merge_Resume_TEST)1161 TEST(Snapuserd_Test, Snapshot_COPY_Overlap_Merge_Resume_TEST) {
1162 CowSnapuserdTest harness;
1163 ASSERT_TRUE(harness.SetupCopyOverlap_1());
1164 harness.MergeInterrupt();
1165 harness.ValidateMerge();
1166 harness.Shutdown();
1167 }
1168
TEST(Snapuserd_Test,ReadDmUserBlockWithoutDaemon)1169 TEST(Snapuserd_Test, ReadDmUserBlockWithoutDaemon) {
1170 CowSnapuserdTest harness;
1171 harness.ReadDmUserBlockWithoutDaemon();
1172 }
1173
TEST(Snapuserd_Test,Snapshot_Merge_Crash_Fixed_Ordered)1174 TEST(Snapuserd_Test, Snapshot_Merge_Crash_Fixed_Ordered) {
1175 CowSnapuserdTest harness;
1176 ASSERT_TRUE(harness.SetupOrderedOps());
1177 harness.MergeInterruptFixed(300);
1178 harness.ValidateMerge();
1179 harness.Shutdown();
1180 }
1181
TEST(Snapuserd_Test,Snapshot_Merge_Crash_Random_Ordered)1182 TEST(Snapuserd_Test, Snapshot_Merge_Crash_Random_Ordered) {
1183 CowSnapuserdTest harness;
1184 ASSERT_TRUE(harness.SetupOrderedOps());
1185 harness.MergeInterruptRandomly(500);
1186 harness.ValidateMerge();
1187 harness.Shutdown();
1188 }
1189
TEST(Snapuserd_Test,Snapshot_Merge_Crash_Fixed_Inverted)1190 TEST(Snapuserd_Test, Snapshot_Merge_Crash_Fixed_Inverted) {
1191 CowSnapuserdTest harness;
1192 ASSERT_TRUE(harness.SetupOrderedOpsInverted());
1193 harness.MergeInterruptFixed(50);
1194 harness.ValidateMerge();
1195 harness.Shutdown();
1196 }
1197
TEST(Snapuserd_Test,Snapshot_Merge_Crash_Random_Inverted)1198 TEST(Snapuserd_Test, Snapshot_Merge_Crash_Random_Inverted) {
1199 CowSnapuserdTest harness;
1200 ASSERT_TRUE(harness.SetupOrderedOpsInverted());
1201 harness.MergeInterruptRandomly(50);
1202 harness.ValidateMerge();
1203 harness.Shutdown();
1204 }
1205
1206 } // namespace snapshot
1207 } // namespace android
1208
main(int argc,char ** argv)1209 int main(int argc, char** argv) {
1210 ::testing::InitGoogleTest(&argc, argv);
1211 return RUN_ALL_TESTS();
1212 }
1213