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/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>
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
, 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();
66 MOCK_METHOD0(send
, void());
68 ceph::mutex lock
= ceph::make_mutex("lock");
69 ceph::condition_variable cond
;
71 const SnapMap
*snap_map
= nullptr;
72 std::map
<uint64_t, Context
*> object_contexts
;
79 ObjectCopyRequest
<librbd::MockTestImageCtx
>* ObjectCopyRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
81 } // namespace deep_copy
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
;
95 MOCK_METHOD0(send
, void());
102 CloseRequest
<MockTestImageCtx
>* CloseRequest
<MockTestImageCtx
>::s_instance
= nullptr;
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
;
115 MOCK_METHOD0(send
, void());
122 OpenRequest
<MockTestImageCtx
>* OpenRequest
<MockTestImageCtx
>::s_instance
= nullptr;
126 namespace object_map
{
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
;
147 MOCK_METHOD0(send
, void());
150 DiffRequest
<MockTestImageCtx
>* DiffRequest
<MockTestImageCtx
>::s_instance
= nullptr;
152 } // namespace object_map
153 } // namespace librbd
155 // template definitions
156 #include "librbd/deep_copy/ImageCopyRequest.cc"
157 template class librbd::deep_copy::ImageCopyRequest
<librbd::MockTestImageCtx
>;
160 namespace deep_copy
{
163 using ::testing::InSequence
;
164 using ::testing::Invoke
;
165 using ::testing::Return
;
167 class TestMockDeepCopyImageCopyRequest
: public TestMockFixture
{
169 typedef ImageCopyRequest
<librbd::MockTestImageCtx
> MockImageCopyRequest
;
170 typedef ObjectCopyRequest
<librbd::MockTestImageCtx
> MockObjectCopyRequest
;
171 typedef object_map::DiffRequest
<librbd::MockTestImageCtx
> MockDiffRequest
;
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
;
180 void SetUp() override
{
181 TestMockFixture::SetUp();
183 ASSERT_EQ(0, open_image(m_image_name
, &m_src_image_ctx
));
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
));
190 librbd::ImageCtx::get_thread_pool_instance(m_src_image_ctx
->cct
,
191 &m_thread_pool
, &m_work_queue
);
194 void expect_get_image_size(librbd::MockTestImageCtx
&mock_image_ctx
,
196 EXPECT_CALL(mock_image_ctx
, get_image_size(_
))
197 .WillOnce(Return(size
)).RetiresOnSaturation();
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
]() {
205 *mock_request
.object_diff_state
= diff_state
;
207 m_work_queue
->queue(mock_request
.on_finish
, r
);
211 void expect_object_copy_send(MockObjectCopyRequest
&mock_object_copy_request
) {
212 EXPECT_CALL(mock_object_copy_request
, send());
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
) {
225 if (object_ctx
!= nullptr) {
226 *object_ctx
= mock_object_copy_request
.object_contexts
[object_num
];
228 m_work_queue
->queue(mock_object_copy_request
.object_contexts
[object_num
],
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
) {
242 return *mock_object_copy_request
.snap_map
;
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
);
253 r
= image_ctx
->state
->refresh();
258 if (image_ctx
->snap_ids
.count({cls::rbd::UserSnapshotNamespace(),
263 if (snap_id
!= nullptr) {
264 *snap_id
= image_ctx
->snap_ids
[{cls::rbd::UserSnapshotNamespace(),
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
);
278 if (src_snap_id_
!= nullptr) {
279 *src_snap_id_
= src_snap_id
;
282 librados::snap_t dst_snap_id
;
283 r
= create_snap(m_dst_image_ctx
, snap_name
, &dst_snap_id
);
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());
295 m_snap_map
[src_snap_id
] = dst_snap_ids
;
296 m_snap_seqs
[src_snap_id
] = dst_snap_id
;
301 TEST_F(TestMockDeepCopyImageCopyRequest
, SimpleImage
) {
302 librados::snap_t snap_id_end
;
303 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
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
;
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
);
316 librbd::NoOpProgressContext no_op
;
318 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
320 0, snap_id_end
, 0, false, boost::none
,
321 m_snap_seqs
, &no_op
, &ctx
);
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());
329 TEST_F(TestMockDeepCopyImageCopyRequest
, FastDiff
) {
330 librados::snap_t snap_id_end
;
331 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
333 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
334 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
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);
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);
346 librbd::NoOpProgressContext no_op
;
348 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
350 0, snap_id_end
, 0, false, boost::none
,
351 m_snap_seqs
, &no_op
, &ctx
);
354 ASSERT_EQ(0, ctx
.wait());
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
;
366 librados::snap_t snap_id_end
;
367 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
369 uint64_t object_count
= 55;
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
;
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);
381 EXPECT_CALL(mock_object_copy_request
, send()).Times(object_count
);
383 class ProgressContext
: public librbd::ProgressContext
{
385 uint64_t object_count
;
386 librbd::deep_copy::ObjectNumber expected_object_number
;
388 ProgressContext(uint64_t object_count
)
389 : object_count(object_count
) {
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;
398 expected_object_number
= *expected_object_number
+ 1;
400 EXPECT_EQ(*expected_object_number
, object_no
- 1);
404 } prog_ctx(object_count
);
407 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
409 0, snap_id_end
, 0, false, boost::none
,
410 m_snap_seqs
, &prog_ctx
, &ctx
);
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
) {
417 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, i
,
418 ©_contexts
[i
], 0));
420 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, i
, nullptr,
425 for (auto& pair
: copy_contexts
) {
426 pair
.second
->complete(0);
429 ASSERT_EQ(0, ctx
.wait());
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
));
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
;
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
);
452 librbd::NoOpProgressContext no_op
;
454 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
456 snap_id_start
, snap_id_end
, 0, false,
457 boost::none
, m_snap_seqs
, &no_op
,
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
));
465 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
466 ASSERT_EQ(0, ctx
.wait());
469 TEST_F(TestMockDeepCopyImageCopyRequest
, RestartPartialSync
) {
470 librados::snap_t snap_id_end
;
471 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
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
;
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
);
484 librbd::NoOpProgressContext no_op
;
486 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
488 0, snap_id_end
, 0, false,
489 librbd::deep_copy::ObjectNumber
{0U},
490 m_snap_seqs
, &no_op
, &ctx
);
493 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 1, nullptr, 0));
494 ASSERT_EQ(0, ctx
.wait());
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
;
506 librados::snap_t snap_id_end
;
507 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
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
;
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
);
520 librbd::NoOpProgressContext no_op
;
522 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
524 0, snap_id_end
, 0, false, boost::none
,
525 m_snap_seqs
, &no_op
, &ctx
);
528 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
531 ASSERT_TRUE(complete_object_copy(mock_object_copy_request
, 0, nullptr, 0));
532 ASSERT_EQ(-ECANCELED
, ctx
.wait());
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
;
544 librados::snap_t snap_id_end
;
545 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
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
;
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
);
557 EXPECT_CALL(mock_object_copy_request
, send()).Times(6);
559 struct ProgressContext
: public librbd::ProgressContext
{
560 librbd::deep_copy::ObjectNumber object_number
;
562 int update_progress(uint64_t object_no
, uint64_t end_object_no
) override
{
563 object_number
= object_number
? *object_number
+ 1 : 0;
569 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
571 0, snap_id_end
, 0, false, boost::none
,
572 m_snap_seqs
, &prog_ctx
, &ctx
);
575 ASSERT_EQ(m_snap_map
, wait_for_snap_map(mock_object_copy_request
));
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
,
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));
587 cancel_ctx
->complete(0);
589 ASSERT_EQ(-ECANCELED
, ctx
.wait());
590 ASSERT_EQ(5u, prog_ctx
.object_number
.get());
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
);
597 librbd::NoOpProgressContext no_op
;
599 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
601 0, 123, 0, false, boost::none
,
602 m_snap_seqs
, &no_op
, &ctx
);
604 ASSERT_EQ(-EINVAL
, ctx
.wait());
607 TEST_F(TestMockDeepCopyImageCopyRequest
, MissingFromSnap
) {
608 librados::snap_t snap_id_end
;
609 ASSERT_EQ(0, create_snap("copy", &snap_id_end
));
611 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
612 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
614 librbd::NoOpProgressContext no_op
;
616 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
618 123, snap_id_end
, 0, false,
619 boost::none
, m_snap_seqs
, &no_op
,
622 ASSERT_EQ(-EINVAL
, ctx
.wait());
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
));
631 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
632 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
634 librbd::NoOpProgressContext no_op
;
636 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
638 snap_id_start
, snap_id_end
, 0, false,
639 boost::none
, {{0, 0}}, &no_op
, &ctx
);
641 ASSERT_EQ(-EINVAL
, ctx
.wait());
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
));
650 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
651 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
653 librbd::NoOpProgressContext no_op
;
655 auto request
= new MockImageCopyRequest(&mock_src_image_ctx
,
657 snap_id_start
, snap_id_end
, 0, false,
658 boost::none
, {}, &no_op
, &ctx
);
660 ASSERT_EQ(-EINVAL
, ctx
.wait());
663 } // namespace deep_copy
664 } // namespace librbd