]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/test_mock_DeepCopyRequest.cc
import ceph quincy 17.2.6
[ceph.git] / ceph / src / test / librbd / test_mock_DeepCopyRequest.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/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"
19
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include <boost/scope_exit.hpp>
23
24 namespace librbd {
25
26 namespace {
27
28 struct MockTestImageCtx : public librbd::MockImageCtx {
29 explicit MockTestImageCtx(librbd::ImageCtx &image_ctx)
30 : librbd::MockImageCtx(image_ctx) {
31 }
32 };
33
34 } // anonymous namespace
35
36 namespace deep_copy {
37
38 template <>
39 class ImageCopyRequest<librbd::MockTestImageCtx> {
40 public:
41 static ImageCopyRequest* s_instance;
42 Context *on_finish;
43
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,
52 Context *on_finish) {
53 ceph_assert(s_instance != nullptr);
54 s_instance->on_finish = on_finish;
55 return s_instance;
56 }
57
58 ImageCopyRequest() {
59 s_instance = this;
60 }
61
62 void put() {
63 }
64
65 void get() {
66 }
67
68 MOCK_METHOD0(cancel, void());
69 MOCK_METHOD0(send, void());
70 };
71
72 template <>
73 class MetadataCopyRequest<librbd::MockTestImageCtx> {
74 public:
75 static MetadataCopyRequest* s_instance;
76 Context *on_finish;
77
78 static MetadataCopyRequest* create(librbd::MockTestImageCtx *src_image_ctx,
79 librbd::MockTestImageCtx *dst_image_ctx,
80 Context *on_finish) {
81 ceph_assert(s_instance != nullptr);
82 s_instance->on_finish = on_finish;
83 return s_instance;
84 }
85
86 MetadataCopyRequest() {
87 s_instance = this;
88 }
89
90 MOCK_METHOD0(send, void());
91 };
92
93 template <>
94 class SnapshotCopyRequest<librbd::MockTestImageCtx> {
95 public:
96 static SnapshotCopyRequest* s_instance;
97 Context *on_finish;
98
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,
104 bool flatten,
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;
109 return s_instance;
110 }
111
112 SnapshotCopyRequest() {
113 s_instance = this;
114 }
115
116 void put() {
117 }
118
119 void get() {
120 }
121
122 MOCK_METHOD0(cancel, void());
123 MOCK_METHOD0(send, void());
124 };
125
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;
129
130 } // namespace deep_copy
131 } // namespace librbd
132
133 // template definitions
134 #include "librbd/DeepCopyRequest.cc"
135
136 using ::testing::_;
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;
144
145 class TestMockDeepCopyRequest : public TestMockFixture {
146 public:
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;
151
152 librbd::ImageCtx *m_src_image_ctx;
153 librbd::ImageCtx *m_dst_image_ctx;
154
155 std::shared_ptr<librbd::AsioEngine> m_asio_engine;
156 librbd::asio::ContextWQ *m_work_queue;
157
158 void SetUp() override {
159 TestMockFixture::SetUp();
160
161 librbd::RBD rbd;
162 ASSERT_EQ(0, open_image(m_image_name, &m_src_image_ctx));
163
164 ASSERT_EQ(0, open_image(m_image_name, &m_dst_image_ctx));
165
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();
169 }
170
171 void TearDown() override {
172 TestMockFixture::TearDown();
173 }
174
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;
179 })));
180 }
181
182 void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) {
183 EXPECT_CALL(mock_exclusive_lock, start_op(_)).WillOnce(Return(new LambdaContext([](int){})));
184 }
185
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);
190 })));
191 }
192
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));
197 }
198
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);
204 }));
205 }
206
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);
212 }));
213 }
214
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);
219 }));
220 }
221
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);
226 }
227
228 void expect_refresh_object_map(librbd::MockTestImageCtx &mock_image_ctx,
229 librbd::MockObjectMap *mock_object_map,
230 int r) {
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);
234 }
235
236 void expect_copy_metadata(MockMetadataCopyRequest &mock_metadata_copy_request,
237 int r) {
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);
241 }));
242 }
243 };
244
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;
251
252 librbd::MockExclusiveLock mock_exclusive_lock;
253 mock_dst_image_ctx.exclusive_lock = &mock_exclusive_lock;
254
255 librbd::MockObjectMap mock_object_map;
256
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;
260 }
261
262 expect_test_features(mock_dst_image_ctx);
263
264 InSequence seq;
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);
269 }
270 expect_copy_metadata(mock_metadata_copy_request, 0);
271
272 C_SaferCond ctx;
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);
278 request->send();
279 ASSERT_EQ(0, ctx.wait());
280 }
281
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;
286
287 InSequence seq;
288 expect_copy_snapshots(mock_snapshot_copy_request, -EINVAL);
289
290 C_SaferCond ctx;
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);
296 request->send();
297 ASSERT_EQ(-EINVAL, ctx.wait());
298 }
299
300 TEST_F(TestMockDeepCopyRequest, ErrorOnRefreshObjectMap) {
301 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
302
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;
307
308 librbd::MockExclusiveLock mock_exclusive_lock;
309 mock_dst_image_ctx.exclusive_lock = &mock_exclusive_lock;
310
311 librbd::MockObjectMap *mock_object_map = new librbd::MockObjectMap();
312 mock_dst_image_ctx.object_map = mock_object_map;
313
314 expect_test_features(mock_dst_image_ctx);
315
316 InSequence seq;
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);
322
323 C_SaferCond ctx;
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);
329 request->send();
330 ASSERT_EQ(-EINVAL, ctx.wait());
331 }
332
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;
338
339 InSequence seq;
340 expect_copy_snapshots(mock_snapshot_copy_request, 0);
341 expect_copy_image(mock_image_copy_request, -EINVAL);
342
343 C_SaferCond ctx;
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);
349 request->send();
350 ASSERT_EQ(-EINVAL, ctx.wait());
351 }
352
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;
359
360 librbd::MockExclusiveLock mock_exclusive_lock;
361 mock_dst_image_ctx.exclusive_lock = &mock_exclusive_lock;
362
363 librbd::MockObjectMap mock_object_map;
364
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;
368 }
369
370 expect_test_features(mock_dst_image_ctx);
371
372 InSequence seq;
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);
377 }
378 expect_copy_metadata(mock_metadata_copy_request, -EINVAL);
379
380 C_SaferCond ctx;
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);
386 request->send();
387 ASSERT_EQ(-EINVAL, ctx.wait());
388 }
389
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(),
394 "copy"));
395
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;
401
402 librbd::MockExclusiveLock mock_exclusive_lock;
403 mock_dst_image_ctx.exclusive_lock = &mock_exclusive_lock;
404
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;
408 }
409
410 expect_test_features(mock_dst_image_ctx);
411
412 InSequence seq;
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);
418 }
419 expect_copy_metadata(mock_metadata_copy_request, 0);
420
421 C_SaferCond ctx;
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);
427 request->send();
428 ASSERT_EQ(0, ctx.wait());
429 }
430
431 TEST_F(TestMockDeepCopyRequest, ErrorOnRollbackObjectMap) {
432 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP);
433
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(),
437 "copy"));
438
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;
444
445 librbd::MockExclusiveLock mock_exclusive_lock;
446 mock_dst_image_ctx.exclusive_lock = &mock_exclusive_lock;
447
448 librbd::MockObjectMap mock_object_map;
449 mock_dst_image_ctx.object_map = &mock_object_map;
450
451 expect_test_features(mock_dst_image_ctx);
452
453 InSequence seq;
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);
457
458 C_SaferCond ctx;
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);
464 request->send();
465 ASSERT_EQ(-EINVAL, ctx.wait());
466 }