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