• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <sys/stat.h>
16 
17 #include <cstdio>
18 #include <iostream>
19 #include <memory>
20 #include <string_view>
21 
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <gtest/gtest.h>
25 #include <libsnapshot/cow_reader.h>
26 #include <libsnapshot/cow_writer.h>
27 
28 using testing::AssertionFailure;
29 using testing::AssertionResult;
30 using testing::AssertionSuccess;
31 
32 namespace android {
33 namespace snapshot {
34 
35 class CowTest : public ::testing::Test {
36   protected:
SetUp()37     virtual void SetUp() override {
38         cow_ = std::make_unique<TemporaryFile>();
39         ASSERT_GE(cow_->fd, 0) << strerror(errno);
40     }
41 
TearDown()42     virtual void TearDown() override { cow_ = nullptr; }
43 
44     std::unique_ptr<TemporaryFile> cow_;
45 };
46 
47 // Sink that always appends to the end of a string.
48 class StringSink : public IByteSink {
49   public:
GetBuffer(size_t requested,size_t * actual)50     void* GetBuffer(size_t requested, size_t* actual) override {
51         size_t old_size = stream_.size();
52         stream_.resize(old_size + requested, '\0');
53         *actual = requested;
54         return stream_.data() + old_size;
55     }
ReturnData(void *,size_t)56     bool ReturnData(void*, size_t) override { return true; }
Reset()57     void Reset() { stream_.clear(); }
58 
stream()59     std::string& stream() { return stream_; }
60 
61   private:
62     std::string stream_;
63 };
64 
TEST_F(CowTest,ReadWrite)65 TEST_F(CowTest, ReadWrite) {
66     CowOptions options;
67     options.cluster_ops = 0;
68     CowWriter writer(options);
69 
70     ASSERT_TRUE(writer.Initialize(cow_->fd));
71 
72     std::string data = "This is some data, believe it";
73     data.resize(options.block_size, '\0');
74 
75     ASSERT_TRUE(writer.AddCopy(10, 20));
76     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
77     ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
78     ASSERT_TRUE(writer.Finalize());
79 
80     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
81 
82     CowReader reader;
83     CowHeader header;
84     CowFooter footer;
85     ASSERT_TRUE(reader.Parse(cow_->fd));
86     ASSERT_TRUE(reader.GetHeader(&header));
87     ASSERT_TRUE(reader.GetFooter(&footer));
88     ASSERT_EQ(header.magic, kCowMagicNumber);
89     ASSERT_EQ(header.major_version, kCowVersionMajor);
90     ASSERT_EQ(header.minor_version, kCowVersionMinor);
91     ASSERT_EQ(header.block_size, options.block_size);
92     ASSERT_EQ(footer.op.num_ops, 4);
93 
94     auto iter = reader.GetOpIter();
95     ASSERT_NE(iter, nullptr);
96     ASSERT_FALSE(iter->Done());
97     auto op = &iter->Get();
98 
99     ASSERT_EQ(op->type, kCowCopyOp);
100     ASSERT_EQ(op->compression, kCowCompressNone);
101     ASSERT_EQ(op->data_length, 0);
102     ASSERT_EQ(op->new_block, 10);
103     ASSERT_EQ(op->source, 20);
104 
105     StringSink sink;
106 
107     iter->Next();
108     ASSERT_FALSE(iter->Done());
109     op = &iter->Get();
110 
111     ASSERT_EQ(op->type, kCowReplaceOp);
112     ASSERT_EQ(op->compression, kCowCompressNone);
113     ASSERT_EQ(op->data_length, 4096);
114     ASSERT_EQ(op->new_block, 50);
115     ASSERT_TRUE(reader.ReadData(*op, &sink));
116     ASSERT_EQ(sink.stream(), data);
117 
118     iter->Next();
119     ASSERT_FALSE(iter->Done());
120     op = &iter->Get();
121 
122     // Note: the zero operation gets split into two blocks.
123     ASSERT_EQ(op->type, kCowZeroOp);
124     ASSERT_EQ(op->compression, kCowCompressNone);
125     ASSERT_EQ(op->data_length, 0);
126     ASSERT_EQ(op->new_block, 51);
127     ASSERT_EQ(op->source, 0);
128 
129     iter->Next();
130     ASSERT_FALSE(iter->Done());
131     op = &iter->Get();
132 
133     ASSERT_EQ(op->type, kCowZeroOp);
134     ASSERT_EQ(op->compression, kCowCompressNone);
135     ASSERT_EQ(op->data_length, 0);
136     ASSERT_EQ(op->new_block, 52);
137     ASSERT_EQ(op->source, 0);
138 
139     iter->Next();
140     ASSERT_TRUE(iter->Done());
141 }
142 
TEST_F(CowTest,ReadWriteXor)143 TEST_F(CowTest, ReadWriteXor) {
144     CowOptions options;
145     options.cluster_ops = 0;
146     CowWriter writer(options);
147 
148     ASSERT_TRUE(writer.Initialize(cow_->fd));
149 
150     std::string data = "This is some data, believe it";
151     data.resize(options.block_size, '\0');
152 
153     ASSERT_TRUE(writer.AddCopy(10, 20));
154     ASSERT_TRUE(writer.AddXorBlocks(50, data.data(), data.size(), 24, 10));
155     ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
156     ASSERT_TRUE(writer.Finalize());
157 
158     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
159 
160     CowReader reader;
161     CowHeader header;
162     CowFooter footer;
163     ASSERT_TRUE(reader.Parse(cow_->fd));
164     ASSERT_TRUE(reader.GetHeader(&header));
165     ASSERT_TRUE(reader.GetFooter(&footer));
166     ASSERT_EQ(header.magic, kCowMagicNumber);
167     ASSERT_EQ(header.major_version, kCowVersionMajor);
168     ASSERT_EQ(header.minor_version, kCowVersionMinor);
169     ASSERT_EQ(header.block_size, options.block_size);
170     ASSERT_EQ(footer.op.num_ops, 4);
171 
172     auto iter = reader.GetOpIter();
173     ASSERT_NE(iter, nullptr);
174     ASSERT_FALSE(iter->Done());
175     auto op = &iter->Get();
176 
177     ASSERT_EQ(op->type, kCowCopyOp);
178     ASSERT_EQ(op->compression, kCowCompressNone);
179     ASSERT_EQ(op->data_length, 0);
180     ASSERT_EQ(op->new_block, 10);
181     ASSERT_EQ(op->source, 20);
182 
183     StringSink sink;
184 
185     iter->Next();
186     ASSERT_FALSE(iter->Done());
187     op = &iter->Get();
188 
189     ASSERT_EQ(op->type, kCowXorOp);
190     ASSERT_EQ(op->compression, kCowCompressNone);
191     ASSERT_EQ(op->data_length, 4096);
192     ASSERT_EQ(op->new_block, 50);
193     ASSERT_EQ(op->source, 98314);  // 4096 * 24 + 10
194     ASSERT_TRUE(reader.ReadData(*op, &sink));
195     ASSERT_EQ(sink.stream(), data);
196 
197     iter->Next();
198     ASSERT_FALSE(iter->Done());
199     op = &iter->Get();
200 
201     // Note: the zero operation gets split into two blocks.
202     ASSERT_EQ(op->type, kCowZeroOp);
203     ASSERT_EQ(op->compression, kCowCompressNone);
204     ASSERT_EQ(op->data_length, 0);
205     ASSERT_EQ(op->new_block, 51);
206     ASSERT_EQ(op->source, 0);
207 
208     iter->Next();
209     ASSERT_FALSE(iter->Done());
210     op = &iter->Get();
211 
212     ASSERT_EQ(op->type, kCowZeroOp);
213     ASSERT_EQ(op->compression, kCowCompressNone);
214     ASSERT_EQ(op->data_length, 0);
215     ASSERT_EQ(op->new_block, 52);
216     ASSERT_EQ(op->source, 0);
217 
218     iter->Next();
219     ASSERT_TRUE(iter->Done());
220 }
221 
TEST_F(CowTest,CompressGz)222 TEST_F(CowTest, CompressGz) {
223     CowOptions options;
224     options.cluster_ops = 0;
225     options.compression = "gz";
226     CowWriter writer(options);
227 
228     ASSERT_TRUE(writer.Initialize(cow_->fd));
229 
230     std::string data = "This is some data, believe it";
231     data.resize(options.block_size, '\0');
232 
233     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
234     ASSERT_TRUE(writer.Finalize());
235 
236     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
237 
238     CowReader reader;
239     ASSERT_TRUE(reader.Parse(cow_->fd));
240 
241     auto iter = reader.GetOpIter();
242     ASSERT_NE(iter, nullptr);
243     ASSERT_FALSE(iter->Done());
244     auto op = &iter->Get();
245 
246     StringSink sink;
247 
248     ASSERT_EQ(op->type, kCowReplaceOp);
249     ASSERT_EQ(op->compression, kCowCompressGz);
250     ASSERT_EQ(op->data_length, 56);  // compressed!
251     ASSERT_EQ(op->new_block, 50);
252     ASSERT_TRUE(reader.ReadData(*op, &sink));
253     ASSERT_EQ(sink.stream(), data);
254 
255     iter->Next();
256     ASSERT_TRUE(iter->Done());
257 }
258 
TEST_F(CowTest,ClusterCompressGz)259 TEST_F(CowTest, ClusterCompressGz) {
260     CowOptions options;
261     options.compression = "gz";
262     options.cluster_ops = 2;
263     CowWriter writer(options);
264 
265     ASSERT_TRUE(writer.Initialize(cow_->fd));
266 
267     std::string data = "This is some data, believe it";
268     data.resize(options.block_size, '\0');
269     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
270 
271     std::string data2 = "More data!";
272     data2.resize(options.block_size, '\0');
273     ASSERT_TRUE(writer.AddRawBlocks(51, data2.data(), data2.size()));
274 
275     ASSERT_TRUE(writer.Finalize());
276 
277     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
278 
279     CowReader reader;
280     ASSERT_TRUE(reader.Parse(cow_->fd));
281 
282     auto iter = reader.GetOpIter();
283     ASSERT_NE(iter, nullptr);
284     ASSERT_FALSE(iter->Done());
285     auto op = &iter->Get();
286 
287     StringSink sink;
288 
289     ASSERT_EQ(op->type, kCowReplaceOp);
290     ASSERT_EQ(op->compression, kCowCompressGz);
291     ASSERT_EQ(op->data_length, 56);  // compressed!
292     ASSERT_EQ(op->new_block, 50);
293     ASSERT_TRUE(reader.ReadData(*op, &sink));
294     ASSERT_EQ(sink.stream(), data);
295 
296     iter->Next();
297     ASSERT_FALSE(iter->Done());
298     op = &iter->Get();
299 
300     ASSERT_EQ(op->type, kCowClusterOp);
301 
302     iter->Next();
303     ASSERT_FALSE(iter->Done());
304     op = &iter->Get();
305 
306     sink.Reset();
307     ASSERT_EQ(op->compression, kCowCompressGz);
308     ASSERT_EQ(op->data_length, 41);  // compressed!
309     ASSERT_EQ(op->new_block, 51);
310     ASSERT_TRUE(reader.ReadData(*op, &sink));
311     ASSERT_EQ(sink.stream(), data2);
312 
313     iter->Next();
314     ASSERT_FALSE(iter->Done());
315     op = &iter->Get();
316 
317     ASSERT_EQ(op->type, kCowClusterOp);
318 
319     iter->Next();
320     ASSERT_TRUE(iter->Done());
321 }
322 
TEST_F(CowTest,CompressTwoBlocks)323 TEST_F(CowTest, CompressTwoBlocks) {
324     CowOptions options;
325     options.compression = "gz";
326     options.cluster_ops = 0;
327     CowWriter writer(options);
328 
329     ASSERT_TRUE(writer.Initialize(cow_->fd));
330 
331     std::string data = "This is some data, believe it";
332     data.resize(options.block_size * 2, '\0');
333 
334     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
335     ASSERT_TRUE(writer.Finalize());
336 
337     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
338 
339     CowReader reader;
340     ASSERT_TRUE(reader.Parse(cow_->fd));
341 
342     auto iter = reader.GetOpIter();
343     ASSERT_NE(iter, nullptr);
344     ASSERT_FALSE(iter->Done());
345     iter->Next();
346     ASSERT_FALSE(iter->Done());
347 
348     StringSink sink;
349 
350     auto op = &iter->Get();
351     ASSERT_EQ(op->type, kCowReplaceOp);
352     ASSERT_EQ(op->compression, kCowCompressGz);
353     ASSERT_EQ(op->new_block, 51);
354     ASSERT_TRUE(reader.ReadData(*op, &sink));
355 }
356 
357 // Only return 1-byte buffers, to stress test the partial read logic in
358 // CowReader.
359 class HorribleStringSink : public StringSink {
360   public:
GetBuffer(size_t,size_t * actual)361     void* GetBuffer(size_t, size_t* actual) override { return StringSink::GetBuffer(1, actual); }
362 };
363 
364 class CompressionTest : public CowTest, public testing::WithParamInterface<const char*> {};
365 
TEST_P(CompressionTest,HorribleSink)366 TEST_P(CompressionTest, HorribleSink) {
367     CowOptions options;
368     options.compression = GetParam();
369     options.cluster_ops = 0;
370     CowWriter writer(options);
371 
372     ASSERT_TRUE(writer.Initialize(cow_->fd));
373 
374     std::string data = "This is some data, believe it";
375     data.resize(options.block_size, '\0');
376 
377     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
378     ASSERT_TRUE(writer.Finalize());
379 
380     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
381 
382     CowReader reader;
383     ASSERT_TRUE(reader.Parse(cow_->fd));
384 
385     auto iter = reader.GetOpIter();
386     ASSERT_NE(iter, nullptr);
387     ASSERT_FALSE(iter->Done());
388 
389     HorribleStringSink sink;
390     auto op = &iter->Get();
391     ASSERT_TRUE(reader.ReadData(*op, &sink));
392     ASSERT_EQ(sink.stream(), data);
393 }
394 
395 INSTANTIATE_TEST_SUITE_P(CowApi, CompressionTest, testing::Values("none", "gz", "brotli"));
396 
TEST_F(CowTest,GetSize)397 TEST_F(CowTest, GetSize) {
398     CowOptions options;
399     options.cluster_ops = 0;
400     CowWriter writer(options);
401     if (ftruncate(cow_->fd, 0) < 0) {
402         perror("Fails to set temp file size");
403         FAIL();
404     }
405     ASSERT_TRUE(writer.Initialize(cow_->fd));
406 
407     std::string data = "This is some data, believe it";
408     data.resize(options.block_size, '\0');
409 
410     ASSERT_TRUE(writer.AddCopy(10, 20));
411     ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
412     ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
413     auto size_before = writer.GetCowSize();
414     ASSERT_TRUE(writer.Finalize());
415     auto size_after = writer.GetCowSize();
416     ASSERT_EQ(size_before, size_after);
417     struct stat buf;
418 
419     ASSERT_GE(fstat(cow_->fd, &buf), 0) << strerror(errno);
420     ASSERT_EQ(buf.st_size, writer.GetCowSize());
421 }
422 
TEST_F(CowTest,AppendLabelSmall)423 TEST_F(CowTest, AppendLabelSmall) {
424     CowOptions options;
425     options.cluster_ops = 0;
426     auto writer = std::make_unique<CowWriter>(options);
427     ASSERT_TRUE(writer->Initialize(cow_->fd));
428 
429     std::string data = "This is some data, believe it";
430     data.resize(options.block_size, '\0');
431     ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
432     ASSERT_TRUE(writer->AddLabel(3));
433     ASSERT_TRUE(writer->Finalize());
434 
435     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
436 
437     writer = std::make_unique<CowWriter>(options);
438     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 3));
439 
440     std::string data2 = "More data!";
441     data2.resize(options.block_size, '\0');
442     ASSERT_TRUE(writer->AddRawBlocks(51, data2.data(), data2.size()));
443     ASSERT_TRUE(writer->Finalize());
444 
445     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
446 
447     struct stat buf;
448     ASSERT_EQ(fstat(cow_->fd, &buf), 0);
449     ASSERT_EQ(buf.st_size, writer->GetCowSize());
450 
451     // Read back both operations, and label.
452     CowReader reader;
453     uint64_t label;
454     ASSERT_TRUE(reader.Parse(cow_->fd));
455     ASSERT_TRUE(reader.GetLastLabel(&label));
456     ASSERT_EQ(label, 3);
457 
458     StringSink sink;
459 
460     auto iter = reader.GetOpIter();
461     ASSERT_NE(iter, nullptr);
462 
463     ASSERT_FALSE(iter->Done());
464     auto op = &iter->Get();
465     ASSERT_EQ(op->type, kCowReplaceOp);
466     ASSERT_TRUE(reader.ReadData(*op, &sink));
467     ASSERT_EQ(sink.stream(), data);
468 
469     iter->Next();
470     sink.Reset();
471 
472     ASSERT_FALSE(iter->Done());
473     op = &iter->Get();
474     ASSERT_EQ(op->type, kCowLabelOp);
475     ASSERT_EQ(op->source, 3);
476 
477     iter->Next();
478 
479     ASSERT_FALSE(iter->Done());
480     op = &iter->Get();
481     ASSERT_EQ(op->type, kCowReplaceOp);
482     ASSERT_TRUE(reader.ReadData(*op, &sink));
483     ASSERT_EQ(sink.stream(), data2);
484 
485     iter->Next();
486     ASSERT_TRUE(iter->Done());
487 }
488 
TEST_F(CowTest,AppendLabelMissing)489 TEST_F(CowTest, AppendLabelMissing) {
490     CowOptions options;
491     options.cluster_ops = 0;
492     auto writer = std::make_unique<CowWriter>(options);
493     ASSERT_TRUE(writer->Initialize(cow_->fd));
494 
495     ASSERT_TRUE(writer->AddLabel(0));
496     std::string data = "This is some data, believe it";
497     data.resize(options.block_size, '\0');
498     ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
499     ASSERT_TRUE(writer->AddLabel(1));
500     // Drop the tail end of the last op header, corrupting it.
501     ftruncate(cow_->fd, writer->GetCowSize() - sizeof(CowFooter) - 3);
502 
503     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
504 
505     writer = std::make_unique<CowWriter>(options);
506     ASSERT_FALSE(writer->InitializeAppend(cow_->fd, 1));
507     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 0));
508 
509     ASSERT_TRUE(writer->AddZeroBlocks(51, 1));
510     ASSERT_TRUE(writer->Finalize());
511 
512     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
513 
514     struct stat buf;
515     ASSERT_EQ(fstat(cow_->fd, &buf), 0);
516     ASSERT_EQ(buf.st_size, writer->GetCowSize());
517 
518     // Read back both operations.
519     CowReader reader;
520     ASSERT_TRUE(reader.Parse(cow_->fd));
521 
522     StringSink sink;
523 
524     auto iter = reader.GetOpIter();
525     ASSERT_NE(iter, nullptr);
526 
527     ASSERT_FALSE(iter->Done());
528     auto op = &iter->Get();
529     ASSERT_EQ(op->type, kCowLabelOp);
530     ASSERT_EQ(op->source, 0);
531 
532     iter->Next();
533 
534     ASSERT_FALSE(iter->Done());
535     op = &iter->Get();
536     ASSERT_EQ(op->type, kCowZeroOp);
537 
538     iter->Next();
539 
540     ASSERT_TRUE(iter->Done());
541 }
542 
TEST_F(CowTest,AppendExtendedCorrupted)543 TEST_F(CowTest, AppendExtendedCorrupted) {
544     CowOptions options;
545     options.cluster_ops = 0;
546     auto writer = std::make_unique<CowWriter>(options);
547     ASSERT_TRUE(writer->Initialize(cow_->fd));
548 
549     ASSERT_TRUE(writer->AddLabel(5));
550 
551     std::string data = "This is some data, believe it";
552     data.resize(options.block_size * 2, '\0');
553     ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
554     ASSERT_TRUE(writer->AddLabel(6));
555 
556     // fail to write the footer. Cow Format does not know if Label 6 is valid
557 
558     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
559 
560     // Get the last known good label
561     CowReader label_reader;
562     uint64_t label;
563     ASSERT_TRUE(label_reader.Parse(cow_->fd, {5}));
564     ASSERT_TRUE(label_reader.GetLastLabel(&label));
565     ASSERT_EQ(label, 5);
566 
567     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
568 
569     writer = std::make_unique<CowWriter>(options);
570     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 5));
571 
572     ASSERT_TRUE(writer->Finalize());
573 
574     struct stat buf;
575     ASSERT_EQ(fstat(cow_->fd, &buf), 0);
576     ASSERT_EQ(buf.st_size, writer->GetCowSize());
577 
578     // Read back all valid operations
579     CowReader reader;
580     ASSERT_TRUE(reader.Parse(cow_->fd));
581 
582     StringSink sink;
583 
584     auto iter = reader.GetOpIter();
585     ASSERT_NE(iter, nullptr);
586 
587     ASSERT_FALSE(iter->Done());
588     auto op = &iter->Get();
589     ASSERT_EQ(op->type, kCowLabelOp);
590     ASSERT_EQ(op->source, 5);
591 
592     iter->Next();
593     ASSERT_TRUE(iter->Done());
594 }
595 
TEST_F(CowTest,AppendbyLabel)596 TEST_F(CowTest, AppendbyLabel) {
597     CowOptions options;
598     options.cluster_ops = 0;
599     auto writer = std::make_unique<CowWriter>(options);
600     ASSERT_TRUE(writer->Initialize(cow_->fd));
601 
602     std::string data = "This is some data, believe it";
603     data.resize(options.block_size * 2, '\0');
604     ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
605 
606     ASSERT_TRUE(writer->AddLabel(4));
607 
608     ASSERT_TRUE(writer->AddZeroBlocks(50, 2));
609 
610     ASSERT_TRUE(writer->AddLabel(5));
611 
612     ASSERT_TRUE(writer->AddCopy(5, 6));
613 
614     ASSERT_TRUE(writer->AddLabel(6));
615 
616     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
617 
618     writer = std::make_unique<CowWriter>(options);
619     ASSERT_FALSE(writer->InitializeAppend(cow_->fd, 12));
620     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 5));
621 
622     // This should drop label 6
623     ASSERT_TRUE(writer->Finalize());
624 
625     struct stat buf;
626     ASSERT_EQ(fstat(cow_->fd, &buf), 0);
627     ASSERT_EQ(buf.st_size, writer->GetCowSize());
628 
629     // Read back all ops
630     CowReader reader;
631     ASSERT_TRUE(reader.Parse(cow_->fd));
632 
633     StringSink sink;
634 
635     auto iter = reader.GetOpIter();
636     ASSERT_NE(iter, nullptr);
637 
638     ASSERT_FALSE(iter->Done());
639     auto op = &iter->Get();
640     ASSERT_EQ(op->type, kCowReplaceOp);
641     ASSERT_TRUE(reader.ReadData(*op, &sink));
642     ASSERT_EQ(sink.stream(), data.substr(0, options.block_size));
643 
644     iter->Next();
645     sink.Reset();
646 
647     ASSERT_FALSE(iter->Done());
648     op = &iter->Get();
649     ASSERT_EQ(op->type, kCowReplaceOp);
650     ASSERT_TRUE(reader.ReadData(*op, &sink));
651     ASSERT_EQ(sink.stream(), data.substr(options.block_size, 2 * options.block_size));
652 
653     iter->Next();
654     sink.Reset();
655 
656     ASSERT_FALSE(iter->Done());
657     op = &iter->Get();
658     ASSERT_EQ(op->type, kCowLabelOp);
659     ASSERT_EQ(op->source, 4);
660 
661     iter->Next();
662 
663     ASSERT_FALSE(iter->Done());
664     op = &iter->Get();
665     ASSERT_EQ(op->type, kCowZeroOp);
666 
667     iter->Next();
668 
669     ASSERT_FALSE(iter->Done());
670     op = &iter->Get();
671     ASSERT_EQ(op->type, kCowZeroOp);
672 
673     iter->Next();
674     ASSERT_FALSE(iter->Done());
675     op = &iter->Get();
676     ASSERT_EQ(op->type, kCowLabelOp);
677     ASSERT_EQ(op->source, 5);
678 
679     iter->Next();
680 
681     ASSERT_TRUE(iter->Done());
682 }
683 
TEST_F(CowTest,ClusterTest)684 TEST_F(CowTest, ClusterTest) {
685     CowOptions options;
686     options.cluster_ops = 4;
687     auto writer = std::make_unique<CowWriter>(options);
688     ASSERT_TRUE(writer->Initialize(cow_->fd));
689 
690     std::string data = "This is some data, believe it";
691     data.resize(options.block_size, '\0');
692     ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
693 
694     ASSERT_TRUE(writer->AddLabel(4));
695 
696     ASSERT_TRUE(writer->AddZeroBlocks(50, 2));  // Cluster split in middle
697 
698     ASSERT_TRUE(writer->AddLabel(5));
699 
700     ASSERT_TRUE(writer->AddCopy(5, 6));
701 
702     // Cluster split
703 
704     ASSERT_TRUE(writer->AddLabel(6));
705 
706     ASSERT_TRUE(writer->Finalize());  // No data for cluster, so no cluster split needed
707 
708     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
709 
710     // Read back all ops
711     CowReader reader;
712     ASSERT_TRUE(reader.Parse(cow_->fd));
713 
714     StringSink sink;
715 
716     auto iter = reader.GetOpIter();
717     ASSERT_NE(iter, nullptr);
718 
719     ASSERT_FALSE(iter->Done());
720     auto op = &iter->Get();
721     ASSERT_EQ(op->type, kCowReplaceOp);
722     ASSERT_TRUE(reader.ReadData(*op, &sink));
723     ASSERT_EQ(sink.stream(), data.substr(0, options.block_size));
724 
725     iter->Next();
726     sink.Reset();
727 
728     ASSERT_FALSE(iter->Done());
729     op = &iter->Get();
730     ASSERT_EQ(op->type, kCowLabelOp);
731     ASSERT_EQ(op->source, 4);
732 
733     iter->Next();
734 
735     ASSERT_FALSE(iter->Done());
736     op = &iter->Get();
737     ASSERT_EQ(op->type, kCowZeroOp);
738 
739     iter->Next();
740 
741     ASSERT_FALSE(iter->Done());
742     op = &iter->Get();
743     ASSERT_EQ(op->type, kCowClusterOp);
744 
745     iter->Next();
746 
747     ASSERT_FALSE(iter->Done());
748     op = &iter->Get();
749     ASSERT_EQ(op->type, kCowZeroOp);
750 
751     iter->Next();
752 
753     ASSERT_FALSE(iter->Done());
754     op = &iter->Get();
755     ASSERT_EQ(op->type, kCowLabelOp);
756     ASSERT_EQ(op->source, 5);
757 
758     iter->Next();
759 
760     ASSERT_FALSE(iter->Done());
761     op = &iter->Get();
762     ASSERT_EQ(op->type, kCowCopyOp);
763 
764     iter->Next();
765 
766     ASSERT_FALSE(iter->Done());
767     op = &iter->Get();
768     ASSERT_EQ(op->type, kCowClusterOp);
769 
770     iter->Next();
771 
772     ASSERT_FALSE(iter->Done());
773     op = &iter->Get();
774     ASSERT_EQ(op->type, kCowLabelOp);
775     ASSERT_EQ(op->source, 6);
776 
777     iter->Next();
778 
779     ASSERT_TRUE(iter->Done());
780 }
781 
TEST_F(CowTest,ClusterAppendTest)782 TEST_F(CowTest, ClusterAppendTest) {
783     CowOptions options;
784     options.cluster_ops = 3;
785     auto writer = std::make_unique<CowWriter>(options);
786     ASSERT_TRUE(writer->Initialize(cow_->fd));
787 
788     ASSERT_TRUE(writer->AddLabel(50));
789     ASSERT_TRUE(writer->Finalize());  // Adds a cluster op, should be dropped on append
790 
791     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
792 
793     writer = std::make_unique<CowWriter>(options);
794     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 50));
795 
796     std::string data2 = "More data!";
797     data2.resize(options.block_size, '\0');
798     ASSERT_TRUE(writer->AddRawBlocks(51, data2.data(), data2.size()));
799     ASSERT_TRUE(writer->Finalize());  // Adds a cluster op
800 
801     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
802 
803     struct stat buf;
804     ASSERT_EQ(fstat(cow_->fd, &buf), 0);
805     ASSERT_EQ(buf.st_size, writer->GetCowSize());
806 
807     // Read back both operations, plus cluster op at end
808     CowReader reader;
809     uint64_t label;
810     ASSERT_TRUE(reader.Parse(cow_->fd));
811     ASSERT_TRUE(reader.GetLastLabel(&label));
812     ASSERT_EQ(label, 50);
813 
814     StringSink sink;
815 
816     auto iter = reader.GetOpIter();
817     ASSERT_NE(iter, nullptr);
818 
819     ASSERT_FALSE(iter->Done());
820     auto op = &iter->Get();
821     ASSERT_EQ(op->type, kCowLabelOp);
822     ASSERT_EQ(op->source, 50);
823 
824     iter->Next();
825 
826     ASSERT_FALSE(iter->Done());
827     op = &iter->Get();
828     ASSERT_EQ(op->type, kCowReplaceOp);
829     ASSERT_TRUE(reader.ReadData(*op, &sink));
830     ASSERT_EQ(sink.stream(), data2);
831 
832     iter->Next();
833 
834     ASSERT_FALSE(iter->Done());
835     op = &iter->Get();
836     ASSERT_EQ(op->type, kCowClusterOp);
837 
838     iter->Next();
839 
840     ASSERT_TRUE(iter->Done());
841 }
842 
TEST_F(CowTest,AppendAfterFinalize)843 TEST_F(CowTest, AppendAfterFinalize) {
844     CowOptions options;
845     options.cluster_ops = 0;
846     auto writer = std::make_unique<CowWriter>(options);
847     ASSERT_TRUE(writer->Initialize(cow_->fd));
848 
849     std::string data = "This is some data, believe it";
850     data.resize(options.block_size, '\0');
851     ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
852     ASSERT_TRUE(writer->AddLabel(3));
853     ASSERT_TRUE(writer->Finalize());
854 
855     std::string data2 = "More data!";
856     data2.resize(options.block_size, '\0');
857     ASSERT_TRUE(writer->AddRawBlocks(51, data2.data(), data2.size()));
858     ASSERT_TRUE(writer->Finalize());
859 
860     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
861 
862     // COW should be valid.
863     CowReader reader;
864     ASSERT_TRUE(reader.Parse(cow_->fd));
865 }
866 
WriteDataBlock(CowWriter * writer,uint64_t new_block,std::string data)867 AssertionResult WriteDataBlock(CowWriter* writer, uint64_t new_block, std::string data) {
868     data.resize(writer->options().block_size, '\0');
869     if (!writer->AddRawBlocks(new_block, data.data(), data.size())) {
870         return AssertionFailure() << "Failed to add raw block";
871     }
872     return AssertionSuccess();
873 }
874 
CompareDataBlock(CowReader * reader,const CowOperation & op,const std::string & data)875 AssertionResult CompareDataBlock(CowReader* reader, const CowOperation& op,
876                                  const std::string& data) {
877     CowHeader header;
878     reader->GetHeader(&header);
879 
880     std::string cmp = data;
881     cmp.resize(header.block_size, '\0');
882 
883     StringSink sink;
884     if (!reader->ReadData(op, &sink)) {
885         return AssertionFailure() << "Failed to read data block";
886     }
887     if (cmp != sink.stream()) {
888         return AssertionFailure() << "Data blocks did not match, expected " << cmp << ", got "
889                                   << sink.stream();
890     }
891 
892     return AssertionSuccess();
893 }
894 
TEST_F(CowTest,ResumeMidCluster)895 TEST_F(CowTest, ResumeMidCluster) {
896     CowOptions options;
897     options.cluster_ops = 7;
898     auto writer = std::make_unique<CowWriter>(options);
899     ASSERT_TRUE(writer->Initialize(cow_->fd));
900 
901     ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1"));
902     ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2"));
903     ASSERT_TRUE(WriteDataBlock(writer.get(), 3, "Block 3"));
904     ASSERT_TRUE(writer->AddLabel(1));
905     ASSERT_TRUE(writer->Finalize());
906     ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
907     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
908 
909     writer = std::make_unique<CowWriter>(options);
910     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
911     ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
912     ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
913     ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
914     ASSERT_TRUE(WriteDataBlock(writer.get(), 7, "Block 7"));
915     ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8"));
916     ASSERT_TRUE(writer->AddLabel(2));
917     ASSERT_TRUE(writer->Finalize());
918     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
919 
920     CowReader reader;
921     ASSERT_TRUE(reader.Parse(cow_->fd));
922 
923     auto iter = reader.GetOpIter();
924     size_t num_replace = 0;
925     size_t max_in_cluster = 0;
926     size_t num_in_cluster = 0;
927     size_t num_clusters = 0;
928     while (!iter->Done()) {
929         const auto& op = iter->Get();
930 
931         num_in_cluster++;
932         max_in_cluster = std::max(max_in_cluster, num_in_cluster);
933 
934         if (op.type == kCowReplaceOp) {
935             num_replace++;
936 
937             ASSERT_EQ(op.new_block, num_replace);
938             ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
939         } else if (op.type == kCowClusterOp) {
940             num_in_cluster = 0;
941             num_clusters++;
942         }
943 
944         iter->Next();
945     }
946     ASSERT_EQ(num_replace, 8);
947     ASSERT_EQ(max_in_cluster, 7);
948     ASSERT_EQ(num_clusters, 2);
949 }
950 
TEST_F(CowTest,ResumeEndCluster)951 TEST_F(CowTest, ResumeEndCluster) {
952     CowOptions options;
953     int cluster_ops = 5;
954     options.cluster_ops = cluster_ops;
955     auto writer = std::make_unique<CowWriter>(options);
956     ASSERT_TRUE(writer->Initialize(cow_->fd));
957 
958     ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1"));
959     ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2"));
960     ASSERT_TRUE(WriteDataBlock(writer.get(), 3, "Block 3"));
961     ASSERT_TRUE(writer->AddLabel(1));
962     ASSERT_TRUE(writer->Finalize());
963     ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
964     ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
965     ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
966     ASSERT_TRUE(WriteDataBlock(writer.get(), 7, "Block 7"));
967     ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8"));
968     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
969 
970     writer = std::make_unique<CowWriter>(options);
971     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
972     ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
973     ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
974     ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
975     ASSERT_TRUE(WriteDataBlock(writer.get(), 7, "Block 7"));
976     ASSERT_TRUE(WriteDataBlock(writer.get(), 8, "Block 8"));
977     ASSERT_TRUE(writer->AddLabel(2));
978     ASSERT_TRUE(writer->Finalize());
979     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
980 
981     CowReader reader;
982     ASSERT_TRUE(reader.Parse(cow_->fd));
983 
984     auto iter = reader.GetOpIter();
985     size_t num_replace = 0;
986     size_t max_in_cluster = 0;
987     size_t num_in_cluster = 0;
988     size_t num_clusters = 0;
989     while (!iter->Done()) {
990         const auto& op = iter->Get();
991 
992         num_in_cluster++;
993         max_in_cluster = std::max(max_in_cluster, num_in_cluster);
994 
995         if (op.type == kCowReplaceOp) {
996             num_replace++;
997 
998             ASSERT_EQ(op.new_block, num_replace);
999             ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
1000         } else if (op.type == kCowClusterOp) {
1001             num_in_cluster = 0;
1002             num_clusters++;
1003         }
1004 
1005         iter->Next();
1006     }
1007     ASSERT_EQ(num_replace, 8);
1008     ASSERT_EQ(max_in_cluster, cluster_ops);
1009     ASSERT_EQ(num_clusters, 3);
1010 }
1011 
TEST_F(CowTest,DeleteMidCluster)1012 TEST_F(CowTest, DeleteMidCluster) {
1013     CowOptions options;
1014     options.cluster_ops = 7;
1015     auto writer = std::make_unique<CowWriter>(options);
1016     ASSERT_TRUE(writer->Initialize(cow_->fd));
1017 
1018     ASSERT_TRUE(WriteDataBlock(writer.get(), 1, "Block 1"));
1019     ASSERT_TRUE(WriteDataBlock(writer.get(), 2, "Block 2"));
1020     ASSERT_TRUE(WriteDataBlock(writer.get(), 3, "Block 3"));
1021     ASSERT_TRUE(writer->AddLabel(1));
1022     ASSERT_TRUE(writer->Finalize());
1023     ASSERT_TRUE(WriteDataBlock(writer.get(), 4, "Block 4"));
1024     ASSERT_TRUE(WriteDataBlock(writer.get(), 5, "Block 5"));
1025     ASSERT_TRUE(WriteDataBlock(writer.get(), 6, "Block 6"));
1026     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
1027 
1028     writer = std::make_unique<CowWriter>(options);
1029     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
1030     ASSERT_TRUE(writer->Finalize());
1031     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
1032 
1033     CowReader reader;
1034     ASSERT_TRUE(reader.Parse(cow_->fd));
1035 
1036     auto iter = reader.GetOpIter();
1037     size_t num_replace = 0;
1038     size_t max_in_cluster = 0;
1039     size_t num_in_cluster = 0;
1040     size_t num_clusters = 0;
1041     while (!iter->Done()) {
1042         const auto& op = iter->Get();
1043 
1044         num_in_cluster++;
1045         max_in_cluster = std::max(max_in_cluster, num_in_cluster);
1046         if (op.type == kCowReplaceOp) {
1047             num_replace++;
1048 
1049             ASSERT_EQ(op.new_block, num_replace);
1050             ASSERT_TRUE(CompareDataBlock(&reader, op, "Block " + std::to_string(num_replace)));
1051         } else if (op.type == kCowClusterOp) {
1052             num_in_cluster = 0;
1053             num_clusters++;
1054         }
1055 
1056         iter->Next();
1057     }
1058     ASSERT_EQ(num_replace, 3);
1059     ASSERT_EQ(max_in_cluster, 5);  // 3 data, 1 label, 1 cluster op
1060     ASSERT_EQ(num_clusters, 1);
1061 }
1062 
TEST_F(CowTest,BigSeqOp)1063 TEST_F(CowTest, BigSeqOp) {
1064     CowOptions options;
1065     CowWriter writer(options);
1066     const int seq_len = std::numeric_limits<uint16_t>::max() / sizeof(uint32_t) + 1;
1067     uint32_t sequence[seq_len];
1068     for (int i = 0; i < seq_len; i++) {
1069         sequence[i] = i + 1;
1070     }
1071 
1072     ASSERT_TRUE(writer.Initialize(cow_->fd));
1073 
1074     ASSERT_TRUE(writer.AddSequenceData(seq_len, sequence));
1075     ASSERT_TRUE(writer.AddZeroBlocks(1, seq_len));
1076     ASSERT_TRUE(writer.Finalize());
1077 
1078     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
1079 
1080     CowReader reader;
1081     ASSERT_TRUE(reader.Parse(cow_->fd));
1082     auto iter = reader.GetRevMergeOpIter();
1083 
1084     for (int i = 0; i < seq_len; i++) {
1085         ASSERT_TRUE(!iter->Done());
1086         const auto& op = iter->Get();
1087 
1088         ASSERT_EQ(op.new_block, seq_len - i);
1089 
1090         iter->Next();
1091     }
1092     ASSERT_TRUE(iter->Done());
1093 }
1094 
TEST_F(CowTest,MissingSeqOp)1095 TEST_F(CowTest, MissingSeqOp) {
1096     CowOptions options;
1097     CowWriter writer(options);
1098     const int seq_len = 10;
1099     uint32_t sequence[seq_len];
1100     for (int i = 0; i < seq_len; i++) {
1101         sequence[i] = i + 1;
1102     }
1103 
1104     ASSERT_TRUE(writer.Initialize(cow_->fd));
1105 
1106     ASSERT_TRUE(writer.AddSequenceData(seq_len, sequence));
1107     ASSERT_TRUE(writer.AddZeroBlocks(1, seq_len - 1));
1108     ASSERT_TRUE(writer.Finalize());
1109 
1110     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
1111 
1112     CowReader reader;
1113     ASSERT_FALSE(reader.Parse(cow_->fd));
1114 }
1115 
TEST_F(CowTest,ResumeSeqOp)1116 TEST_F(CowTest, ResumeSeqOp) {
1117     CowOptions options;
1118     auto writer = std::make_unique<CowWriter>(options);
1119     const int seq_len = 10;
1120     uint32_t sequence[seq_len];
1121     for (int i = 0; i < seq_len; i++) {
1122         sequence[i] = i + 1;
1123     }
1124 
1125     ASSERT_TRUE(writer->Initialize(cow_->fd));
1126 
1127     ASSERT_TRUE(writer->AddSequenceData(seq_len, sequence));
1128     ASSERT_TRUE(writer->AddZeroBlocks(1, seq_len / 2));
1129     ASSERT_TRUE(writer->AddLabel(1));
1130     ASSERT_TRUE(writer->AddZeroBlocks(1 + seq_len / 2, 1));
1131 
1132     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
1133     auto reader = std::make_unique<CowReader>();
1134     ASSERT_TRUE(reader->Parse(cow_->fd, 1));
1135     auto itr = reader->GetRevMergeOpIter();
1136     ASSERT_TRUE(itr->Done());
1137 
1138     writer = std::make_unique<CowWriter>(options);
1139     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
1140     ASSERT_TRUE(writer->AddZeroBlocks(1 + seq_len / 2, seq_len / 2));
1141     ASSERT_TRUE(writer->Finalize());
1142 
1143     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
1144 
1145     reader = std::make_unique<CowReader>();
1146     ASSERT_TRUE(reader->Parse(cow_->fd));
1147 
1148     auto iter = reader->GetRevMergeOpIter();
1149 
1150     uint64_t expected_block = 10;
1151     while (!iter->Done() && expected_block > 0) {
1152         ASSERT_FALSE(iter->Done());
1153         const auto& op = iter->Get();
1154 
1155         ASSERT_EQ(op.new_block, expected_block);
1156 
1157         iter->Next();
1158         expected_block--;
1159     }
1160     ASSERT_EQ(expected_block, 0);
1161     ASSERT_TRUE(iter->Done());
1162 }
1163 
TEST_F(CowTest,RevMergeOpItrTest)1164 TEST_F(CowTest, RevMergeOpItrTest) {
1165     CowOptions options;
1166     options.cluster_ops = 5;
1167     options.num_merge_ops = 1;
1168     CowWriter writer(options);
1169     uint32_t sequence[] = {2, 10, 6, 7, 3, 5};
1170 
1171     ASSERT_TRUE(writer.Initialize(cow_->fd));
1172 
1173     ASSERT_TRUE(writer.AddSequenceData(6, sequence));
1174     ASSERT_TRUE(writer.AddCopy(6, 13));
1175     ASSERT_TRUE(writer.AddZeroBlocks(12, 1));
1176     ASSERT_TRUE(writer.AddZeroBlocks(8, 1));
1177     ASSERT_TRUE(writer.AddZeroBlocks(11, 1));
1178     ASSERT_TRUE(writer.AddCopy(3, 15));
1179     ASSERT_TRUE(writer.AddCopy(2, 11));
1180     ASSERT_TRUE(writer.AddZeroBlocks(4, 1));
1181     ASSERT_TRUE(writer.AddZeroBlocks(9, 1));
1182     ASSERT_TRUE(writer.AddCopy(5, 16));
1183     ASSERT_TRUE(writer.AddZeroBlocks(1, 1));
1184     ASSERT_TRUE(writer.AddCopy(10, 12));
1185     ASSERT_TRUE(writer.AddCopy(7, 14));
1186     ASSERT_TRUE(writer.Finalize());
1187 
1188     // New block in cow order is 6, 12, 8, 11, 3, 2, 4, 9, 5, 1, 10, 7
1189     // New block in merge order is 2, 10, 6, 7, 3, 5, 12, 11, 9, 8, 4, 1
1190     // RevMergeOrder is 1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10, 2
1191     // new block 2 is "already merged", so will be left out.
1192 
1193     std::vector<uint64_t> revMergeOpSequence = {1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10};
1194 
1195     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
1196 
1197     CowReader reader;
1198     ASSERT_TRUE(reader.Parse(cow_->fd));
1199     auto iter = reader.GetRevMergeOpIter();
1200     auto expected_new_block = revMergeOpSequence.begin();
1201 
1202     while (!iter->Done() && expected_new_block != revMergeOpSequence.end()) {
1203         const auto& op = iter->Get();
1204 
1205         ASSERT_EQ(op.new_block, *expected_new_block);
1206 
1207         iter->Next();
1208         expected_new_block++;
1209     }
1210     ASSERT_EQ(expected_new_block, revMergeOpSequence.end());
1211     ASSERT_TRUE(iter->Done());
1212 }
1213 
TEST_F(CowTest,LegacyRevMergeOpItrTest)1214 TEST_F(CowTest, LegacyRevMergeOpItrTest) {
1215     CowOptions options;
1216     options.cluster_ops = 5;
1217     options.num_merge_ops = 1;
1218     CowWriter writer(options);
1219 
1220     ASSERT_TRUE(writer.Initialize(cow_->fd));
1221 
1222     ASSERT_TRUE(writer.AddCopy(2, 11));
1223     ASSERT_TRUE(writer.AddCopy(10, 12));
1224     ASSERT_TRUE(writer.AddCopy(6, 13));
1225     ASSERT_TRUE(writer.AddCopy(7, 14));
1226     ASSERT_TRUE(writer.AddCopy(3, 15));
1227     ASSERT_TRUE(writer.AddCopy(5, 16));
1228     ASSERT_TRUE(writer.AddZeroBlocks(12, 1));
1229     ASSERT_TRUE(writer.AddZeroBlocks(8, 1));
1230     ASSERT_TRUE(writer.AddZeroBlocks(11, 1));
1231     ASSERT_TRUE(writer.AddZeroBlocks(4, 1));
1232     ASSERT_TRUE(writer.AddZeroBlocks(9, 1));
1233     ASSERT_TRUE(writer.AddZeroBlocks(1, 1));
1234 
1235     ASSERT_TRUE(writer.Finalize());
1236 
1237     // New block in cow order is 2, 10, 6, 7, 3, 5, 12, 8, 11, 4, 9, 1
1238     // New block in merge order is 2, 10, 6, 7, 3, 5, 12, 11, 9, 8, 4, 1
1239     // RevMergeOrder is 1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10, 2
1240     // new block 2 is "already merged", so will be left out.
1241 
1242     std::vector<uint64_t> revMergeOpSequence = {1, 4, 8, 9, 11, 12, 5, 3, 7, 6, 10};
1243 
1244     ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
1245 
1246     CowReader reader;
1247     ASSERT_TRUE(reader.Parse(cow_->fd));
1248     auto iter = reader.GetRevMergeOpIter();
1249     auto expected_new_block = revMergeOpSequence.begin();
1250 
1251     while (!iter->Done() && expected_new_block != revMergeOpSequence.end()) {
1252         const auto& op = iter->Get();
1253 
1254         ASSERT_EQ(op.new_block, *expected_new_block);
1255 
1256         iter->Next();
1257         expected_new_block++;
1258     }
1259     ASSERT_EQ(expected_new_block, revMergeOpSequence.end());
1260     ASSERT_TRUE(iter->Done());
1261 }
1262 
TEST_F(CowTest,InvalidMergeOrderTest)1263 TEST_F(CowTest, InvalidMergeOrderTest) {
1264     CowOptions options;
1265     options.cluster_ops = 5;
1266     options.num_merge_ops = 1;
1267     std::string data = "This is some data, believe it";
1268     data.resize(options.block_size, '\0');
1269     auto writer = std::make_unique<CowWriter>(options);
1270     CowReader reader;
1271 
1272     ASSERT_TRUE(writer->Initialize(cow_->fd));
1273 
1274     ASSERT_TRUE(writer->AddCopy(3, 2));
1275     ASSERT_TRUE(writer->AddCopy(2, 1));
1276     ASSERT_TRUE(writer->AddLabel(1));
1277     ASSERT_TRUE(writer->Finalize());
1278     ASSERT_TRUE(reader.Parse(cow_->fd));
1279     ASSERT_TRUE(reader.VerifyMergeOps());
1280 
1281     ASSERT_TRUE(writer->InitializeAppend(cow_->fd, 1));
1282     ASSERT_TRUE(writer->AddCopy(4, 2));
1283     ASSERT_TRUE(writer->Finalize());
1284     ASSERT_TRUE(reader.Parse(cow_->fd));
1285     ASSERT_FALSE(reader.VerifyMergeOps());
1286 
1287     writer = std::make_unique<CowWriter>(options);
1288     ASSERT_TRUE(writer->Initialize(cow_->fd));
1289     ASSERT_TRUE(writer->AddCopy(2, 1));
1290     ASSERT_TRUE(writer->AddXorBlocks(3, &data, data.size(), 1, 1));
1291     ASSERT_TRUE(writer->Finalize());
1292     ASSERT_TRUE(reader.Parse(cow_->fd));
1293     ASSERT_FALSE(reader.VerifyMergeOps());
1294 }
1295 
1296 }  // namespace snapshot
1297 }  // namespace android
1298 
main(int argc,char ** argv)1299 int main(int argc, char** argv) {
1300     ::testing::InitGoogleTest(&argc, argv);
1301     return RUN_ALL_TESTS();
1302 }
1303