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
>;
119 using namespace std::chrono_literals
;
122 namespace deep_copy
{
125 using ::testing::InSequence
;
126 using ::testing::Invoke
;
127 using ::testing::Return
;
129 class TestMockDeepCopyImageCopyRequest
: public TestMockFixture
{
131 typedef ImageCopyRequest
<librbd::MockTestImageCtx
> MockImageCopyRequest
;
132 typedef ObjectCopyRequest
<librbd::MockTestImageCtx
> MockObjectCopyRequest
;
133 typedef object_map::DiffRequest
<librbd::MockTestImageCtx
> MockDiffRequest
;
135 librbd::ImageCtx
*m_src_image_ctx
;
136 librbd::ImageCtx
*m_dst_image_ctx
;
138 std::shared_ptr
<librbd::AsioEngine
> m_asio_engine
;
139 asio::ContextWQ
*m_work_queue
;
141 librbd::SnapSeqs m_snap_seqs
;
144 void SetUp() override
{
145 TestMockFixture::SetUp();
147 ASSERT_EQ(0, open_image(m_image_name
, &m_src_image_ctx
));
150 std::string dst_image_name
= get_temp_image_name();
151 ASSERT_EQ(0, create_image_pp(rbd
, m_ioctx
, dst_image_name
, m_image_size
));
152 ASSERT_EQ(0, open_image(dst_image_name
, &m_dst_image_ctx
));
154 m_asio_engine
= std::make_shared
<librbd::AsioEngine
>(
155 m_src_image_ctx
->md_ctx
);
156 m_work_queue
= m_asio_engine
->get_work_queue();
159 void expect_get_image_size(librbd::MockTestImageCtx
&mock_image_ctx
,
161 EXPECT_CALL(mock_image_ctx
, get_image_size(_
))
162 .WillOnce(Return(size
)).RetiresOnSaturation();
165 void expect_diff_send(MockDiffRequest
& mock_request
,
166 const BitVector
<2>& diff_state
, int r
) {
167 EXPECT_CALL(mock_request
, send())
168 .WillOnce(Invoke([this, &mock_request
, diff_state
, r
]() {
170 *mock_request
.object_diff_state
= diff_state
;
172 m_work_queue
->queue(mock_request
.on_finish
, r
);
176 void expect_object_copy_send(MockObjectCopyRequest
&mock_object_copy_request
,
178 EXPECT_CALL(mock_object_copy_request
, send())
179 .WillOnce(Invoke([&mock_object_copy_request
, flags
]() {
180 ASSERT_EQ(flags
, mock_object_copy_request
.flags
);
184 bool complete_object_copy(MockObjectCopyRequest
&mock_object_copy_request
,
185 uint64_t object_num
, Context
**object_ctx
, int r
) {
186 std::unique_lock locker
{mock_object_copy_request
.lock
};
187 while (mock_object_copy_request
.object_contexts
.count(object_num
) == 0) {
188 if (mock_object_copy_request
.cond
.wait_for(locker
, 10s
) ==
189 std::cv_status::timeout
) {
194 if (object_ctx
!= nullptr) {
195 *object_ctx
= mock_object_copy_request
.object_contexts
[object_num
];
197 m_work_queue
->queue(mock_object_copy_request
.object_contexts
[object_num
],
203 SnapMap
wait_for_snap_map(MockObjectCopyRequest
&mock_object_copy_request
) {
204 std::unique_lock locker
{mock_object_copy_request
.lock
};
205 while (mock_object_copy_request
.snap_map
== nullptr) {
206 if (mock_object_copy_request
.cond
.wait_for(locker
, 10s
) ==
207 std::cv_status::timeout
) {
211 return *mock_object_copy_request
.snap_map
;
214 int create_snap(librbd::ImageCtx
*image_ctx
, const char* snap_name
,
215 librados::snap_t
*snap_id
) {
216 NoOpProgressContext prog_ctx
;
217 int r
= image_ctx
->operations
->snap_create(
218 cls::rbd::UserSnapshotNamespace(), snap_name
, 0, prog_ctx
);
223 r
= image_ctx
->state
->refresh();
228 if (image_ctx
->snap_ids
.count({cls::rbd::UserSnapshotNamespace(),
233 if (snap_id
!= nullptr) {
234 *snap_id
= image_ctx
->snap_ids
[{cls::rbd::UserSnapshotNamespace(),
240 int create_snap(const char* snap_name
,
241 librados::snap_t
*src_snap_id_
= nullptr) {
242 librados::snap_t src_snap_id
;
243 int r
= create_snap(m_src_image_ctx
, snap_name
, &src_snap_id
);
248 if (src_snap_id_
!= nullptr) {
249 *src_snap_id_
= src_snap_id
;
252 librados::snap_t dst_snap_id
;
253 r
= create_snap(m_dst_image_ctx
, snap_name
, &dst_snap_id
);
258 // collection of all existing snaps in dst image
259 SnapIds
dst_snap_ids({dst_snap_id
});
260 if (!m_snap_map
.empty()) {
261 dst_snap_ids
.insert(dst_snap_ids
.end(),
262 m_snap_map
.rbegin()->second
.begin(),
263 m_snap_map
.rbegin()->second
.end());
265 m_snap_map
[src_snap_id
] = dst_snap_ids
;
266 m_snap_seqs
[src_snap_id
] = dst_snap_id
;
271 TEST_F(TestMockDeepCopyImageCopyRequest
, SimpleImage
) {
272 librados::snap_t snap_id_end
;
273 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
275 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
276 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
277 MockObjectCopyRequest mock_object_copy_request
;
280 MockDiffRequest mock_diff_request
;
281 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
282 expect_get_image_size(mock_src_image_ctx
, 1 << m_src_image_ctx
->order
);
283 expect_get_image_size(mock_src_image_ctx
, 0);
284 expect_object_copy_send(mock_object_copy_request
, 0);
286 librbd::deep_copy::NoOpHandler no_op
;
288 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
290 0, snap_id_end
, 0, false, boost::none
,
291 m_snap_seqs
, &no_op
, &ctx
);
294 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
295 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
296 ASSERT_EQ(0, ctx
.wait());
299 TEST_F(TestMockDeepCopyImageCopyRequest
, FastDiffNonExistent
) {
300 librados::snap_t snap_id_end
;
301 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
303 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
304 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
308 MockDiffRequest mock_diff_request
;
309 BitVector
<2> diff_state
;
310 diff_state
.resize(1);
311 expect_diff_send(mock_diff_request
, diff_state
, 0);
313 expect_get_image_size(mock_src_image_ctx
, 1 << m_src_image_ctx
->order
);
314 expect_get_image_size(mock_src_image_ctx
, 0);
315 expect_op_work_queue(mock_src_image_ctx
);
317 librbd::deep_copy::NoOpHandler no_op
;
319 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
321 0, snap_id_end
, 0, false, boost::none
,
322 m_snap_seqs
, &no_op
, &ctx
);
325 ASSERT_EQ(0, ctx
.wait());
328 TEST_F(TestMockDeepCopyImageCopyRequest
, FastDiffExistsDirty
) {
329 librados::snap_t snap_id_end
;
330 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
332 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
333 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
337 MockDiffRequest mock_diff_request
;
338 BitVector
<2> diff_state
;
339 diff_state
.resize(1);
340 diff_state
[0] = object_map::DIFF_STATE_DATA_UPDATED
;
341 expect_diff_send(mock_diff_request
, diff_state
, 0);
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 MockObjectCopyRequest mock_object_copy_request
;
346 expect_object_copy_send(mock_object_copy_request
, 0);
348 librbd::deep_copy::NoOpHandler no_op
;
350 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
352 0, snap_id_end
, 0, false, boost::none
,
353 m_snap_seqs
, &no_op
, &ctx
);
356 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
357 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
358 ASSERT_EQ(0, ctx
.wait());
361 TEST_F(TestMockDeepCopyImageCopyRequest
, FastDiffExistsClean
) {
362 librados::snap_t snap_id_end
;
363 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
365 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
366 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
370 MockDiffRequest mock_diff_request
;
371 BitVector
<2> diff_state
;
372 diff_state
.resize(1);
373 diff_state
[0] = object_map::DIFF_STATE_DATA
;
374 expect_diff_send(mock_diff_request
, diff_state
, 0);
376 expect_get_image_size(mock_src_image_ctx
, 1 << m_src_image_ctx
->order
);
377 expect_get_image_size(mock_src_image_ctx
, 0);
378 MockObjectCopyRequest mock_object_copy_request
;
379 expect_object_copy_send(mock_object_copy_request
,
380 OBJECT_COPY_REQUEST_FLAG_EXISTS_CLEAN
);
382 librbd::deep_copy::NoOpHandler no_op
;
384 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
386 0, snap_id_end
, 0, false, boost::none
,
387 m_snap_seqs
, &no_op
, &ctx
);
390 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
391 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
392 ASSERT_EQ(0, ctx
.wait());
395 TEST_F(TestMockDeepCopyImageCopyRequest
, FastDiffMix
) {
396 librados::snap_t snap_id_end
;
397 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
399 uint64_t object_count
= 12;
401 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
402 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
403 MockObjectCopyRequest mock_object_copy_request
;
407 MockDiffRequest mock_diff_request
;
408 BitVector
<2> diff_state
;
409 diff_state
.resize(object_count
);
410 diff_state
[1] = object_map::DIFF_STATE_DATA_UPDATED
;
411 diff_state
[2] = object_map::DIFF_STATE_DATA_UPDATED
;
412 diff_state
[3] = object_map::DIFF_STATE_DATA
;
413 diff_state
[5] = object_map::DIFF_STATE_DATA_UPDATED
;
414 diff_state
[8] = object_map::DIFF_STATE_DATA
;
415 diff_state
[9] = object_map::DIFF_STATE_DATA
;
416 diff_state
[10] = object_map::DIFF_STATE_DATA_UPDATED
;
417 expect_diff_send(mock_diff_request
, diff_state
, 0);
419 expect_get_image_size(mock_src_image_ctx
,
420 object_count
* (1 << m_src_image_ctx
->order
));
421 expect_get_image_size(mock_src_image_ctx
, 0);
423 expect_op_work_queue(mock_src_image_ctx
);
424 expect_object_copy_send(mock_object_copy_request
, 0);
425 expect_object_copy_send(mock_object_copy_request
, 0);
426 expect_object_copy_send(mock_object_copy_request
,
427 OBJECT_COPY_REQUEST_FLAG_EXISTS_CLEAN
);
428 expect_op_work_queue(mock_src_image_ctx
);
429 expect_object_copy_send(mock_object_copy_request
, 0);
430 expect_op_work_queue(mock_src_image_ctx
);
431 expect_object_copy_send(mock_object_copy_request
,
432 OBJECT_COPY_REQUEST_FLAG_EXISTS_CLEAN
);
433 expect_object_copy_send(mock_object_copy_request
,
434 OBJECT_COPY_REQUEST_FLAG_EXISTS_CLEAN
);
435 expect_object_copy_send(mock_object_copy_request
, 0);
436 expect_op_work_queue(mock_src_image_ctx
);
438 std::vector
<bool> seen(object_count
);
439 struct Handler
: public librbd::deep_copy::NoOpHandler
{
440 Handler(std::vector
<bool>* seen
) : m_seen(seen
) {}
442 int update_progress(uint64_t object_no
, uint64_t end_object_no
) override
{
443 EXPECT_THAT(object_no
, ::testing::AllOf(::testing::Ge(1),
444 ::testing::Le(m_seen
->size())));
445 EXPECT_EQ(end_object_no
, m_seen
->size());
446 EXPECT_FALSE((*m_seen
)[object_no
- 1]);
447 (*m_seen
)[object_no
- 1] = true;
451 std::vector
<bool>* m_seen
;
455 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
457 0, snap_id_end
, 0, false, boost::none
,
458 m_snap_seqs
, &handler
, &ctx
);
461 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
462 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 1, nullptr, 0));
463 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 2, nullptr, 0));
464 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 3, nullptr, 0));
465 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 5, nullptr, 0));
466 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 8, nullptr, 0));
467 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 9, nullptr, 0));
468 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 10, nullptr, 0));
469 ASSERT_EQ(0, ctx
.wait());
471 EXPECT_THAT(seen
, ::testing::Each(::testing::IsTrue()));
474 TEST_F(TestMockDeepCopyImageCopyRequest
, OutOfOrder
) {
475 std::string max_ops_str
;
476 ASSERT_EQ(0, _rados
.conf_get("rbd_concurrent_management_ops", max_ops_str
));
477 ASSERT_EQ(0, _rados
.conf_set("rbd_concurrent_management_ops", "10"));
478 BOOST_SCOPE_EXIT( (max_ops_str
) ) {
479 ASSERT_EQ(0, _rados
.conf_set("rbd_concurrent_management_ops",
480 max_ops_str
.c_str()));
481 } BOOST_SCOPE_EXIT_END
;
483 librados::snap_t snap_id_end
;
484 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
486 uint64_t object_count
= 55;
488 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
489 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
490 MockObjectCopyRequest mock_object_copy_request
;
492 MockDiffRequest mock_diff_request
;
493 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
494 expect_get_image_size(mock_src_image_ctx
,
495 object_count
* (1 << m_src_image_ctx
->order
));
496 expect_get_image_size(mock_src_image_ctx
, 0);
498 EXPECT_CALL(mock_object_copy_request
, send()).Times(object_count
);
500 class Handler
: public librbd::deep_copy::NoOpHandler
{
502 uint64_t object_count
;
503 librbd::deep_copy::ObjectNumber expected_object_number
;
505 Handler(uint64_t object_count
)
506 : object_count(object_count
) {
509 int update_progress(uint64_t object_no
, uint64_t end_object_no
) override
{
510 EXPECT_LE(object_no
, object_count
);
511 EXPECT_EQ(end_object_no
, object_count
);
512 if (!expected_object_number
) {
513 expected_object_number
= 0;
515 expected_object_number
= *expected_object_number
+ 1;
517 EXPECT_EQ(*expected_object_number
, object_no
- 1);
521 } handler(object_count
);
524 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
526 0, snap_id_end
, 0, false, boost::none
,
527 m_snap_seqs
, &handler
, &ctx
);
530 std::map
<uint64_t, Context
*> copy_contexts
;
531 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
532 for (uint64_t i
= 0; i
< object_count
; ++i
) {
534 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, i
,
535 ©_contexts
[i
], 0));
537 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, i
, nullptr,
542 for (auto& pair
: copy_contexts
) {
543 pair
.second
->complete(0);
546 ASSERT_EQ(0, ctx
.wait());
549 TEST_F(TestMockDeepCopyImageCopyRequest
, SnapshotSubset
) {
550 librados::snap_t snap_id_start
;
551 librados::snap_t snap_id_end
;
552 ASSERT_EQ(0, create_snap("snap1"));
553 ASSERT_EQ(0, create_snap("snap2", &snap_id_start
));
554 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
556 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
557 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
558 MockObjectCopyRequest mock_object_copy_request
;
561 MockDiffRequest mock_diff_request
;
562 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
563 expect_get_image_size(mock_src_image_ctx
, 1 << m_src_image_ctx
->order
);
564 expect_get_image_size(mock_src_image_ctx
, 0);
565 expect_get_image_size(mock_src_image_ctx
, 0);
566 expect_get_image_size(mock_src_image_ctx
, 0);
567 expect_object_copy_send(mock_object_copy_request
, 0);
569 librbd::deep_copy::NoOpHandler no_op
;
571 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
573 snap_id_start
, snap_id_end
, 0, false,
574 boost::none
, m_snap_seqs
, &no_op
,
578 SnapMap
snap_map(m_snap_map
);
579 snap_map
.erase(snap_map
.begin());
580 ASSERT_EQ(snap_map
, wait_for_snap_map(mock_object_copy_request
));
582 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
583 ASSERT_EQ(0, ctx
.wait());
586 TEST_F(TestMockDeepCopyImageCopyRequest
, RestartPartialSync
) {
587 librados::snap_t snap_id_end
;
588 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
590 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
591 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
592 MockObjectCopyRequest mock_object_copy_request
;
595 MockDiffRequest mock_diff_request
;
596 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
597 expect_get_image_size(mock_src_image_ctx
, 2 * (1 << m_src_image_ctx
->order
));
598 expect_get_image_size(mock_src_image_ctx
, 0);
599 expect_object_copy_send(mock_object_copy_request
, 0);
601 librbd::deep_copy::NoOpHandler no_op
;
603 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
605 0, snap_id_end
, 0, false,
606 librbd::deep_copy::ObjectNumber
{0U},
607 m_snap_seqs
, &no_op
, &ctx
);
610 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 1, nullptr, 0));
611 ASSERT_EQ(0, ctx
.wait());
614 TEST_F(TestMockDeepCopyImageCopyRequest
, Cancel
) {
615 std::string max_ops_str
;
616 ASSERT_EQ(0, _rados
.conf_get("rbd_concurrent_management_ops", max_ops_str
));
617 ASSERT_EQ(0, _rados
.conf_set("rbd_concurrent_management_ops", "1"));
618 BOOST_SCOPE_EXIT( (max_ops_str
) ) {
619 ASSERT_EQ(0, _rados
.conf_set("rbd_concurrent_management_ops",
620 max_ops_str
.c_str()));
621 } BOOST_SCOPE_EXIT_END
;
623 librados::snap_t snap_id_end
;
624 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
626 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
627 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
628 MockObjectCopyRequest mock_object_copy_request
;
631 MockDiffRequest mock_diff_request
;
632 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
633 expect_get_image_size(mock_src_image_ctx
, 1 << m_src_image_ctx
->order
);
634 expect_get_image_size(mock_src_image_ctx
, 0);
635 expect_object_copy_send(mock_object_copy_request
, 0);
637 librbd::deep_copy::NoOpHandler no_op
;
639 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
641 0, snap_id_end
, 0, false, boost::none
,
642 m_snap_seqs
, &no_op
, &ctx
);
645 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
648 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
649 ASSERT_EQ(-ECANCELED
, ctx
.wait());
652 TEST_F(TestMockDeepCopyImageCopyRequest
, Cancel_Inflight_Sync
) {
653 std::string max_ops_str
;
654 ASSERT_EQ(0, _rados
.conf_get("rbd_concurrent_management_ops", max_ops_str
));
655 ASSERT_EQ(0, _rados
.conf_set("rbd_concurrent_management_ops", "3"));
656 BOOST_SCOPE_EXIT( (max_ops_str
) ) {
657 ASSERT_EQ(0, _rados
.conf_set("rbd_concurrent_management_ops",
658 max_ops_str
.c_str()));
659 } BOOST_SCOPE_EXIT_END
;
661 librados::snap_t snap_id_end
;
662 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
664 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
665 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
666 MockObjectCopyRequest mock_object_copy_request
;
669 MockDiffRequest mock_diff_request
;
670 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
671 expect_get_image_size(mock_src_image_ctx
, 6 * (1 << m_src_image_ctx
->order
));
672 expect_get_image_size(mock_src_image_ctx
, m_image_size
);
674 EXPECT_CALL(mock_object_copy_request
, send()).Times(6);
676 struct Handler
: public librbd::deep_copy::NoOpHandler
{
677 librbd::deep_copy::ObjectNumber object_number
;
679 int update_progress(uint64_t object_no
, uint64_t end_object_no
) override
{
680 object_number
= object_number
? *object_number
+ 1 : 0;
686 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
688 0, snap_id_end
, 0, false, boost::none
,
689 m_snap_seqs
, &handler
, &ctx
);
692 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
694 Context
*cancel_ctx
= nullptr;
695 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
696 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 1, nullptr, 0));
697 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 2, nullptr, 0));
698 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 3, &cancel_ctx
,
700 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 4, nullptr, 0));
701 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 5, nullptr, 0));
704 cancel_ctx
->complete(0);
706 ASSERT_EQ(-ECANCELED
, ctx
.wait());
707 ASSERT_EQ(5u, handler
.object_number
.get());
710 TEST_F(TestMockDeepCopyImageCopyRequest
, CancelBeforeSend
) {
711 librados::snap_t snap_id_end
;
712 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
714 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
715 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
719 MockDiffRequest mock_diff_request
;
720 expect_diff_send(mock_diff_request
, {}, -EINVAL
);
721 expect_get_image_size(mock_src_image_ctx
, 2 * (1 << m_src_image_ctx
->order
));
722 expect_get_image_size(mock_src_image_ctx
, 0);
724 librbd::deep_copy::NoOpHandler no_op
;
726 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
728 0, snap_id_end
, 0, false, boost::none
,
729 m_snap_seqs
, &no_op
, &ctx
);
733 ASSERT_EQ(-ECANCELED
, ctx
.wait());
736 TEST_F(TestMockDeepCopyImageCopyRequest
, MissingSnap
) {
737 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
738 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
740 librbd::deep_copy::NoOpHandler no_op
;
742 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
744 0, 123, 0, false, boost::none
,
745 m_snap_seqs
, &no_op
, &ctx
);
747 ASSERT_EQ(-EINVAL
, ctx
.wait());
750 TEST_F(TestMockDeepCopyImageCopyRequest
, MissingFromSnap
) {
751 librados::snap_t snap_id_end
;
752 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
754 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
755 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
757 librbd::deep_copy::NoOpHandler no_op
;
759 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
761 123, snap_id_end
, 0, false,
762 boost::none
, m_snap_seqs
, &no_op
,
765 ASSERT_EQ(-EINVAL
, ctx
.wait());
768 TEST_F(TestMockDeepCopyImageCopyRequest
, EmptySnapMap
) {
769 librados::snap_t snap_id_start
;
770 librados::snap_t snap_id_end
;
771 ASSERT_EQ(0, create_snap("snap1", &snap_id_start
));
772 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
774 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
775 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
777 librbd::deep_copy::NoOpHandler no_op
;
779 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
781 snap_id_start
, snap_id_end
, 0, false,
782 boost::none
, {{0, 0}}, &no_op
, &ctx
);
784 ASSERT_EQ(-EINVAL
, ctx
.wait());
787 TEST_F(TestMockDeepCopyImageCopyRequest
, EmptySnapSeqs
) {
788 librados::snap_t snap_id_start
;
789 librados::snap_t snap_id_end
;
790 ASSERT_EQ(0, create_snap("snap1", &snap_id_start
));
791 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
793 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
794 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
796 librbd::deep_copy::NoOpHandler no_op
;
798 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
800 snap_id_start
, snap_id_end
, 0, false,
801 boost::none
, {}, &no_op
, &ctx
);
803 ASSERT_EQ(-EINVAL
, ctx
.wait());
806 } // namespace deep_copy
807 } // namespace librbd