1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/librbd/test_mock_fixture.h"
5 #include "include/rbd/librbd.hpp"
6 #include "librbd/AsioEngine.h"
7 #include "librbd/ImageCtx.h"
8 #include "librbd/ImageState.h"
9 #include "librbd/internal.h"
10 #include "librbd/Operations.h"
11 #include "librbd/deep_copy/Handler.h"
12 #include "librbd/deep_copy/ImageCopyRequest.h"
13 #include "librbd/deep_copy/ObjectCopyRequest.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>
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
,
30 ceph_assert(s_instance
!= nullptr);
34 explicit MockTestImageCtx(librbd::ImageCtx
&image_ctx
)
35 : librbd::MockImageCtx(image_ctx
) {
39 MOCK_METHOD0(destroy
, void());
42 MockTestImageCtx
* MockTestImageCtx::s_instance
= nullptr;
44 } // anonymous namespace
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
, uint32_t flags
, Handler
* handler
,
59 ceph_assert(s_instance
!= nullptr);
60 std::lock_guard locker
{s_instance
->lock
};
61 s_instance
->snap_map
= &snap_map
;
62 s_instance
->flags
= flags
;
63 s_instance
->object_contexts
[object_number
] = on_finish
;
64 s_instance
->cond
.notify_all();
68 MOCK_METHOD0(send
, void());
70 ceph::mutex lock
= ceph::make_mutex("lock");
71 ceph::condition_variable cond
;
73 const SnapMap
*snap_map
= nullptr;
74 std::map
<uint64_t, Context
*> object_contexts
;
82 ObjectCopyRequest
<librbd::MockTestImageCtx
>* ObjectCopyRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
84 } // namespace deep_copy
86 namespace object_map
{
89 struct DiffRequest
<MockTestImageCtx
> {
90 BitVector
<2>* object_diff_state
= nullptr;
91 Context
* on_finish
= nullptr;
92 static DiffRequest
* s_instance
;
93 static DiffRequest
* create(MockTestImageCtx
*image_ctx
,
94 uint64_t snap_id_start
, uint64_t snap_id_end
,
95 BitVector
<2>* object_diff_state
,
97 ceph_assert(s_instance
!= nullptr);
98 s_instance
->object_diff_state
= object_diff_state
;
99 s_instance
->on_finish
= on_finish
;
107 MOCK_METHOD0(send
, void());
110 DiffRequest
<MockTestImageCtx
>* DiffRequest
<MockTestImageCtx
>::s_instance
= nullptr;
112 } // namespace object_map
113 } // namespace librbd
115 // template definitions
116 #include "librbd/deep_copy/ImageCopyRequest.cc"
117 template class librbd::deep_copy::ImageCopyRequest
<librbd::MockTestImageCtx
>;
120 namespace deep_copy
{
123 using ::testing::InSequence
;
124 using ::testing::Invoke
;
125 using ::testing::Return
;
127 class TestMockDeepCopyImageCopyRequest
: public TestMockFixture
{
129 typedef ImageCopyRequest
<librbd::MockTestImageCtx
> MockImageCopyRequest
;
130 typedef ObjectCopyRequest
<librbd::MockTestImageCtx
> MockObjectCopyRequest
;
131 typedef object_map::DiffRequest
<librbd::MockTestImageCtx
> MockDiffRequest
;
133 librbd::ImageCtx
*m_src_image_ctx
;
134 librbd::ImageCtx
*m_dst_image_ctx
;
136 std::shared_ptr
<librbd::AsioEngine
> m_asio_engine
;
137 asio::ContextWQ
*m_work_queue
;
139 librbd::SnapSeqs m_snap_seqs
;
142 void SetUp() override
{
143 TestMockFixture::SetUp();
145 ASSERT_EQ(0, open_image(m_image_name
, &m_src_image_ctx
));
148 std::string dst_image_name
= get_temp_image_name();
149 ASSERT_EQ(0, create_image_pp(rbd
, m_ioctx
, dst_image_name
, m_image_size
));
150 ASSERT_EQ(0, open_image(dst_image_name
, &m_dst_image_ctx
));
152 m_asio_engine
= std::make_shared
<librbd::AsioEngine
>(
153 m_src_image_ctx
->md_ctx
);
154 m_work_queue
= m_asio_engine
->get_work_queue();
157 void expect_get_image_size(librbd::MockTestImageCtx
&mock_image_ctx
,
159 EXPECT_CALL(mock_image_ctx
, get_image_size(_
))
160 .WillOnce(Return(size
)).RetiresOnSaturation();
163 void expect_diff_send(MockDiffRequest
& mock_request
,
164 const BitVector
<2>& diff_state
, int r
) {
165 EXPECT_CALL(mock_request
, send())
166 .WillOnce(Invoke([this, &mock_request
, diff_state
, r
]() {
168 *mock_request
.object_diff_state
= diff_state
;
170 m_work_queue
->queue(mock_request
.on_finish
, r
);
174 void expect_object_copy_send(MockObjectCopyRequest
&mock_object_copy_request
,
176 EXPECT_CALL(mock_object_copy_request
, send())
177 .WillOnce(Invoke([&mock_object_copy_request
, flags
]() {
178 ASSERT_EQ(flags
, mock_object_copy_request
.flags
);
182 bool complete_object_copy(MockObjectCopyRequest
&mock_object_copy_request
,
183 uint64_t object_num
, Context
**object_ctx
, int r
) {
184 std::unique_lock locker
{mock_object_copy_request
.lock
};
185 while (mock_object_copy_request
.object_contexts
.count(object_num
) == 0) {
186 if (mock_object_copy_request
.cond
.wait_for(locker
, 10s
) ==
187 std::cv_status::timeout
) {
192 if (object_ctx
!= nullptr) {
193 *object_ctx
= mock_object_copy_request
.object_contexts
[object_num
];
195 m_work_queue
->queue(mock_object_copy_request
.object_contexts
[object_num
],
201 SnapMap
wait_for_snap_map(MockObjectCopyRequest
&mock_object_copy_request
) {
202 std::unique_lock locker
{mock_object_copy_request
.lock
};
203 while (mock_object_copy_request
.snap_map
== nullptr) {
204 if (mock_object_copy_request
.cond
.wait_for(locker
, 10s
) ==
205 std::cv_status::timeout
) {
209 return *mock_object_copy_request
.snap_map
;
212 int create_snap(librbd::ImageCtx
*image_ctx
, const char* snap_name
,
213 librados::snap_t
*snap_id
) {
214 NoOpProgressContext prog_ctx
;
215 int r
= image_ctx
->operations
->snap_create(
216 cls::rbd::UserSnapshotNamespace(), snap_name
, 0, prog_ctx
);
221 r
= image_ctx
->state
->refresh();
226 if (image_ctx
->snap_ids
.count({cls::rbd::UserSnapshotNamespace(),
231 if (snap_id
!= nullptr) {
232 *snap_id
= image_ctx
->snap_ids
[{cls::rbd::UserSnapshotNamespace(),
238 int create_snap(const char* snap_name
,
239 librados::snap_t
*src_snap_id_
= nullptr) {
240 librados::snap_t src_snap_id
;
241 int r
= create_snap(m_src_image_ctx
, snap_name
, &src_snap_id
);
246 if (src_snap_id_
!= nullptr) {
247 *src_snap_id_
= src_snap_id
;
250 librados::snap_t dst_snap_id
;
251 r
= create_snap(m_dst_image_ctx
, snap_name
, &dst_snap_id
);
256 // collection of all existing snaps in dst image
257 SnapIds
dst_snap_ids({dst_snap_id
});
258 if (!m_snap_map
.empty()) {
259 dst_snap_ids
.insert(dst_snap_ids
.end(),
260 m_snap_map
.rbegin()->second
.begin(),
261 m_snap_map
.rbegin()->second
.end());
263 m_snap_map
[src_snap_id
] = dst_snap_ids
;
264 m_snap_seqs
[src_snap_id
] = dst_snap_id
;
269 TEST_F(TestMockDeepCopyImageCopyRequest
, SimpleImage
) {
270 librados::snap_t snap_id_end
;
271 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
273 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
274 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
275 MockObjectCopyRequest mock_object_copy_request
;
278 MockDiffRequest mock_diff_request
;
279 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
280 expect_get_image_size(mock_src_image_ctx
, 1 << m_src_image_ctx
->order
);
281 expect_get_image_size(mock_src_image_ctx
, 0);
282 expect_object_copy_send(mock_object_copy_request
, 0);
284 librbd::deep_copy::NoOpHandler no_op
;
286 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
288 0, snap_id_end
, 0, false, boost::none
,
289 m_snap_seqs
, &no_op
, &ctx
);
292 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
293 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
294 ASSERT_EQ(0, ctx
.wait());
297 TEST_F(TestMockDeepCopyImageCopyRequest
, FastDiffNonExistent
) {
298 librados::snap_t snap_id_end
;
299 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
301 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
302 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
306 MockDiffRequest mock_diff_request
;
307 BitVector
<2> diff_state
;
308 diff_state
.resize(1);
309 expect_diff_send(mock_diff_request
, diff_state
, 0);
311 expect_get_image_size(mock_src_image_ctx
, 1 << m_src_image_ctx
->order
);
312 expect_get_image_size(mock_src_image_ctx
, 0);
314 librbd::deep_copy::NoOpHandler no_op
;
316 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
318 0, snap_id_end
, 0, false, boost::none
,
319 m_snap_seqs
, &no_op
, &ctx
);
322 ASSERT_EQ(0, ctx
.wait());
325 TEST_F(TestMockDeepCopyImageCopyRequest
, FastDiffExistsDirty
) {
326 librados::snap_t snap_id_end
;
327 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
329 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
330 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
334 MockDiffRequest mock_diff_request
;
335 BitVector
<2> diff_state
;
336 diff_state
.resize(1);
337 diff_state
[0] = object_map::DIFF_STATE_DATA_UPDATED
;
338 expect_diff_send(mock_diff_request
, diff_state
, 0);
340 expect_get_image_size(mock_src_image_ctx
, 1 << m_src_image_ctx
->order
);
341 expect_get_image_size(mock_src_image_ctx
, 0);
342 MockObjectCopyRequest mock_object_copy_request
;
343 expect_object_copy_send(mock_object_copy_request
, 0);
345 librbd::deep_copy::NoOpHandler no_op
;
347 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
349 0, snap_id_end
, 0, false, boost::none
,
350 m_snap_seqs
, &no_op
, &ctx
);
353 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
354 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
355 ASSERT_EQ(0, ctx
.wait());
358 TEST_F(TestMockDeepCopyImageCopyRequest
, FastDiffExistsClean
) {
359 librados::snap_t snap_id_end
;
360 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
362 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
363 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
367 MockDiffRequest mock_diff_request
;
368 BitVector
<2> diff_state
;
369 diff_state
.resize(1);
370 diff_state
[0] = object_map::DIFF_STATE_DATA
;
371 expect_diff_send(mock_diff_request
, diff_state
, 0);
373 expect_get_image_size(mock_src_image_ctx
, 1 << m_src_image_ctx
->order
);
374 expect_get_image_size(mock_src_image_ctx
, 0);
375 MockObjectCopyRequest mock_object_copy_request
;
376 expect_object_copy_send(mock_object_copy_request
,
377 OBJECT_COPY_REQUEST_FLAG_EXISTS_CLEAN
);
379 librbd::deep_copy::NoOpHandler no_op
;
381 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
383 0, snap_id_end
, 0, false, boost::none
,
384 m_snap_seqs
, &no_op
, &ctx
);
387 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
388 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
389 ASSERT_EQ(0, ctx
.wait());
392 TEST_F(TestMockDeepCopyImageCopyRequest
, OutOfOrder
) {
393 std::string max_ops_str
;
394 ASSERT_EQ(0, _rados
.conf_get("rbd_concurrent_management_ops", max_ops_str
));
395 ASSERT_EQ(0, _rados
.conf_set("rbd_concurrent_management_ops", "10"));
396 BOOST_SCOPE_EXIT( (max_ops_str
) ) {
397 ASSERT_EQ(0, _rados
.conf_set("rbd_concurrent_management_ops",
398 max_ops_str
.c_str()));
399 } BOOST_SCOPE_EXIT_END
;
401 librados::snap_t snap_id_end
;
402 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
404 uint64_t object_count
= 55;
406 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
407 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
408 MockObjectCopyRequest mock_object_copy_request
;
410 MockDiffRequest mock_diff_request
;
411 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
412 expect_get_image_size(mock_src_image_ctx
,
413 object_count
* (1 << m_src_image_ctx
->order
));
414 expect_get_image_size(mock_src_image_ctx
, 0);
416 EXPECT_CALL(mock_object_copy_request
, send()).Times(object_count
);
418 class Handler
: public librbd::deep_copy::NoOpHandler
{
420 uint64_t object_count
;
421 librbd::deep_copy::ObjectNumber expected_object_number
;
423 Handler(uint64_t object_count
)
424 : object_count(object_count
) {
427 int update_progress(uint64_t object_no
, uint64_t end_object_no
) override
{
428 EXPECT_LE(object_no
, object_count
);
429 EXPECT_EQ(end_object_no
, object_count
);
430 if (!expected_object_number
) {
431 expected_object_number
= 0;
433 expected_object_number
= *expected_object_number
+ 1;
435 EXPECT_EQ(*expected_object_number
, object_no
- 1);
439 } handler(object_count
);
442 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
444 0, snap_id_end
, 0, false, boost::none
,
445 m_snap_seqs
, &handler
, &ctx
);
448 std::map
<uint64_t, Context
*> copy_contexts
;
449 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
450 for (uint64_t i
= 0; i
< object_count
; ++i
) {
452 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, i
,
453 ©_contexts
[i
], 0));
455 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, i
, nullptr,
460 for (auto& pair
: copy_contexts
) {
461 pair
.second
->complete(0);
464 ASSERT_EQ(0, ctx
.wait());
467 TEST_F(TestMockDeepCopyImageCopyRequest
, SnapshotSubset
) {
468 librados::snap_t snap_id_start
;
469 librados::snap_t snap_id_end
;
470 ASSERT_EQ(0, create_snap("snap1"));
471 ASSERT_EQ(0, create_snap("snap2", &snap_id_start
));
472 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
474 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
475 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
476 MockObjectCopyRequest mock_object_copy_request
;
479 MockDiffRequest mock_diff_request
;
480 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
481 expect_get_image_size(mock_src_image_ctx
, 1 << m_src_image_ctx
->order
);
482 expect_get_image_size(mock_src_image_ctx
, 0);
483 expect_get_image_size(mock_src_image_ctx
, 0);
484 expect_get_image_size(mock_src_image_ctx
, 0);
485 expect_object_copy_send(mock_object_copy_request
, 0);
487 librbd::deep_copy::NoOpHandler no_op
;
489 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
491 snap_id_start
, snap_id_end
, 0, false,
492 boost::none
, m_snap_seqs
, &no_op
,
496 SnapMap
snap_map(m_snap_map
);
497 snap_map
.erase(snap_map
.begin());
498 ASSERT_EQ(snap_map
, wait_for_snap_map(mock_object_copy_request
));
500 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
501 ASSERT_EQ(0, ctx
.wait());
504 TEST_F(TestMockDeepCopyImageCopyRequest
, RestartPartialSync
) {
505 librados::snap_t snap_id_end
;
506 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
508 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
509 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
510 MockObjectCopyRequest mock_object_copy_request
;
513 MockDiffRequest mock_diff_request
;
514 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
515 expect_get_image_size(mock_src_image_ctx
, 2 * (1 << m_src_image_ctx
->order
));
516 expect_get_image_size(mock_src_image_ctx
, 0);
517 expect_object_copy_send(mock_object_copy_request
, 0);
519 librbd::deep_copy::NoOpHandler no_op
;
521 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
523 0, snap_id_end
, 0, false,
524 librbd::deep_copy::ObjectNumber
{0U},
525 m_snap_seqs
, &no_op
, &ctx
);
528 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 1, nullptr, 0));
529 ASSERT_EQ(0, ctx
.wait());
532 TEST_F(TestMockDeepCopyImageCopyRequest
, Cancel
) {
533 std::string max_ops_str
;
534 ASSERT_EQ(0, _rados
.conf_get("rbd_concurrent_management_ops", max_ops_str
));
535 ASSERT_EQ(0, _rados
.conf_set("rbd_concurrent_management_ops", "1"));
536 BOOST_SCOPE_EXIT( (max_ops_str
) ) {
537 ASSERT_EQ(0, _rados
.conf_set("rbd_concurrent_management_ops",
538 max_ops_str
.c_str()));
539 } BOOST_SCOPE_EXIT_END
;
541 librados::snap_t snap_id_end
;
542 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
544 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
545 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
546 MockObjectCopyRequest mock_object_copy_request
;
549 MockDiffRequest mock_diff_request
;
550 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
551 expect_get_image_size(mock_src_image_ctx
, 1 << m_src_image_ctx
->order
);
552 expect_get_image_size(mock_src_image_ctx
, 0);
553 expect_object_copy_send(mock_object_copy_request
, 0);
555 librbd::deep_copy::NoOpHandler no_op
;
557 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
559 0, snap_id_end
, 0, false, boost::none
,
560 m_snap_seqs
, &no_op
, &ctx
);
563 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
566 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
567 ASSERT_EQ(-ECANCELED
, ctx
.wait());
570 TEST_F(TestMockDeepCopyImageCopyRequest
, Cancel_Inflight_Sync
) {
571 std::string max_ops_str
;
572 ASSERT_EQ(0, _rados
.conf_get("rbd_concurrent_management_ops", max_ops_str
));
573 ASSERT_EQ(0, _rados
.conf_set("rbd_concurrent_management_ops", "3"));
574 BOOST_SCOPE_EXIT( (max_ops_str
) ) {
575 ASSERT_EQ(0, _rados
.conf_set("rbd_concurrent_management_ops",
576 max_ops_str
.c_str()));
577 } BOOST_SCOPE_EXIT_END
;
579 librados::snap_t snap_id_end
;
580 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
582 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
583 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
584 MockObjectCopyRequest mock_object_copy_request
;
587 MockDiffRequest mock_diff_request
;
588 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
589 expect_get_image_size(mock_src_image_ctx
, 6 * (1 << m_src_image_ctx
->order
));
590 expect_get_image_size(mock_src_image_ctx
, m_image_size
);
592 EXPECT_CALL(mock_object_copy_request
, send()).Times(6);
594 struct Handler
: public librbd::deep_copy::NoOpHandler
{
595 librbd::deep_copy::ObjectNumber object_number
;
597 int update_progress(uint64_t object_no
, uint64_t end_object_no
) override
{
598 object_number
= object_number
? *object_number
+ 1 : 0;
604 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
606 0, snap_id_end
, 0, false, boost::none
,
607 m_snap_seqs
, &handler
, &ctx
);
610 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
612 Context
*cancel_ctx
= nullptr;
613 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
614 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 1, nullptr, 0));
615 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 2, nullptr, 0));
616 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 3, &cancel_ctx
,
618 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 4, nullptr, 0));
619 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 5, nullptr, 0));
622 cancel_ctx
->complete(0);
624 ASSERT_EQ(-ECANCELED
, ctx
.wait());
625 ASSERT_EQ(5u, handler
.object_number
.get());
628 TEST_F(TestMockDeepCopyImageCopyRequest
, MissingSnap
) {
629 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
630 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
632 librbd::deep_copy::NoOpHandler no_op
;
634 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
636 0, 123, 0, false, boost::none
,
637 m_snap_seqs
, &no_op
, &ctx
);
639 ASSERT_EQ(-EINVAL
, ctx
.wait());
642 TEST_F(TestMockDeepCopyImageCopyRequest
, MissingFromSnap
) {
643 librados::snap_t snap_id_end
;
644 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
646 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
647 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
649 librbd::deep_copy::NoOpHandler no_op
;
651 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
653 123, snap_id_end
, 0, false,
654 boost::none
, m_snap_seqs
, &no_op
,
657 ASSERT_EQ(-EINVAL
, ctx
.wait());
660 TEST_F(TestMockDeepCopyImageCopyRequest
, EmptySnapMap
) {
661 librados::snap_t snap_id_start
;
662 librados::snap_t snap_id_end
;
663 ASSERT_EQ(0, create_snap("snap1", &snap_id_start
));
664 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
666 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
667 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
669 librbd::deep_copy::NoOpHandler no_op
;
671 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
673 snap_id_start
, snap_id_end
, 0, false,
674 boost::none
, {{0, 0}}, &no_op
, &ctx
);
676 ASSERT_EQ(-EINVAL
, ctx
.wait());
679 TEST_F(TestMockDeepCopyImageCopyRequest
, EmptySnapSeqs
) {
680 librados::snap_t snap_id_start
;
681 librados::snap_t snap_id_end
;
682 ASSERT_EQ(0, create_snap("snap1", &snap_id_start
));
683 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
685 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
686 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
688 librbd::deep_copy::NoOpHandler no_op
;
690 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
692 snap_id_start
, snap_id_end
, 0, false,
693 boost::none
, {}, &no_op
, &ctx
);
695 ASSERT_EQ(-EINVAL
, ctx
.wait());
698 } // namespace deep_copy
699 } // namespace librbd