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/DeepCopyRequest.h"
8 #include "librbd/ImageState.h"
9 #include "librbd/Operations.h"
10 #include "librbd/internal.h"
11 #include "librbd/api/Image.h"
12 #include "librbd/deep_copy/Handler.h"
13 #include "librbd/deep_copy/ImageCopyRequest.h"
14 #include "librbd/deep_copy/MetadataCopyRequest.h"
15 #include "librbd/deep_copy/SnapshotCopyRequest.h"
16 #include "test/librbd/mock/MockImageCtx.h"
17 #include "test/librbd/mock/MockObjectMap.h"
18 #include "test/librbd/test_support.h"
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include <boost/scope_exit.hpp>
28 struct MockTestImageCtx
: public librbd::MockImageCtx
{
29 explicit MockTestImageCtx(librbd::ImageCtx
&image_ctx
)
30 : librbd::MockImageCtx(image_ctx
) {
34 } // anonymous namespace
39 class ImageCopyRequest
<librbd::MockTestImageCtx
> {
41 static ImageCopyRequest
* s_instance
;
44 static ImageCopyRequest
* create(
45 librbd::MockTestImageCtx
*src_image_ctx
,
46 librbd::MockTestImageCtx
*dst_image_ctx
,
47 librados::snap_t src_snap_id_start
,
48 librados::snap_t src_snap_id_end
,
49 librados::snap_t dst_snap_id_start
,
50 bool flatten
, const ObjectNumber
&object_number
,
51 const SnapSeqs
&snap_seqs
, Handler
*handler
,
53 ceph_assert(s_instance
!= nullptr);
54 s_instance
->on_finish
= on_finish
;
68 MOCK_METHOD0(cancel
, void());
69 MOCK_METHOD0(send
, void());
73 class MetadataCopyRequest
<librbd::MockTestImageCtx
> {
75 static MetadataCopyRequest
* s_instance
;
78 static MetadataCopyRequest
* create(librbd::MockTestImageCtx
*src_image_ctx
,
79 librbd::MockTestImageCtx
*dst_image_ctx
,
81 ceph_assert(s_instance
!= nullptr);
82 s_instance
->on_finish
= on_finish
;
86 MetadataCopyRequest() {
90 MOCK_METHOD0(send
, void());
94 class SnapshotCopyRequest
<librbd::MockTestImageCtx
> {
96 static SnapshotCopyRequest
* s_instance
;
99 static SnapshotCopyRequest
* create(librbd::MockTestImageCtx
*src_image_ctx
,
100 librbd::MockTestImageCtx
*dst_image_ctx
,
101 librados::snap_t src_snap_id_start
,
102 librados::snap_t src_snap_id_end
,
103 librados::snap_t dst_snap_id_start
,
105 librbd::asio::ContextWQ
*work_queue
,
106 SnapSeqs
*snap_seqs
, Context
*on_finish
) {
107 ceph_assert(s_instance
!= nullptr);
108 s_instance
->on_finish
= on_finish
;
112 SnapshotCopyRequest() {
122 MOCK_METHOD0(cancel
, void());
123 MOCK_METHOD0(send
, void());
126 ImageCopyRequest
<librbd::MockTestImageCtx
>* ImageCopyRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
127 MetadataCopyRequest
<librbd::MockTestImageCtx
>* MetadataCopyRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
128 SnapshotCopyRequest
<librbd::MockTestImageCtx
>* SnapshotCopyRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
130 } // namespace deep_copy
131 } // namespace librbd
133 // template definitions
134 #include "librbd/DeepCopyRequest.cc"
137 using ::testing::DoAll
;
138 using ::testing::InSequence
;
139 using ::testing::Invoke
;
140 using ::testing::Return
;
141 using ::testing::ReturnNew
;
142 using ::testing::SetArgPointee
;
143 using ::testing::WithArg
;
145 class TestMockDeepCopyRequest
: public TestMockFixture
{
147 typedef librbd::DeepCopyRequest
<librbd::MockTestImageCtx
> MockDeepCopyRequest
;
148 typedef librbd::deep_copy::ImageCopyRequest
<librbd::MockTestImageCtx
> MockImageCopyRequest
;
149 typedef librbd::deep_copy::MetadataCopyRequest
<librbd::MockTestImageCtx
> MockMetadataCopyRequest
;
150 typedef librbd::deep_copy::SnapshotCopyRequest
<librbd::MockTestImageCtx
> MockSnapshotCopyRequest
;
152 librbd::ImageCtx
*m_src_image_ctx
;
153 librbd::ImageCtx
*m_dst_image_ctx
;
155 std::shared_ptr
<librbd::AsioEngine
> m_asio_engine
;
156 librbd::asio::ContextWQ
*m_work_queue
;
158 void SetUp() override
{
159 TestMockFixture::SetUp();
162 ASSERT_EQ(0, open_image(m_image_name
, &m_src_image_ctx
));
164 ASSERT_EQ(0, open_image(m_image_name
, &m_dst_image_ctx
));
166 m_asio_engine
= std::make_shared
<librbd::AsioEngine
>(
167 m_src_image_ctx
->md_ctx
);
168 m_work_queue
= m_asio_engine
->get_work_queue();
171 void TearDown() override
{
172 TestMockFixture::TearDown();
175 void expect_test_features(librbd::MockImageCtx
&mock_image_ctx
) {
176 EXPECT_CALL(mock_image_ctx
, test_features(_
, _
))
177 .WillRepeatedly(WithArg
<0>(Invoke([&mock_image_ctx
](uint64_t features
) {
178 return (mock_image_ctx
.features
& features
) != 0;
182 void expect_start_op(librbd::MockExclusiveLock
&mock_exclusive_lock
) {
183 EXPECT_CALL(mock_exclusive_lock
, start_op(_
)).WillOnce(Return(new LambdaContext([](int){})));
186 void expect_rollback_object_map(librbd::MockObjectMap
&mock_object_map
, int r
) {
187 EXPECT_CALL(mock_object_map
, rollback(_
, _
))
188 .WillOnce(WithArg
<1>(Invoke([this, r
](Context
*ctx
) {
189 m_work_queue
->queue(ctx
, r
);
193 void expect_create_object_map(librbd::MockTestImageCtx
&mock_image_ctx
,
194 librbd::MockObjectMap
*mock_object_map
) {
195 EXPECT_CALL(mock_image_ctx
, create_object_map(CEPH_NOSNAP
))
196 .WillOnce(Return(mock_object_map
));
199 void expect_open_object_map(librbd::MockTestImageCtx
&mock_image_ctx
,
200 librbd::MockObjectMap
&mock_object_map
, int r
) {
201 EXPECT_CALL(mock_object_map
, open(_
))
202 .WillOnce(Invoke([this, r
](Context
*ctx
) {
203 m_work_queue
->queue(ctx
, r
);
207 void expect_copy_snapshots(
208 MockSnapshotCopyRequest
&mock_snapshot_copy_request
, int r
) {
209 EXPECT_CALL(mock_snapshot_copy_request
, send())
210 .WillOnce(Invoke([this, &mock_snapshot_copy_request
, r
]() {
211 m_work_queue
->queue(mock_snapshot_copy_request
.on_finish
, r
);
215 void expect_copy_image(MockImageCopyRequest
&mock_image_copy_request
, int r
) {
216 EXPECT_CALL(mock_image_copy_request
, send())
217 .WillOnce(Invoke([this, &mock_image_copy_request
, r
]() {
218 m_work_queue
->queue(mock_image_copy_request
.on_finish
, r
);
222 void expect_copy_object_map(librbd::MockExclusiveLock
&mock_exclusive_lock
,
223 librbd::MockObjectMap
*mock_object_map
, int r
) {
224 expect_start_op(mock_exclusive_lock
);
225 expect_rollback_object_map(*mock_object_map
, r
);
228 void expect_refresh_object_map(librbd::MockTestImageCtx
&mock_image_ctx
,
229 librbd::MockObjectMap
*mock_object_map
,
231 expect_start_op(*mock_image_ctx
.exclusive_lock
);
232 expect_create_object_map(mock_image_ctx
, mock_object_map
);
233 expect_open_object_map(mock_image_ctx
, *mock_object_map
, r
);
236 void expect_copy_metadata(MockMetadataCopyRequest
&mock_metadata_copy_request
,
238 EXPECT_CALL(mock_metadata_copy_request
, send())
239 .WillOnce(Invoke([this, &mock_metadata_copy_request
, r
]() {
240 m_work_queue
->queue(mock_metadata_copy_request
.on_finish
, r
);
245 TEST_F(TestMockDeepCopyRequest
, SimpleCopy
) {
246 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
247 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
248 MockImageCopyRequest mock_image_copy_request
;
249 MockMetadataCopyRequest mock_metadata_copy_request
;
250 MockSnapshotCopyRequest mock_snapshot_copy_request
;
252 librbd::MockExclusiveLock mock_exclusive_lock
;
253 mock_dst_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
255 librbd::MockObjectMap mock_object_map
;
257 mock_dst_image_ctx
.object_map
= nullptr;
258 if (is_feature_enabled(RBD_FEATURE_OBJECT_MAP
)) {
259 mock_dst_image_ctx
.object_map
= &mock_object_map
;
262 expect_test_features(mock_dst_image_ctx
);
265 expect_copy_snapshots(mock_snapshot_copy_request
, 0);
266 expect_copy_image(mock_image_copy_request
, 0);
267 if (mock_dst_image_ctx
.object_map
!= nullptr) {
268 expect_refresh_object_map(mock_dst_image_ctx
, &mock_object_map
, 0);
270 expect_copy_metadata(mock_metadata_copy_request
, 0);
273 librbd::SnapSeqs snap_seqs
;
274 librbd::deep_copy::NoOpHandler no_op
;
275 auto request
= librbd::DeepCopyRequest
<librbd::MockTestImageCtx
>::create(
276 &mock_src_image_ctx
, &mock_dst_image_ctx
, 0, CEPH_NOSNAP
, 0, false,
277 boost::none
, m_work_queue
, &snap_seqs
, &no_op
, &ctx
);
279 ASSERT_EQ(0, ctx
.wait());
282 TEST_F(TestMockDeepCopyRequest
, ErrorOnCopySnapshots
) {
283 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
284 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
285 MockSnapshotCopyRequest mock_snapshot_copy_request
;
288 expect_copy_snapshots(mock_snapshot_copy_request
, -EINVAL
);
291 librbd::SnapSeqs snap_seqs
;
292 librbd::deep_copy::NoOpHandler no_op
;
293 auto request
= librbd::DeepCopyRequest
<librbd::MockTestImageCtx
>::create(
294 &mock_src_image_ctx
, &mock_dst_image_ctx
, 0, CEPH_NOSNAP
, 0, false,
295 boost::none
, m_work_queue
, &snap_seqs
, &no_op
, &ctx
);
297 ASSERT_EQ(-EINVAL
, ctx
.wait());
300 TEST_F(TestMockDeepCopyRequest
, ErrorOnRefreshObjectMap
) {
301 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
303 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
304 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
305 MockImageCopyRequest mock_image_copy_request
;
306 MockSnapshotCopyRequest mock_snapshot_copy_request
;
308 librbd::MockExclusiveLock mock_exclusive_lock
;
309 mock_dst_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
311 librbd::MockObjectMap
*mock_object_map
= new librbd::MockObjectMap();
312 mock_dst_image_ctx
.object_map
= mock_object_map
;
314 expect_test_features(mock_dst_image_ctx
);
317 expect_copy_snapshots(mock_snapshot_copy_request
, 0);
318 expect_copy_image(mock_image_copy_request
, 0);
319 expect_start_op(*mock_dst_image_ctx
.exclusive_lock
);
320 expect_create_object_map(mock_dst_image_ctx
, mock_object_map
);
321 expect_open_object_map(mock_dst_image_ctx
, *mock_object_map
, -EINVAL
);
324 librbd::SnapSeqs snap_seqs
;
325 librbd::deep_copy::NoOpHandler no_op
;
326 auto request
= librbd::DeepCopyRequest
<librbd::MockTestImageCtx
>::create(
327 &mock_src_image_ctx
, &mock_dst_image_ctx
, 0, CEPH_NOSNAP
, 0, false,
328 boost::none
, m_work_queue
, &snap_seqs
, &no_op
, &ctx
);
330 ASSERT_EQ(-EINVAL
, ctx
.wait());
333 TEST_F(TestMockDeepCopyRequest
, ErrorOnCopyImage
) {
334 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
335 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
336 MockImageCopyRequest mock_image_copy_request
;
337 MockSnapshotCopyRequest mock_snapshot_copy_request
;
340 expect_copy_snapshots(mock_snapshot_copy_request
, 0);
341 expect_copy_image(mock_image_copy_request
, -EINVAL
);
344 librbd::SnapSeqs snap_seqs
;
345 librbd::deep_copy::NoOpHandler no_op
;
346 auto request
= librbd::DeepCopyRequest
<librbd::MockTestImageCtx
>::create(
347 &mock_src_image_ctx
, &mock_dst_image_ctx
, 0, CEPH_NOSNAP
, 0, false,
348 boost::none
, m_work_queue
, &snap_seqs
, &no_op
, &ctx
);
350 ASSERT_EQ(-EINVAL
, ctx
.wait());
353 TEST_F(TestMockDeepCopyRequest
, ErrorOnCopyMetadata
) {
354 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
355 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
356 MockImageCopyRequest mock_image_copy_request
;
357 MockMetadataCopyRequest mock_metadata_copy_request
;
358 MockSnapshotCopyRequest mock_snapshot_copy_request
;
360 librbd::MockExclusiveLock mock_exclusive_lock
;
361 mock_dst_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
363 librbd::MockObjectMap mock_object_map
;
365 mock_dst_image_ctx
.object_map
= nullptr;
366 if (is_feature_enabled(RBD_FEATURE_OBJECT_MAP
)) {
367 mock_dst_image_ctx
.object_map
= &mock_object_map
;
370 expect_test_features(mock_dst_image_ctx
);
373 expect_copy_snapshots(mock_snapshot_copy_request
, 0);
374 expect_copy_image(mock_image_copy_request
, 0);
375 if (mock_dst_image_ctx
.object_map
!= nullptr) {
376 expect_refresh_object_map(mock_dst_image_ctx
, &mock_object_map
, 0);
378 expect_copy_metadata(mock_metadata_copy_request
, -EINVAL
);
381 librbd::SnapSeqs snap_seqs
;
382 librbd::deep_copy::NoOpHandler no_op
;
383 auto request
= librbd::DeepCopyRequest
<librbd::MockTestImageCtx
>::create(
384 &mock_src_image_ctx
, &mock_dst_image_ctx
, 0, CEPH_NOSNAP
, 0, false,
385 boost::none
, m_work_queue
, &snap_seqs
, &no_op
, &ctx
);
387 ASSERT_EQ(-EINVAL
, ctx
.wait());
390 TEST_F(TestMockDeepCopyRequest
, Snap
) {
391 EXPECT_EQ(0, snap_create(*m_src_image_ctx
, "copy"));
392 EXPECT_EQ(0, librbd::api::Image
<>::snap_set(m_src_image_ctx
,
393 cls::rbd::UserSnapshotNamespace(),
396 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
397 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
398 MockImageCopyRequest mock_image_copy_request
;
399 MockMetadataCopyRequest mock_metadata_copy_request
;
400 MockSnapshotCopyRequest mock_snapshot_copy_request
;
402 librbd::MockExclusiveLock mock_exclusive_lock
;
403 mock_dst_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
405 librbd::MockObjectMap mock_object_map
;
406 if (is_feature_enabled(RBD_FEATURE_OBJECT_MAP
)) {
407 mock_dst_image_ctx
.object_map
= &mock_object_map
;
410 expect_test_features(mock_dst_image_ctx
);
413 expect_copy_snapshots(mock_snapshot_copy_request
, 0);
414 expect_copy_image(mock_image_copy_request
, 0);
415 if (mock_dst_image_ctx
.object_map
!= nullptr) {
416 expect_copy_object_map(mock_exclusive_lock
, &mock_object_map
, 0);
417 expect_refresh_object_map(mock_dst_image_ctx
, &mock_object_map
, 0);
419 expect_copy_metadata(mock_metadata_copy_request
, 0);
422 librbd::SnapSeqs snap_seqs
= {{m_src_image_ctx
->snap_id
, 123}};
423 librbd::deep_copy::NoOpHandler no_op
;
424 auto request
= librbd::DeepCopyRequest
<librbd::MockTestImageCtx
>::create(
425 &mock_src_image_ctx
, &mock_dst_image_ctx
, 0, m_src_image_ctx
->snap_id
,
426 0, false, boost::none
, m_work_queue
, &snap_seqs
, &no_op
, &ctx
);
428 ASSERT_EQ(0, ctx
.wait());
431 TEST_F(TestMockDeepCopyRequest
, ErrorOnRollbackObjectMap
) {
432 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
434 EXPECT_EQ(0, snap_create(*m_src_image_ctx
, "copy"));
435 EXPECT_EQ(0, librbd::api::Image
<>::snap_set(m_src_image_ctx
,
436 cls::rbd::UserSnapshotNamespace(),
439 librbd::MockTestImageCtx
mock_src_image_ctx(*m_src_image_ctx
);
440 librbd::MockTestImageCtx
mock_dst_image_ctx(*m_dst_image_ctx
);
441 MockImageCopyRequest mock_image_copy_request
;
442 MockMetadataCopyRequest mock_metadata_copy_request
;
443 MockSnapshotCopyRequest mock_snapshot_copy_request
;
445 librbd::MockExclusiveLock mock_exclusive_lock
;
446 mock_dst_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
448 librbd::MockObjectMap mock_object_map
;
449 mock_dst_image_ctx
.object_map
= &mock_object_map
;
451 expect_test_features(mock_dst_image_ctx
);
454 expect_copy_snapshots(mock_snapshot_copy_request
, 0);
455 expect_copy_image(mock_image_copy_request
, 0);
456 expect_copy_object_map(mock_exclusive_lock
, &mock_object_map
, -EINVAL
);
459 librbd::SnapSeqs snap_seqs
= {{m_src_image_ctx
->snap_id
, 123}};
460 librbd::deep_copy::NoOpHandler no_op
;
461 auto request
= librbd::DeepCopyRequest
<librbd::MockTestImageCtx
>::create(
462 &mock_src_image_ctx
, &mock_dst_image_ctx
, 0, m_src_image_ctx
->snap_id
,
463 0, false, boost::none
, m_work_queue
, &snap_seqs
, &no_op
, &ctx
);
465 ASSERT_EQ(-EINVAL
, ctx
.wait());