]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/deep_copy/test_mock_ImageCopyRequest.cc
4ee6320f3e5c9fdc6f6a6cfb113d7951db406a78
[ceph.git] / ceph / src / test / librbd / deep_copy / test_mock_ImageCopyRequest.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/librbd/test_mock_fixture.h"
5 #include "include/rbd/librbd.hpp"
6 #include "librbd/ImageCtx.h"
7 #include "librbd/ImageState.h"
8 #include "librbd/internal.h"
9 #include "librbd/Operations.h"
10 #include "librbd/deep_copy/Handler.h"
11 #include "librbd/deep_copy/ImageCopyRequest.h"
12 #include "librbd/deep_copy/ObjectCopyRequest.h"
13 #include "librbd/image/CloseRequest.h"
14 #include "librbd/image/OpenRequest.h"
15 #include "librbd/object_map/DiffRequest.h"
16 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
17 #include "test/librbd/mock/MockImageCtx.h"
18 #include "test/librbd/test_support.h"
19 #include <boost/scope_exit.hpp>
20
21 namespace librbd {
22
23 namespace {
24
25 struct MockTestImageCtx : public librbd::MockImageCtx {
26 static MockTestImageCtx* s_instance;
27 static MockTestImageCtx* create(const std::string &image_name,
28 const std::string &image_id,
29 librados::snap_t snap_id, librados::IoCtx& p,
30 bool read_only) {
31 ceph_assert(s_instance != nullptr);
32 return s_instance;
33 }
34
35 explicit MockTestImageCtx(librbd::ImageCtx &image_ctx)
36 : librbd::MockImageCtx(image_ctx) {
37 s_instance = this;
38 }
39
40 MOCK_METHOD0(destroy, void());
41 };
42
43 MockTestImageCtx* MockTestImageCtx::s_instance = nullptr;
44
45 } // anonymous namespace
46
47 namespace deep_copy {
48
49 template <>
50 struct ObjectCopyRequest<librbd::MockTestImageCtx> {
51 static ObjectCopyRequest* s_instance;
52 static ObjectCopyRequest* create(
53 librbd::MockTestImageCtx *src_image_ctx,
54 librbd::MockTestImageCtx *dst_image_ctx,
55 librados::snap_t src_snap_id_start,
56 librados::snap_t dst_snap_id_start,
57 const SnapMap &snap_map,
58 uint64_t object_number, bool flatten, Handler* handler,
59 Context *on_finish) {
60 ceph_assert(s_instance != nullptr);
61 std::lock_guard locker{s_instance->lock};
62 s_instance->snap_map = &snap_map;
63 s_instance->object_contexts[object_number] = on_finish;
64 s_instance->cond.notify_all();
65 return s_instance;
66 }
67
68 MOCK_METHOD0(send, void());
69
70 ceph::mutex lock = ceph::make_mutex("lock");
71 ceph::condition_variable cond;
72
73 const SnapMap *snap_map = nullptr;
74 std::map<uint64_t, Context *> object_contexts;
75
76 ObjectCopyRequest() {
77 s_instance = this;
78 }
79 };
80
81 ObjectCopyRequest<librbd::MockTestImageCtx>* ObjectCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
82
83 } // namespace deep_copy
84
85 namespace image {
86
87 template <>
88 struct CloseRequest<MockTestImageCtx> {
89 Context* on_finish = nullptr;
90 static CloseRequest* s_instance;
91 static CloseRequest* create(MockTestImageCtx *image_ctx, Context *on_finish) {
92 ceph_assert(s_instance != nullptr);
93 s_instance->on_finish = on_finish;
94 return s_instance;
95 }
96
97 MOCK_METHOD0(send, void());
98
99 CloseRequest() {
100 s_instance = this;
101 }
102 };
103
104 CloseRequest<MockTestImageCtx>* CloseRequest<MockTestImageCtx>::s_instance = nullptr;
105
106 template <>
107 struct OpenRequest<MockTestImageCtx> {
108 Context* on_finish = nullptr;
109 static OpenRequest* s_instance;
110 static OpenRequest* create(MockTestImageCtx *image_ctx,
111 bool skip_open_parent, Context *on_finish) {
112 ceph_assert(s_instance != nullptr);
113 s_instance->on_finish = on_finish;
114 return s_instance;
115 }
116
117 MOCK_METHOD0(send, void());
118
119 OpenRequest() {
120 s_instance = this;
121 }
122 };
123
124 OpenRequest<MockTestImageCtx>* OpenRequest<MockTestImageCtx>::s_instance = nullptr;
125
126 } // namespace image
127
128 namespace object_map {
129
130 template <>
131 struct DiffRequest<MockTestImageCtx> {
132 BitVector<2>* object_diff_state = nullptr;
133 Context* on_finish = nullptr;
134 static DiffRequest* s_instance;
135 static DiffRequest* create(MockTestImageCtx *image_ctx,
136 uint64_t snap_id_start, uint64_t snap_id_end,
137 BitVector<2>* object_diff_state,
138 Context* on_finish) {
139 ceph_assert(s_instance != nullptr);
140 s_instance->object_diff_state = object_diff_state;
141 s_instance->on_finish = on_finish;
142 return s_instance;
143 }
144
145 DiffRequest() {
146 s_instance = this;
147 }
148
149 MOCK_METHOD0(send, void());
150 };
151
152 DiffRequest<MockTestImageCtx>* DiffRequest<MockTestImageCtx>::s_instance = nullptr;
153
154 } // namespace object_map
155 } // namespace librbd
156
157 // template definitions
158 #include "librbd/deep_copy/ImageCopyRequest.cc"
159 template class librbd::deep_copy::ImageCopyRequest<librbd::MockTestImageCtx>;
160
161 namespace librbd {
162 namespace deep_copy {
163
164 using ::testing::_;
165 using ::testing::InSequence;
166 using ::testing::Invoke;
167 using ::testing::Return;
168
169 class TestMockDeepCopyImageCopyRequest : public TestMockFixture {
170 public:
171 typedef ImageCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest;
172 typedef ObjectCopyRequest<librbd::MockTestImageCtx> MockObjectCopyRequest;
173 typedef object_map::DiffRequest<librbd::MockTestImageCtx> MockDiffRequest;
174
175 librbd::ImageCtx *m_src_image_ctx;
176 librbd::ImageCtx *m_dst_image_ctx;
177 ThreadPool *m_thread_pool;
178 ContextWQ *m_work_queue;
179 librbd::SnapSeqs m_snap_seqs;
180 SnapMap m_snap_map;
181
182 void SetUp() override {
183 TestMockFixture::SetUp();
184
185 ASSERT_EQ(0, open_image(m_image_name, &m_src_image_ctx));
186
187 librbd::RBD rbd;
188 std::string dst_image_name = get_temp_image_name();
189 ASSERT_EQ(0, create_image_pp(rbd, m_ioctx, dst_image_name, m_image_size));
190 ASSERT_EQ(0, open_image(dst_image_name, &m_dst_image_ctx));
191
192 librbd::ImageCtx::get_thread_pool_instance(m_src_image_ctx->cct,
193 &m_thread_pool, &m_work_queue);
194 }
195
196 void expect_get_image_size(librbd::MockTestImageCtx &mock_image_ctx,
197 uint64_t size) {
198 EXPECT_CALL(mock_image_ctx, get_image_size(_))
199 .WillOnce(Return(size)).RetiresOnSaturation();
200 }
201
202 void expect_diff_send(MockDiffRequest& mock_request,
203 const BitVector<2>& diff_state, int r) {
204 EXPECT_CALL(mock_request, send())
205 .WillOnce(Invoke([this, &mock_request, diff_state, r]() {
206 if (r >= 0) {
207 *mock_request.object_diff_state = diff_state;
208 }
209 m_work_queue->queue(mock_request.on_finish, r);
210 }));
211 }
212
213 void expect_object_copy_send(MockObjectCopyRequest &mock_object_copy_request) {
214 EXPECT_CALL(mock_object_copy_request, send());
215 }
216
217 bool complete_object_copy(MockObjectCopyRequest &mock_object_copy_request,
218 uint64_t object_num, Context **object_ctx, int r) {
219 std::unique_lock locker{mock_object_copy_request.lock};
220 while (mock_object_copy_request.object_contexts.count(object_num) == 0) {
221 if (mock_object_copy_request.cond.wait_for(locker, 10s) ==
222 std::cv_status::timeout) {
223 return false;
224 }
225 }
226
227 if (object_ctx != nullptr) {
228 *object_ctx = mock_object_copy_request.object_contexts[object_num];
229 } else {
230 m_work_queue->queue(mock_object_copy_request.object_contexts[object_num],
231 r);
232 }
233 return true;
234 }
235
236 SnapMap wait_for_snap_map(MockObjectCopyRequest &mock_object_copy_request) {
237 std::unique_lock locker{mock_object_copy_request.lock};
238 while (mock_object_copy_request.snap_map == nullptr) {
239 if (mock_object_copy_request.cond.wait_for(locker, 10s) ==
240 std::cv_status::timeout) {
241 return SnapMap();
242 }
243 }
244 return *mock_object_copy_request.snap_map;
245 }
246
247 int create_snap(librbd::ImageCtx *image_ctx, const char* snap_name,
248 librados::snap_t *snap_id) {
249 int r = image_ctx->operations->snap_create(
250 cls::rbd::UserSnapshotNamespace(), snap_name);
251 if (r < 0) {
252 return r;
253 }
254
255 r = image_ctx->state->refresh();
256 if (r < 0) {
257 return r;
258 }
259
260 if (image_ctx->snap_ids.count({cls::rbd::UserSnapshotNamespace(),
261 snap_name}) == 0) {
262 return -ENOENT;
263 }
264
265 if (snap_id != nullptr) {
266 *snap_id = image_ctx->snap_ids[{cls::rbd::UserSnapshotNamespace(),
267 snap_name}];
268 }
269 return 0;
270 }
271
272 int create_snap(const char* snap_name,
273 librados::snap_t *src_snap_id_ = nullptr) {
274 librados::snap_t src_snap_id;
275 int r = create_snap(m_src_image_ctx, snap_name, &src_snap_id);
276 if (r < 0) {
277 return r;
278 }
279
280 if (src_snap_id_ != nullptr) {
281 *src_snap_id_ = src_snap_id;
282 }
283
284 librados::snap_t dst_snap_id;
285 r = create_snap(m_dst_image_ctx, snap_name, &dst_snap_id);
286 if (r < 0) {
287 return r;
288 }
289
290 // collection of all existing snaps in dst image
291 SnapIds dst_snap_ids({dst_snap_id});
292 if (!m_snap_map.empty()) {
293 dst_snap_ids.insert(dst_snap_ids.end(),
294 m_snap_map.rbegin()->second.begin(),
295 m_snap_map.rbegin()->second.end());
296 }
297 m_snap_map[src_snap_id] = dst_snap_ids;
298 m_snap_seqs[src_snap_id] = dst_snap_id;
299 return 0;
300 }
301 };
302
303 TEST_F(TestMockDeepCopyImageCopyRequest, SimpleImage) {
304 librados::snap_t snap_id_end;
305 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
306
307 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
308 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
309 MockObjectCopyRequest mock_object_copy_request;
310
311 InSequence seq;
312 MockDiffRequest mock_diff_request;
313 expect_diff_send(mock_diff_request, {}, -EINVAL);
314 expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order);
315 expect_get_image_size(mock_src_image_ctx, 0);
316 expect_object_copy_send(mock_object_copy_request);
317
318 librbd::deep_copy::NoOpHandler no_op;
319 C_SaferCond ctx;
320 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
321 &mock_dst_image_ctx,
322 0, snap_id_end, 0, false, boost::none,
323 m_snap_seqs, &no_op, &ctx);
324 request->send();
325
326 ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request));
327 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0));
328 ASSERT_EQ(0, ctx.wait());
329 }
330
331 TEST_F(TestMockDeepCopyImageCopyRequest, FastDiff) {
332 librados::snap_t snap_id_end;
333 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
334
335 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
336 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
337
338 InSequence seq;
339
340 MockDiffRequest mock_diff_request;
341 BitVector<2> diff_state;
342 diff_state.resize(1);
343 expect_diff_send(mock_diff_request, diff_state, 0);
344
345 expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order);
346 expect_get_image_size(mock_src_image_ctx, 0);
347
348 librbd::deep_copy::NoOpHandler no_op;
349 C_SaferCond ctx;
350 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
351 &mock_dst_image_ctx,
352 0, snap_id_end, 0, false, boost::none,
353 m_snap_seqs, &no_op, &ctx);
354 request->send();
355
356 ASSERT_EQ(0, ctx.wait());
357 }
358
359 TEST_F(TestMockDeepCopyImageCopyRequest, OutOfOrder) {
360 std::string max_ops_str;
361 ASSERT_EQ(0, _rados.conf_get("rbd_concurrent_management_ops", max_ops_str));
362 ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", "10"));
363 BOOST_SCOPE_EXIT( (max_ops_str) ) {
364 ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops",
365 max_ops_str.c_str()));
366 } BOOST_SCOPE_EXIT_END;
367
368 librados::snap_t snap_id_end;
369 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
370
371 uint64_t object_count = 55;
372
373 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
374 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
375 MockObjectCopyRequest mock_object_copy_request;
376
377 MockDiffRequest mock_diff_request;
378 expect_diff_send(mock_diff_request, {}, -EINVAL);
379 expect_get_image_size(mock_src_image_ctx,
380 object_count * (1 << m_src_image_ctx->order));
381 expect_get_image_size(mock_src_image_ctx, 0);
382
383 EXPECT_CALL(mock_object_copy_request, send()).Times(object_count);
384
385 class Handler : public librbd::deep_copy::NoOpHandler {
386 public:
387 uint64_t object_count;
388 librbd::deep_copy::ObjectNumber expected_object_number;
389
390 Handler(uint64_t object_count)
391 : object_count(object_count) {
392 }
393
394 int update_progress(uint64_t object_no, uint64_t end_object_no) override {
395 EXPECT_LE(object_no, object_count);
396 EXPECT_EQ(end_object_no, object_count);
397 if (!expected_object_number) {
398 expected_object_number = 0;
399 } else {
400 expected_object_number = *expected_object_number + 1;
401 }
402 EXPECT_EQ(*expected_object_number, object_no - 1);
403
404 return 0;
405 }
406 } handler(object_count);
407
408 C_SaferCond ctx;
409 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
410 &mock_dst_image_ctx,
411 0, snap_id_end, 0, false, boost::none,
412 m_snap_seqs, &handler, &ctx);
413 request->send();
414
415 std::map<uint64_t, Context*> copy_contexts;
416 ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request));
417 for (uint64_t i = 0; i < object_count; ++i) {
418 if (i % 10 == 0) {
419 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i,
420 &copy_contexts[i], 0));
421 } else {
422 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i, nullptr,
423 0));
424 }
425 }
426
427 for (auto& pair : copy_contexts) {
428 pair.second->complete(0);
429 }
430
431 ASSERT_EQ(0, ctx.wait());
432 }
433
434 TEST_F(TestMockDeepCopyImageCopyRequest, SnapshotSubset) {
435 librados::snap_t snap_id_start;
436 librados::snap_t snap_id_end;
437 ASSERT_EQ(0, create_snap("snap1"));
438 ASSERT_EQ(0, create_snap("snap2", &snap_id_start));
439 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
440
441 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
442 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
443 MockObjectCopyRequest mock_object_copy_request;
444
445 InSequence seq;
446 MockDiffRequest mock_diff_request;
447 expect_diff_send(mock_diff_request, {}, -EINVAL);
448 expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order);
449 expect_get_image_size(mock_src_image_ctx, 0);
450 expect_get_image_size(mock_src_image_ctx, 0);
451 expect_get_image_size(mock_src_image_ctx, 0);
452 expect_object_copy_send(mock_object_copy_request);
453
454 librbd::deep_copy::NoOpHandler no_op;
455 C_SaferCond ctx;
456 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
457 &mock_dst_image_ctx,
458 snap_id_start, snap_id_end, 0, false,
459 boost::none, m_snap_seqs, &no_op,
460 &ctx);
461 request->send();
462
463 SnapMap snap_map(m_snap_map);
464 snap_map.erase(snap_map.begin());
465 ASSERT_EQ(snap_map, wait_for_snap_map(mock_object_copy_request));
466
467 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0));
468 ASSERT_EQ(0, ctx.wait());
469 }
470
471 TEST_F(TestMockDeepCopyImageCopyRequest, RestartPartialSync) {
472 librados::snap_t snap_id_end;
473 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
474
475 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
476 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
477 MockObjectCopyRequest mock_object_copy_request;
478
479 InSequence seq;
480 MockDiffRequest mock_diff_request;
481 expect_diff_send(mock_diff_request, {}, -EINVAL);
482 expect_get_image_size(mock_src_image_ctx, 2 * (1 << m_src_image_ctx->order));
483 expect_get_image_size(mock_src_image_ctx, 0);
484 expect_object_copy_send(mock_object_copy_request);
485
486 librbd::deep_copy::NoOpHandler no_op;
487 C_SaferCond ctx;
488 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
489 &mock_dst_image_ctx,
490 0, snap_id_end, 0, false,
491 librbd::deep_copy::ObjectNumber{0U},
492 m_snap_seqs, &no_op, &ctx);
493 request->send();
494
495 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 1, nullptr, 0));
496 ASSERT_EQ(0, ctx.wait());
497 }
498
499 TEST_F(TestMockDeepCopyImageCopyRequest, Cancel) {
500 std::string max_ops_str;
501 ASSERT_EQ(0, _rados.conf_get("rbd_concurrent_management_ops", max_ops_str));
502 ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", "1"));
503 BOOST_SCOPE_EXIT( (max_ops_str) ) {
504 ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops",
505 max_ops_str.c_str()));
506 } BOOST_SCOPE_EXIT_END;
507
508 librados::snap_t snap_id_end;
509 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
510
511 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
512 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
513 MockObjectCopyRequest mock_object_copy_request;
514
515 InSequence seq;
516 MockDiffRequest mock_diff_request;
517 expect_diff_send(mock_diff_request, {}, -EINVAL);
518 expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order);
519 expect_get_image_size(mock_src_image_ctx, 0);
520 expect_object_copy_send(mock_object_copy_request);
521
522 librbd::deep_copy::NoOpHandler no_op;
523 C_SaferCond ctx;
524 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
525 &mock_dst_image_ctx,
526 0, snap_id_end, 0, false, boost::none,
527 m_snap_seqs, &no_op, &ctx);
528 request->send();
529
530 ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request));
531 request->cancel();
532
533 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0));
534 ASSERT_EQ(-ECANCELED, ctx.wait());
535 }
536
537 TEST_F(TestMockDeepCopyImageCopyRequest, Cancel_Inflight_Sync) {
538 std::string max_ops_str;
539 ASSERT_EQ(0, _rados.conf_get("rbd_concurrent_management_ops", max_ops_str));
540 ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", "3"));
541 BOOST_SCOPE_EXIT( (max_ops_str) ) {
542 ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops",
543 max_ops_str.c_str()));
544 } BOOST_SCOPE_EXIT_END;
545
546 librados::snap_t snap_id_end;
547 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
548
549 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
550 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
551 MockObjectCopyRequest mock_object_copy_request;
552
553 InSequence seq;
554 MockDiffRequest mock_diff_request;
555 expect_diff_send(mock_diff_request, {}, -EINVAL);
556 expect_get_image_size(mock_src_image_ctx, 6 * (1 << m_src_image_ctx->order));
557 expect_get_image_size(mock_src_image_ctx, m_image_size);
558
559 EXPECT_CALL(mock_object_copy_request, send()).Times(6);
560
561 struct Handler : public librbd::deep_copy::NoOpHandler {
562 librbd::deep_copy::ObjectNumber object_number;
563
564 int update_progress(uint64_t object_no, uint64_t end_object_no) override {
565 object_number = object_number ? *object_number + 1 : 0;
566 return 0;
567 }
568 } handler;
569
570 C_SaferCond ctx;
571 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
572 &mock_dst_image_ctx,
573 0, snap_id_end, 0, false, boost::none,
574 m_snap_seqs, &handler, &ctx);
575 request->send();
576
577 ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request));
578
579 Context *cancel_ctx = nullptr;
580 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0));
581 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 1, nullptr, 0));
582 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 2, nullptr, 0));
583 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 3, &cancel_ctx,
584 0));
585 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 4, nullptr, 0));
586 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 5, nullptr, 0));
587
588 request->cancel();
589 cancel_ctx->complete(0);
590
591 ASSERT_EQ(-ECANCELED, ctx.wait());
592 ASSERT_EQ(5u, handler.object_number.get());
593 }
594
595 TEST_F(TestMockDeepCopyImageCopyRequest, MissingSnap) {
596 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
597 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
598
599 librbd::deep_copy::NoOpHandler no_op;
600 C_SaferCond ctx;
601 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
602 &mock_dst_image_ctx,
603 0, 123, 0, false, boost::none,
604 m_snap_seqs, &no_op, &ctx);
605 request->send();
606 ASSERT_EQ(-EINVAL, ctx.wait());
607 }
608
609 TEST_F(TestMockDeepCopyImageCopyRequest, MissingFromSnap) {
610 librados::snap_t snap_id_end;
611 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
612
613 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
614 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
615
616 librbd::deep_copy::NoOpHandler no_op;
617 C_SaferCond ctx;
618 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
619 &mock_dst_image_ctx,
620 123, snap_id_end, 0, false,
621 boost::none, m_snap_seqs, &no_op,
622 &ctx);
623 request->send();
624 ASSERT_EQ(-EINVAL, ctx.wait());
625 }
626
627 TEST_F(TestMockDeepCopyImageCopyRequest, EmptySnapMap) {
628 librados::snap_t snap_id_start;
629 librados::snap_t snap_id_end;
630 ASSERT_EQ(0, create_snap("snap1", &snap_id_start));
631 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
632
633 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
634 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
635
636 librbd::deep_copy::NoOpHandler no_op;
637 C_SaferCond ctx;
638 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
639 &mock_dst_image_ctx,
640 snap_id_start, snap_id_end, 0, false,
641 boost::none, {{0, 0}}, &no_op, &ctx);
642 request->send();
643 ASSERT_EQ(-EINVAL, ctx.wait());
644 }
645
646 TEST_F(TestMockDeepCopyImageCopyRequest, EmptySnapSeqs) {
647 librados::snap_t snap_id_start;
648 librados::snap_t snap_id_end;
649 ASSERT_EQ(0, create_snap("snap1", &snap_id_start));
650 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
651
652 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
653 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
654
655 librbd::deep_copy::NoOpHandler no_op;
656 C_SaferCond ctx;
657 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
658 &mock_dst_image_ctx,
659 snap_id_start, snap_id_end, 0, false,
660 boost::none, {}, &no_op, &ctx);
661 request->send();
662 ASSERT_EQ(-EINVAL, ctx.wait());
663 }
664
665 } // namespace deep_copy
666 } // namespace librbd