Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / rbd_mirror / image_sync / test_mock_ObjectCopyRequest.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "test/rbd_mirror/test_mock_fixture.h"
5 #include "include/interval_set.h"
6 #include "include/rbd/librbd.hpp"
7 #include "include/rbd/object_map_types.h"
8 #include "librbd/ImageCtx.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/internal.h"
11 #include "librbd/Operations.h"
12 #include "librbd/io/ImageRequestWQ.h"
13 #include "librbd/io/ReadResult.h"
14 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
15 #include "test/librbd/mock/MockImageCtx.h"
16 #include "tools/rbd_mirror/Threads.h"
17 #include "tools/rbd_mirror/image_sync/ObjectCopyRequest.h"
18
19 namespace librbd {
20 namespace {
21
22 struct MockTestImageCtx : public librbd::MockImageCtx {
23   MockTestImageCtx(librbd::ImageCtx &image_ctx)
24     : librbd::MockImageCtx(image_ctx) {
25   }
26 };
27
28 } // anonymous namespace
29 } // namespace librbd
30
31 // template definitions
32 #include "tools/rbd_mirror/image_sync/ObjectCopyRequest.cc"
33 template class rbd::mirror::image_sync::ObjectCopyRequest<librbd::MockTestImageCtx>;
34
35 bool operator==(const SnapContext& rhs, const SnapContext& lhs) {
36   return (rhs.seq == lhs.seq && rhs.snaps == lhs.snaps);
37 }
38
39 namespace rbd {
40 namespace mirror {
41 namespace image_sync {
42
43 using ::testing::_;
44 using ::testing::DoAll;
45 using ::testing::DoDefault;
46 using ::testing::InSequence;
47 using ::testing::Invoke;
48 using ::testing::Return;
49 using ::testing::ReturnNew;
50 using ::testing::WithArg;
51
52 namespace {
53
54 void scribble(librbd::ImageCtx *image_ctx, int num_ops, size_t max_size,
55               interval_set<uint64_t> *what)
56 {
57   uint64_t object_size = 1 << image_ctx->order;
58   for (int i=0; i<num_ops; i++) {
59     uint64_t off = rand() % (object_size - max_size + 1);
60     uint64_t len = 1 + rand() % max_size;
61
62     bufferlist bl;
63     bl.append(std::string(len, '1'));
64
65     int r = image_ctx->io_work_queue->write(off, len, std::move(bl), 0);
66     ASSERT_EQ(static_cast<int>(len), r);
67
68     interval_set<uint64_t> w;
69     w.insert(off, len);
70     what->union_of(w);
71   }
72   std::cout << " wrote " << *what << std::endl;
73 }
74
75 } // anonymous namespace
76
77 class TestMockImageSyncObjectCopyRequest : public TestMockFixture {
78 public:
79   typedef ObjectCopyRequest<librbd::MockTestImageCtx> MockObjectCopyRequest;
80
81   void SetUp() override {
82     TestMockFixture::SetUp();
83
84     librbd::RBD rbd;
85     ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size));
86     ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx));
87
88     ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size));
89     ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx));
90   }
91
92   void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) {
93     EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce(
94       ReturnNew<FunctionContext>([](int) {}));
95   }
96
97   void expect_list_snaps(librbd::MockTestImageCtx &mock_image_ctx,
98                          librados::MockTestMemIoCtxImpl &mock_io_ctx,
99                          const librados::snap_set_t &snap_set) {
100     expect_set_snap_read(mock_io_ctx, CEPH_SNAPDIR);
101     EXPECT_CALL(mock_io_ctx,
102                 list_snaps(mock_image_ctx.image_ctx->get_object_name(0), _))
103       .WillOnce(DoAll(WithArg<1>(Invoke([&snap_set](librados::snap_set_t *out_snap_set) {
104                           *out_snap_set = snap_set;
105                         })),
106                       Return(0)));
107   }
108
109   void expect_list_snaps(librbd::MockTestImageCtx &mock_image_ctx,
110                          librados::MockTestMemIoCtxImpl &mock_io_ctx, int r) {
111     expect_set_snap_read(mock_io_ctx, CEPH_SNAPDIR);
112     auto &expect = EXPECT_CALL(mock_io_ctx,
113                                list_snaps(mock_image_ctx.image_ctx->get_object_name(0),
114                                           _));
115     if (r < 0) {
116       expect.WillOnce(Return(r));
117     } else {
118       expect.WillOnce(DoDefault());
119     }
120   }
121
122   void expect_get_object_name(librbd::MockTestImageCtx &mock_image_ctx) {
123     EXPECT_CALL(mock_image_ctx, get_object_name(0))
124                   .WillOnce(Return(mock_image_ctx.image_ctx->get_object_name(0)));
125   }
126
127   MockObjectCopyRequest *create_request(librbd::MockTestImageCtx &mock_remote_image_ctx,
128                                         librbd::MockTestImageCtx &mock_local_image_ctx,
129                                         Context *on_finish) {
130     expect_get_object_name(mock_local_image_ctx);
131     expect_get_object_name(mock_remote_image_ctx);
132     return new MockObjectCopyRequest(&mock_local_image_ctx,
133                                      &mock_remote_image_ctx, &m_snap_map,
134                                      0, on_finish);
135   }
136
137   void expect_set_snap_read(librados::MockTestMemIoCtxImpl &mock_io_ctx,
138                             uint64_t snap_id) {
139     EXPECT_CALL(mock_io_ctx, set_snap_read(snap_id));
140   }
141
142   void expect_sparse_read(librados::MockTestMemIoCtxImpl &mock_io_ctx, uint64_t offset,
143                           uint64_t length, int r) {
144
145     auto &expect = EXPECT_CALL(mock_io_ctx, sparse_read(_, offset, length, _, _));
146     if (r < 0) {
147       expect.WillOnce(Return(r));
148     } else {
149       expect.WillOnce(DoDefault());
150     }
151   }
152
153   void expect_sparse_read(librados::MockTestMemIoCtxImpl &mock_io_ctx,
154                    const interval_set<uint64_t> &extents, int r) {
155     for (auto extent : extents) {
156       expect_sparse_read(mock_io_ctx, extent.first, extent.second, r);
157       if (r < 0) {
158         break;
159       }
160     }
161   }
162
163   void expect_write(librados::MockTestMemIoCtxImpl &mock_io_ctx,
164                     uint64_t offset, uint64_t length,
165                     const SnapContext &snapc, int r) {
166     auto &expect = EXPECT_CALL(mock_io_ctx, write(_, _, length, offset, snapc));
167     if (r < 0) {
168       expect.WillOnce(Return(r));
169     } else {
170       expect.WillOnce(DoDefault());
171     }
172   }
173
174   void expect_write(librados::MockTestMemIoCtxImpl &mock_io_ctx,
175                     const interval_set<uint64_t> &extents,
176                     const SnapContext &snapc, int r) {
177     for (auto extent : extents) {
178       expect_write(mock_io_ctx, extent.first, extent.second, snapc, r);
179       if (r < 0) {
180         break;
181       }
182     }
183   }
184
185   void expect_truncate(librados::MockTestMemIoCtxImpl &mock_io_ctx,
186                        uint64_t offset, int r) {
187     auto &expect = EXPECT_CALL(mock_io_ctx, truncate(_, offset, _));
188     if (r < 0) {
189       expect.WillOnce(Return(r));
190     } else {
191       expect.WillOnce(DoDefault());
192     }
193   }
194
195   void expect_remove(librados::MockTestMemIoCtxImpl &mock_io_ctx, int r) {
196     auto &expect = EXPECT_CALL(mock_io_ctx, remove(_, _));
197     if (r < 0) {
198       expect.WillOnce(Return(r));
199     } else {
200       expect.WillOnce(DoDefault());
201     }
202   }
203
204   void expect_update_object_map(librbd::MockTestImageCtx &mock_image_ctx,
205                                 librbd::MockObjectMap &mock_object_map,
206                                 librados::snap_t snap_id, uint8_t state,
207                                 int r) {
208     if (mock_image_ctx.image_ctx->object_map != nullptr) {
209       auto &expect = EXPECT_CALL(mock_object_map, aio_update(snap_id, 0, 1, state, _, _, _));
210       if (r < 0) {
211         expect.WillOnce(DoAll(WithArg<6>(Invoke([this, r](Context *ctx) {
212                                   m_threads->work_queue->queue(ctx, r);
213                                 })),
214                               Return(true)));
215       } else {
216         expect.WillOnce(DoAll(WithArg<6>(Invoke([&mock_image_ctx, snap_id, state, r](Context *ctx) {
217                                   assert(mock_image_ctx.image_ctx->snap_lock.is_locked());
218                                   assert(mock_image_ctx.image_ctx->object_map_lock.is_wlocked());
219                                   mock_image_ctx.image_ctx->object_map->aio_update<Context>(
220                                     snap_id, 0, 1, state, boost::none, {}, ctx);
221                                 })),
222                               Return(true)));
223       }
224     }
225   }
226
227   using TestFixture::create_snap;
228   int create_snap(const char* snap_name) {
229     librados::snap_t remote_snap_id;
230     int r = create_snap(m_remote_image_ctx, snap_name, &remote_snap_id);
231     if (r < 0) {
232       return r;
233     }
234
235     librados::snap_t local_snap_id;
236     r = create_snap(m_local_image_ctx, snap_name, &local_snap_id);
237     if (r < 0) {
238       return r;
239     }
240
241     // collection of all existing snaps in local image
242     MockObjectCopyRequest::SnapIds local_snap_ids({local_snap_id});
243     if (!m_snap_map.empty()) {
244       local_snap_ids.insert(local_snap_ids.end(),
245                             m_snap_map.rbegin()->second.begin(),
246                             m_snap_map.rbegin()->second.end());
247     }
248     m_snap_map[remote_snap_id] = local_snap_ids;
249     m_remote_snap_ids.push_back(remote_snap_id);
250     m_local_snap_ids.push_back(local_snap_id);
251
252     return 0;
253   }
254
255   std::string get_snap_name(librbd::ImageCtx *image_ctx,
256                             librados::snap_t snap_id) {
257     auto it = std::find_if(image_ctx->snap_ids.begin(),
258                            image_ctx->snap_ids.end(),
259                            [snap_id](const std::pair<std::pair<cls::rbd::SnapshotNamespace,
260                                                                std::string>,
261                                                      librados::snap_t> &pair) {
262         return (pair.second == snap_id);
263       });
264     if (it == image_ctx->snap_ids.end()) {
265       return "";
266     }
267     return it->first.second;
268   }
269
270   int compare_objects() {
271     MockObjectCopyRequest::SnapMap snap_map(m_snap_map);
272     if (snap_map.empty()) {
273       return -ENOENT;
274     }
275
276     int r;
277     uint64_t object_size = 1 << m_remote_image_ctx->order;
278     while (!snap_map.empty()) {
279       librados::snap_t remote_snap_id = snap_map.begin()->first;
280       librados::snap_t local_snap_id = *snap_map.begin()->second.begin();
281       snap_map.erase(snap_map.begin());
282
283       std::string snap_name = get_snap_name(m_remote_image_ctx, remote_snap_id);
284       if (snap_name.empty()) {
285         return -ENOENT;
286       }
287
288       std::cout << "comparing '" << snap_name << " (" << remote_snap_id
289                 << " to " << local_snap_id << ")" << std::endl;
290
291       r = librbd::snap_set(m_remote_image_ctx,
292                            cls::rbd::UserSnapshotNamespace(),
293                            snap_name.c_str());
294       if (r < 0) {
295         return r;
296       }
297
298       r = librbd::snap_set(m_local_image_ctx,
299                            cls::rbd::UserSnapshotNamespace(),
300                            snap_name.c_str());
301       if (r < 0) {
302         return r;
303       }
304
305       bufferlist remote_bl;
306       remote_bl.append(std::string(object_size, '1'));
307       r = m_remote_image_ctx->io_work_queue->read(
308         0, object_size, librbd::io::ReadResult{&remote_bl}, 0);
309       if (r < 0) {
310         return r;
311       }
312
313       bufferlist local_bl;
314       local_bl.append(std::string(object_size, '1'));
315       r = m_local_image_ctx->io_work_queue->read(
316         0, object_size, librbd::io::ReadResult{&local_bl}, 0);
317       if (r < 0) {
318         return r;
319       }
320
321       if (!remote_bl.contents_equal(local_bl)) {
322         return -EBADMSG;
323       }
324     }
325
326     r = librbd::snap_set(m_remote_image_ctx,
327                          cls::rbd::UserSnapshotNamespace(),
328                          nullptr);
329     if (r < 0) {
330       return r;
331     }
332     r = librbd::snap_set(m_local_image_ctx,
333                          cls::rbd::UserSnapshotNamespace(),
334                          nullptr);
335     if (r < 0) {
336       return r;
337     }
338
339     return 0;
340   }
341
342   librbd::ImageCtx *m_remote_image_ctx;
343   librbd::ImageCtx *m_local_image_ctx;
344
345   MockObjectCopyRequest::SnapMap m_snap_map;
346   std::vector<librados::snap_t> m_remote_snap_ids;
347   std::vector<librados::snap_t> m_local_snap_ids;
348 };
349
350 TEST_F(TestMockImageSyncObjectCopyRequest, DNE) {
351   ASSERT_EQ(0, create_snap("sync"));
352   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
353   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
354
355   librbd::MockExclusiveLock mock_exclusive_lock;
356   mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
357
358   librbd::MockObjectMap mock_object_map;
359   mock_local_image_ctx.object_map = &mock_object_map;
360   expect_test_features(mock_local_image_ctx);
361
362   C_SaferCond ctx;
363   MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
364                                                   mock_local_image_ctx, &ctx);
365
366   librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
367     request->get_remote_io_ctx()));
368
369   InSequence seq;
370   expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, -ENOENT);
371
372   request->send();
373   ASSERT_EQ(0, ctx.wait());
374 }
375
376 TEST_F(TestMockImageSyncObjectCopyRequest, Write) {
377   // scribble some data
378   interval_set<uint64_t> one;
379   scribble(m_remote_image_ctx, 10, 102400, &one);
380
381   ASSERT_EQ(0, create_snap("sync"));
382   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
383   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
384
385   librbd::MockExclusiveLock mock_exclusive_lock;
386   mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
387
388   librbd::MockObjectMap mock_object_map;
389   mock_local_image_ctx.object_map = &mock_object_map;
390
391   expect_test_features(mock_local_image_ctx);
392
393   C_SaferCond ctx;
394   MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
395                                                   mock_local_image_ctx, &ctx);
396
397   librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
398     request->get_remote_io_ctx()));
399   librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
400     request->get_local_io_ctx()));
401
402   InSequence seq;
403   expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
404   expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
405   expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
406   expect_start_op(mock_exclusive_lock);
407   expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
408   expect_start_op(mock_exclusive_lock);
409   expect_update_object_map(mock_local_image_ctx, mock_object_map,
410                            m_local_snap_ids[0], OBJECT_EXISTS, 0);
411
412   request->send();
413   ASSERT_EQ(0, ctx.wait());
414   ASSERT_EQ(0, compare_objects());
415 }
416
417 TEST_F(TestMockImageSyncObjectCopyRequest, ReadMissingStaleSnapSet) {
418   ASSERT_EQ(0, create_snap("one"));
419   ASSERT_EQ(0, create_snap("two"));
420
421   // scribble some data
422   interval_set<uint64_t> one;
423   scribble(m_remote_image_ctx, 10, 102400, &one);
424   ASSERT_EQ(0, create_snap("three"));
425
426   ASSERT_EQ(0, create_snap("sync"));
427   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
428   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
429
430   librbd::MockExclusiveLock mock_exclusive_lock;
431   mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
432
433   librbd::MockObjectMap mock_object_map;
434   mock_local_image_ctx.object_map = &mock_object_map;
435
436   expect_test_features(mock_local_image_ctx);
437
438   C_SaferCond ctx;
439   MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
440                                                   mock_local_image_ctx, &ctx);
441
442   librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
443     request->get_remote_io_ctx()));
444   librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
445     request->get_local_io_ctx()));
446
447   librados::clone_info_t dummy_clone_info;
448   dummy_clone_info.cloneid = librados::SNAP_HEAD;
449   dummy_clone_info.size = 123;
450
451   librados::snap_set_t dummy_snap_set1;
452   dummy_snap_set1.clones.push_back(dummy_clone_info);
453
454   dummy_clone_info.size = 234;
455   librados::snap_set_t dummy_snap_set2;
456   dummy_snap_set2.clones.push_back(dummy_clone_info);
457
458   InSequence seq;
459   expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, dummy_snap_set1);
460   expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]);
461   expect_sparse_read(mock_remote_io_ctx, 0, 123, -ENOENT);
462   expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, dummy_snap_set2);
463   expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]);
464   expect_sparse_read(mock_remote_io_ctx, 0, 234, -ENOENT);
465   expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
466   expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[3]);
467   expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
468   expect_start_op(mock_exclusive_lock);
469   expect_write(mock_local_io_ctx, 0, one.range_end(),
470                {m_local_snap_ids[1], {m_local_snap_ids[1],
471                                       m_local_snap_ids[0]}},
472                 0);
473   expect_start_op(mock_exclusive_lock);
474   expect_update_object_map(mock_local_image_ctx, mock_object_map,
475                            m_local_snap_ids[2], OBJECT_EXISTS, 0);
476   expect_start_op(mock_exclusive_lock);
477   expect_update_object_map(mock_local_image_ctx, mock_object_map,
478                            m_local_snap_ids[3], OBJECT_EXISTS_CLEAN, 0);
479
480   request->send();
481   ASSERT_EQ(0, ctx.wait());
482   ASSERT_EQ(0, compare_objects());
483 }
484
485 TEST_F(TestMockImageSyncObjectCopyRequest, ReadMissingUpToDateSnapMap) {
486   // scribble some data
487   interval_set<uint64_t> one;
488   scribble(m_remote_image_ctx, 10, 102400, &one);
489
490   ASSERT_EQ(0, create_snap("sync"));
491   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
492   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
493
494   librbd::MockExclusiveLock mock_exclusive_lock;
495   mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
496
497   librbd::MockObjectMap mock_object_map;
498   mock_local_image_ctx.object_map = &mock_object_map;
499
500   expect_test_features(mock_local_image_ctx);
501
502   C_SaferCond ctx;
503   MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
504                                                   mock_local_image_ctx, &ctx);
505
506   librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
507     request->get_remote_io_ctx()));
508
509   InSequence seq;
510   expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
511   expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
512   expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), -ENOENT);
513   expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
514
515   request->send();
516   ASSERT_EQ(-ENOENT, ctx.wait());
517 }
518
519 TEST_F(TestMockImageSyncObjectCopyRequest, ReadError) {
520   // scribble some data
521   interval_set<uint64_t> one;
522   scribble(m_remote_image_ctx, 10, 102400, &one);
523
524   ASSERT_EQ(0, create_snap("sync"));
525   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
526   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
527
528   librbd::MockExclusiveLock mock_exclusive_lock;
529   mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
530
531   librbd::MockObjectMap mock_object_map;
532   mock_local_image_ctx.object_map = &mock_object_map;
533
534   expect_test_features(mock_local_image_ctx);
535
536   C_SaferCond ctx;
537   MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
538                                                   mock_local_image_ctx, &ctx);
539
540   librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
541     request->get_remote_io_ctx()));
542
543   InSequence seq;
544   expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
545   expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
546   expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(),  -EINVAL);
547
548   request->send();
549   ASSERT_EQ(-EINVAL, ctx.wait());
550 }
551
552 TEST_F(TestMockImageSyncObjectCopyRequest, WriteError) {
553   // scribble some data
554   interval_set<uint64_t> one;
555   scribble(m_remote_image_ctx, 10, 102400, &one);
556
557   ASSERT_EQ(0, create_snap("sync"));
558   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
559   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
560
561   librbd::MockExclusiveLock mock_exclusive_lock;
562   mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
563
564   librbd::MockObjectMap mock_object_map;
565   mock_local_image_ctx.object_map = &mock_object_map;
566
567   expect_test_features(mock_local_image_ctx);
568
569   C_SaferCond ctx;
570   MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
571                                                   mock_local_image_ctx, &ctx);
572
573   librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
574     request->get_remote_io_ctx()));
575   librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
576     request->get_local_io_ctx()));
577
578   InSequence seq;
579   expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
580   expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
581   expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
582   expect_start_op(mock_exclusive_lock);
583   expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, -EINVAL);
584
585   request->send();
586   ASSERT_EQ(-EINVAL, ctx.wait());
587 }
588
589 TEST_F(TestMockImageSyncObjectCopyRequest, WriteSnaps) {
590   // scribble some data
591   interval_set<uint64_t> one;
592   scribble(m_remote_image_ctx, 10, 102400, &one);
593   ASSERT_EQ(0, create_snap("one"));
594
595   interval_set<uint64_t> two;
596   scribble(m_remote_image_ctx, 10, 102400, &two);
597   ASSERT_EQ(0, create_snap("two"));
598
599   if (one.range_end() < two.range_end()) {
600     interval_set<uint64_t> resize_diff;
601     resize_diff.insert(one.range_end(), two.range_end() - one.range_end());
602     two.union_of(resize_diff);
603   }
604
605   ASSERT_EQ(0, create_snap("sync"));
606   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
607   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
608
609   librbd::MockExclusiveLock mock_exclusive_lock;
610   mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
611
612   librbd::MockObjectMap mock_object_map;
613   mock_local_image_ctx.object_map = &mock_object_map;
614
615   expect_test_features(mock_local_image_ctx);
616
617   C_SaferCond ctx;
618   MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
619                                                   mock_local_image_ctx, &ctx);
620
621   librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
622     request->get_remote_io_ctx()));
623   librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
624     request->get_local_io_ctx()));
625
626   InSequence seq;
627   expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
628   expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
629   expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
630   expect_start_op(mock_exclusive_lock);
631   expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
632   expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[2]);
633   expect_sparse_read(mock_remote_io_ctx, two, 0);
634   expect_start_op(mock_exclusive_lock);
635   expect_write(mock_local_io_ctx, two,
636                {m_local_snap_ids[0], {m_local_snap_ids[0]}}, 0);
637   expect_start_op(mock_exclusive_lock);
638   expect_update_object_map(mock_local_image_ctx, mock_object_map,
639                            m_local_snap_ids[0], OBJECT_EXISTS, 0);
640   expect_start_op(mock_exclusive_lock);
641   expect_update_object_map(mock_local_image_ctx, mock_object_map,
642                            m_local_snap_ids[1], OBJECT_EXISTS, 0);
643   expect_start_op(mock_exclusive_lock);
644   expect_update_object_map(mock_local_image_ctx, mock_object_map,
645                            m_local_snap_ids[2], OBJECT_EXISTS_CLEAN, 0);
646
647   request->send();
648   ASSERT_EQ(0, ctx.wait());
649   ASSERT_EQ(0, compare_objects());
650 }
651
652 TEST_F(TestMockImageSyncObjectCopyRequest, Trim) {
653   ASSERT_EQ(0, m_remote_image_ctx->operations->metadata_set(
654               "conf_rbd_skip_partial_discard", "false"));
655   // scribble some data
656   interval_set<uint64_t> one;
657   scribble(m_remote_image_ctx, 10, 102400, &one);
658   ASSERT_EQ(0, create_snap("one"));
659
660   // trim the object
661   uint64_t trim_offset = rand() % one.range_end();
662   ASSERT_LE(0, m_remote_image_ctx->io_work_queue->discard(
663     trim_offset, one.range_end() - trim_offset, m_remote_image_ctx->skip_partial_discard));
664   ASSERT_EQ(0, create_snap("sync"));
665
666   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
667   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
668
669   librbd::MockExclusiveLock mock_exclusive_lock;
670   mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
671
672   librbd::MockObjectMap mock_object_map;
673   mock_local_image_ctx.object_map = &mock_object_map;
674
675   expect_test_features(mock_local_image_ctx);
676
677   C_SaferCond ctx;
678   MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
679                                                   mock_local_image_ctx, &ctx);
680
681   librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
682     request->get_remote_io_ctx()));
683   librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
684     request->get_local_io_ctx()));
685
686   InSequence seq;
687   expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
688   expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[0]);
689   expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
690   expect_start_op(mock_exclusive_lock);
691   expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
692   expect_start_op(mock_exclusive_lock);
693   expect_truncate(mock_local_io_ctx, trim_offset, 0);
694   expect_start_op(mock_exclusive_lock);
695   expect_update_object_map(mock_local_image_ctx, mock_object_map,
696                            m_local_snap_ids[0], OBJECT_EXISTS, 0);
697   expect_start_op(mock_exclusive_lock);
698   expect_update_object_map(mock_local_image_ctx, mock_object_map,
699                            m_local_snap_ids[1], OBJECT_EXISTS, 0);
700
701   request->send();
702   ASSERT_EQ(0, ctx.wait());
703   ASSERT_EQ(0, compare_objects());
704 }
705
706 TEST_F(TestMockImageSyncObjectCopyRequest, Remove) {
707   // scribble some data
708   interval_set<uint64_t> one;
709   scribble(m_remote_image_ctx, 10, 102400, &one);
710   ASSERT_EQ(0, create_snap("one"));
711   ASSERT_EQ(0, create_snap("two"));
712
713   // remove the object
714   uint64_t object_size = 1 << m_remote_image_ctx->order;
715   ASSERT_LE(0, m_remote_image_ctx->io_work_queue->discard(0, object_size, m_remote_image_ctx->skip_partial_discard));
716   ASSERT_EQ(0, create_snap("sync"));
717   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
718   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
719
720   librbd::MockExclusiveLock mock_exclusive_lock;
721   mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
722
723   librbd::MockObjectMap mock_object_map;
724   mock_local_image_ctx.object_map = &mock_object_map;
725
726   expect_test_features(mock_local_image_ctx);
727
728   C_SaferCond ctx;
729   MockObjectCopyRequest *request = create_request(mock_remote_image_ctx,
730                                                   mock_local_image_ctx, &ctx);
731
732   librados::MockTestMemIoCtxImpl &mock_remote_io_ctx(get_mock_io_ctx(
733     request->get_remote_io_ctx()));
734   librados::MockTestMemIoCtxImpl &mock_local_io_ctx(get_mock_io_ctx(
735     request->get_local_io_ctx()));
736
737   InSequence seq;
738   expect_list_snaps(mock_remote_image_ctx, mock_remote_io_ctx, 0);
739   expect_set_snap_read(mock_remote_io_ctx, m_remote_snap_ids[1]);
740   expect_sparse_read(mock_remote_io_ctx, 0, one.range_end(), 0);
741   expect_start_op(mock_exclusive_lock);
742   expect_write(mock_local_io_ctx, 0, one.range_end(), {0, {}}, 0);
743   expect_start_op(mock_exclusive_lock);
744   expect_remove(mock_local_io_ctx, 0);
745   expect_start_op(mock_exclusive_lock);
746   expect_update_object_map(mock_local_image_ctx, mock_object_map,
747                            m_local_snap_ids[0], OBJECT_EXISTS, 0);
748   expect_start_op(mock_exclusive_lock);
749   expect_update_object_map(mock_local_image_ctx, mock_object_map,
750                            m_local_snap_ids[1], OBJECT_EXISTS_CLEAN, 0);
751
752   request->send();
753   ASSERT_EQ(0, ctx.wait());
754   ASSERT_EQ(0, compare_objects());
755 }
756
757 } // namespace image_sync
758 } // namespace mirror
759 } // namespace rbd