]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/deep_copy/test_mock_ImageCopyRequest.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / test / librbd / deep_copy / test_mock_ImageCopyRequest.cc
CommitLineData
11fdf7f2
TL
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"
f67539c2 6#include "librbd/AsioEngine.h"
11fdf7f2
TL
7#include "librbd/ImageCtx.h"
8#include "librbd/ImageState.h"
9f95a23c 9#include "librbd/internal.h"
11fdf7f2 10#include "librbd/Operations.h"
1911f103 11#include "librbd/deep_copy/Handler.h"
11fdf7f2
TL
12#include "librbd/deep_copy/ImageCopyRequest.h"
13#include "librbd/deep_copy/ObjectCopyRequest.h"
9f95a23c 14#include "librbd/object_map/DiffRequest.h"
11fdf7f2
TL
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>
19
20namespace librbd {
21
22namespace {
23
24struct 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,
29 bool read_only) {
30 ceph_assert(s_instance != nullptr);
31 return s_instance;
32 }
33
34 explicit MockTestImageCtx(librbd::ImageCtx &image_ctx)
35 : librbd::MockImageCtx(image_ctx) {
36 s_instance = this;
37 }
38
39 MOCK_METHOD0(destroy, void());
40};
41
42MockTestImageCtx* MockTestImageCtx::s_instance = nullptr;
43
44} // anonymous namespace
45
46namespace deep_copy {
47
48template <>
49struct ObjectCopyRequest<librbd::MockTestImageCtx> {
50 static ObjectCopyRequest* s_instance;
51 static ObjectCopyRequest* create(
52 librbd::MockTestImageCtx *src_image_ctx,
9f95a23c
TL
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,
cd265ab1 57 uint64_t object_number, uint32_t flags, Handler* handler,
1911f103 58 Context *on_finish) {
11fdf7f2 59 ceph_assert(s_instance != nullptr);
9f95a23c 60 std::lock_guard locker{s_instance->lock};
11fdf7f2 61 s_instance->snap_map = &snap_map;
f67539c2 62 s_instance->flags = flags;
11fdf7f2 63 s_instance->object_contexts[object_number] = on_finish;
9f95a23c 64 s_instance->cond.notify_all();
11fdf7f2
TL
65 return s_instance;
66 }
67
68 MOCK_METHOD0(send, void());
69
9f95a23c
TL
70 ceph::mutex lock = ceph::make_mutex("lock");
71 ceph::condition_variable cond;
11fdf7f2
TL
72
73 const SnapMap *snap_map = nullptr;
74 std::map<uint64_t, Context *> object_contexts;
f67539c2 75 uint32_t flags = 0;
11fdf7f2 76
9f95a23c 77 ObjectCopyRequest() {
11fdf7f2
TL
78 s_instance = this;
79 }
80};
81
82ObjectCopyRequest<librbd::MockTestImageCtx>* ObjectCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
83
84} // namespace deep_copy
85
9f95a23c
TL
86namespace object_map {
87
88template <>
89struct 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,
96 Context* on_finish) {
97 ceph_assert(s_instance != nullptr);
98 s_instance->object_diff_state = object_diff_state;
99 s_instance->on_finish = on_finish;
100 return s_instance;
101 }
102
103 DiffRequest() {
104 s_instance = this;
105 }
106
107 MOCK_METHOD0(send, void());
108};
109
110DiffRequest<MockTestImageCtx>* DiffRequest<MockTestImageCtx>::s_instance = nullptr;
111
112} // namespace object_map
11fdf7f2
TL
113} // namespace librbd
114
115// template definitions
116#include "librbd/deep_copy/ImageCopyRequest.cc"
117template class librbd::deep_copy::ImageCopyRequest<librbd::MockTestImageCtx>;
118
20effc67
TL
119using namespace std::chrono_literals;
120
11fdf7f2
TL
121namespace librbd {
122namespace deep_copy {
123
124using ::testing::_;
125using ::testing::InSequence;
9f95a23c 126using ::testing::Invoke;
11fdf7f2
TL
127using ::testing::Return;
128
129class TestMockDeepCopyImageCopyRequest : public TestMockFixture {
130public:
131 typedef ImageCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest;
132 typedef ObjectCopyRequest<librbd::MockTestImageCtx> MockObjectCopyRequest;
9f95a23c 133 typedef object_map::DiffRequest<librbd::MockTestImageCtx> MockDiffRequest;
11fdf7f2
TL
134
135 librbd::ImageCtx *m_src_image_ctx;
136 librbd::ImageCtx *m_dst_image_ctx;
f67539c2
TL
137
138 std::shared_ptr<librbd::AsioEngine> m_asio_engine;
139 asio::ContextWQ *m_work_queue;
140
11fdf7f2
TL
141 librbd::SnapSeqs m_snap_seqs;
142 SnapMap m_snap_map;
143
144 void SetUp() override {
145 TestMockFixture::SetUp();
146
147 ASSERT_EQ(0, open_image(m_image_name, &m_src_image_ctx));
148
149 librbd::RBD rbd;
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));
153
f67539c2
TL
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();
11fdf7f2
TL
157 }
158
159 void expect_get_image_size(librbd::MockTestImageCtx &mock_image_ctx,
160 uint64_t size) {
161 EXPECT_CALL(mock_image_ctx, get_image_size(_))
162 .WillOnce(Return(size)).RetiresOnSaturation();
163 }
164
9f95a23c
TL
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]() {
169 if (r >= 0) {
170 *mock_request.object_diff_state = diff_state;
171 }
172 m_work_queue->queue(mock_request.on_finish, r);
173 }));
174 }
175
f67539c2
TL
176 void expect_object_copy_send(MockObjectCopyRequest &mock_object_copy_request,
177 uint32_t flags) {
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);
181 }));
11fdf7f2
TL
182 }
183
184 bool complete_object_copy(MockObjectCopyRequest &mock_object_copy_request,
185 uint64_t object_num, Context **object_ctx, int r) {
9f95a23c 186 std::unique_lock locker{mock_object_copy_request.lock};
11fdf7f2 187 while (mock_object_copy_request.object_contexts.count(object_num) == 0) {
9f95a23c
TL
188 if (mock_object_copy_request.cond.wait_for(locker, 10s) ==
189 std::cv_status::timeout) {
11fdf7f2
TL
190 return false;
191 }
192 }
193
194 if (object_ctx != nullptr) {
195 *object_ctx = mock_object_copy_request.object_contexts[object_num];
196 } else {
197 m_work_queue->queue(mock_object_copy_request.object_contexts[object_num],
198 r);
199 }
200 return true;
201 }
202
203 SnapMap wait_for_snap_map(MockObjectCopyRequest &mock_object_copy_request) {
9f95a23c 204 std::unique_lock locker{mock_object_copy_request.lock};
11fdf7f2 205 while (mock_object_copy_request.snap_map == nullptr) {
9f95a23c
TL
206 if (mock_object_copy_request.cond.wait_for(locker, 10s) ==
207 std::cv_status::timeout) {
11fdf7f2
TL
208 return SnapMap();
209 }
210 }
211 return *mock_object_copy_request.snap_map;
212 }
213
214 int create_snap(librbd::ImageCtx *image_ctx, const char* snap_name,
215 librados::snap_t *snap_id) {
f67539c2 216 NoOpProgressContext prog_ctx;
11fdf7f2 217 int r = image_ctx->operations->snap_create(
f67539c2 218 cls::rbd::UserSnapshotNamespace(), snap_name, 0, prog_ctx);
11fdf7f2
TL
219 if (r < 0) {
220 return r;
221 }
222
223 r = image_ctx->state->refresh();
224 if (r < 0) {
225 return r;
226 }
227
228 if (image_ctx->snap_ids.count({cls::rbd::UserSnapshotNamespace(),
229 snap_name}) == 0) {
230 return -ENOENT;
231 }
232
233 if (snap_id != nullptr) {
234 *snap_id = image_ctx->snap_ids[{cls::rbd::UserSnapshotNamespace(),
235 snap_name}];
236 }
237 return 0;
238 }
239
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);
244 if (r < 0) {
245 return r;
246 }
247
248 if (src_snap_id_ != nullptr) {
249 *src_snap_id_ = src_snap_id;
250 }
251
252 librados::snap_t dst_snap_id;
253 r = create_snap(m_dst_image_ctx, snap_name, &dst_snap_id);
254 if (r < 0) {
255 return r;
256 }
257
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());
264 }
265 m_snap_map[src_snap_id] = dst_snap_ids;
266 m_snap_seqs[src_snap_id] = dst_snap_id;
267 return 0;
268 }
269};
270
271TEST_F(TestMockDeepCopyImageCopyRequest, SimpleImage) {
272 librados::snap_t snap_id_end;
273 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
274
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;
278
279 InSequence seq;
9f95a23c
TL
280 MockDiffRequest mock_diff_request;
281 expect_diff_send(mock_diff_request, {}, -EINVAL);
11fdf7f2
TL
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);
f67539c2
TL
284 expect_object_copy_send(mock_object_copy_request, 0);
285
286 librbd::deep_copy::NoOpHandler no_op;
287 C_SaferCond ctx;
288 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
289 &mock_dst_image_ctx,
290 0, snap_id_end, 0, false, boost::none,
291 m_snap_seqs, &no_op, &ctx);
292 request->send();
293
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());
297}
298
299TEST_F(TestMockDeepCopyImageCopyRequest, FastDiffNonExistent) {
300 librados::snap_t snap_id_end;
301 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
302
303 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
304 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
305
306 InSequence seq;
307
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);
312
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
316 librbd::deep_copy::NoOpHandler no_op;
317 C_SaferCond ctx;
318 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
319 &mock_dst_image_ctx,
320 0, snap_id_end, 0, false, boost::none,
321 m_snap_seqs, &no_op, &ctx);
322 request->send();
323
324 ASSERT_EQ(0, ctx.wait());
325}
326
327TEST_F(TestMockDeepCopyImageCopyRequest, FastDiffExistsDirty) {
328 librados::snap_t snap_id_end;
329 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
330
331 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
332 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
333
334 InSequence seq;
335
336 MockDiffRequest mock_diff_request;
337 BitVector<2> diff_state;
338 diff_state.resize(1);
339 diff_state[0] = object_map::DIFF_STATE_DATA_UPDATED;
340 expect_diff_send(mock_diff_request, diff_state, 0);
341
342 expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order);
343 expect_get_image_size(mock_src_image_ctx, 0);
344 MockObjectCopyRequest mock_object_copy_request;
345 expect_object_copy_send(mock_object_copy_request, 0);
11fdf7f2 346
1911f103 347 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
348 C_SaferCond ctx;
349 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
350 &mock_dst_image_ctx,
9f95a23c 351 0, snap_id_end, 0, false, boost::none,
11fdf7f2
TL
352 m_snap_seqs, &no_op, &ctx);
353 request->send();
354
355 ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request));
356 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0));
357 ASSERT_EQ(0, ctx.wait());
358}
359
f67539c2 360TEST_F(TestMockDeepCopyImageCopyRequest, FastDiffExistsClean) {
9f95a23c
TL
361 librados::snap_t snap_id_end;
362 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
363
364 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
365 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
366
367 InSequence seq;
368
369 MockDiffRequest mock_diff_request;
370 BitVector<2> diff_state;
371 diff_state.resize(1);
f67539c2 372 diff_state[0] = object_map::DIFF_STATE_DATA;
9f95a23c
TL
373 expect_diff_send(mock_diff_request, diff_state, 0);
374
375 expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order);
376 expect_get_image_size(mock_src_image_ctx, 0);
f67539c2
TL
377 MockObjectCopyRequest mock_object_copy_request;
378 expect_object_copy_send(mock_object_copy_request,
379 OBJECT_COPY_REQUEST_FLAG_EXISTS_CLEAN);
9f95a23c 380
1911f103 381 librbd::deep_copy::NoOpHandler no_op;
9f95a23c
TL
382 C_SaferCond ctx;
383 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
384 &mock_dst_image_ctx,
385 0, snap_id_end, 0, false, boost::none,
386 m_snap_seqs, &no_op, &ctx);
387 request->send();
388
f67539c2
TL
389 ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request));
390 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0));
9f95a23c
TL
391 ASSERT_EQ(0, ctx.wait());
392}
393
11fdf7f2
TL
394TEST_F(TestMockDeepCopyImageCopyRequest, OutOfOrder) {
395 std::string max_ops_str;
396 ASSERT_EQ(0, _rados.conf_get("rbd_concurrent_management_ops", max_ops_str));
397 ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", "10"));
398 BOOST_SCOPE_EXIT( (max_ops_str) ) {
399 ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops",
400 max_ops_str.c_str()));
401 } BOOST_SCOPE_EXIT_END;
402
403 librados::snap_t snap_id_end;
404 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
405
406 uint64_t object_count = 55;
407
408 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
409 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
410 MockObjectCopyRequest mock_object_copy_request;
411
9f95a23c
TL
412 MockDiffRequest mock_diff_request;
413 expect_diff_send(mock_diff_request, {}, -EINVAL);
11fdf7f2
TL
414 expect_get_image_size(mock_src_image_ctx,
415 object_count * (1 << m_src_image_ctx->order));
416 expect_get_image_size(mock_src_image_ctx, 0);
417
418 EXPECT_CALL(mock_object_copy_request, send()).Times(object_count);
419
1911f103 420 class Handler : public librbd::deep_copy::NoOpHandler {
11fdf7f2
TL
421 public:
422 uint64_t object_count;
423 librbd::deep_copy::ObjectNumber expected_object_number;
424
1911f103 425 Handler(uint64_t object_count)
11fdf7f2
TL
426 : object_count(object_count) {
427 }
428
429 int update_progress(uint64_t object_no, uint64_t end_object_no) override {
430 EXPECT_LE(object_no, object_count);
431 EXPECT_EQ(end_object_no, object_count);
432 if (!expected_object_number) {
433 expected_object_number = 0;
434 } else {
435 expected_object_number = *expected_object_number + 1;
436 }
437 EXPECT_EQ(*expected_object_number, object_no - 1);
438
439 return 0;
440 }
1911f103 441 } handler(object_count);
11fdf7f2
TL
442
443 C_SaferCond ctx;
444 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
445 &mock_dst_image_ctx,
9f95a23c 446 0, snap_id_end, 0, false, boost::none,
1911f103 447 m_snap_seqs, &handler, &ctx);
11fdf7f2
TL
448 request->send();
449
450 std::map<uint64_t, Context*> copy_contexts;
451 ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request));
452 for (uint64_t i = 0; i < object_count; ++i) {
453 if (i % 10 == 0) {
454 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i,
455 &copy_contexts[i], 0));
456 } else {
457 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, i, nullptr,
458 0));
459 }
460 }
461
462 for (auto& pair : copy_contexts) {
463 pair.second->complete(0);
464 }
465
466 ASSERT_EQ(0, ctx.wait());
467}
468
469TEST_F(TestMockDeepCopyImageCopyRequest, SnapshotSubset) {
470 librados::snap_t snap_id_start;
471 librados::snap_t snap_id_end;
472 ASSERT_EQ(0, create_snap("snap1"));
473 ASSERT_EQ(0, create_snap("snap2", &snap_id_start));
474 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
475
476 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
477 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
478 MockObjectCopyRequest mock_object_copy_request;
479
480 InSequence seq;
9f95a23c
TL
481 MockDiffRequest mock_diff_request;
482 expect_diff_send(mock_diff_request, {}, -EINVAL);
11fdf7f2
TL
483 expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order);
484 expect_get_image_size(mock_src_image_ctx, 0);
485 expect_get_image_size(mock_src_image_ctx, 0);
486 expect_get_image_size(mock_src_image_ctx, 0);
f67539c2 487 expect_object_copy_send(mock_object_copy_request, 0);
11fdf7f2 488
1911f103 489 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
490 C_SaferCond ctx;
491 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
492 &mock_dst_image_ctx,
9f95a23c 493 snap_id_start, snap_id_end, 0, false,
11fdf7f2
TL
494 boost::none, m_snap_seqs, &no_op,
495 &ctx);
496 request->send();
497
498 SnapMap snap_map(m_snap_map);
499 snap_map.erase(snap_map.begin());
500 ASSERT_EQ(snap_map, wait_for_snap_map(mock_object_copy_request));
501
502 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0));
503 ASSERT_EQ(0, ctx.wait());
504}
505
506TEST_F(TestMockDeepCopyImageCopyRequest, RestartPartialSync) {
507 librados::snap_t snap_id_end;
508 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
509
510 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
511 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
512 MockObjectCopyRequest mock_object_copy_request;
513
514 InSequence seq;
9f95a23c
TL
515 MockDiffRequest mock_diff_request;
516 expect_diff_send(mock_diff_request, {}, -EINVAL);
11fdf7f2
TL
517 expect_get_image_size(mock_src_image_ctx, 2 * (1 << m_src_image_ctx->order));
518 expect_get_image_size(mock_src_image_ctx, 0);
f67539c2 519 expect_object_copy_send(mock_object_copy_request, 0);
11fdf7f2 520
1911f103 521 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
522 C_SaferCond ctx;
523 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
524 &mock_dst_image_ctx,
9f95a23c 525 0, snap_id_end, 0, false,
11fdf7f2
TL
526 librbd::deep_copy::ObjectNumber{0U},
527 m_snap_seqs, &no_op, &ctx);
528 request->send();
529
530 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 1, nullptr, 0));
531 ASSERT_EQ(0, ctx.wait());
532}
533
534TEST_F(TestMockDeepCopyImageCopyRequest, Cancel) {
535 std::string max_ops_str;
536 ASSERT_EQ(0, _rados.conf_get("rbd_concurrent_management_ops", max_ops_str));
537 ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", "1"));
538 BOOST_SCOPE_EXIT( (max_ops_str) ) {
539 ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops",
540 max_ops_str.c_str()));
541 } BOOST_SCOPE_EXIT_END;
542
543 librados::snap_t snap_id_end;
544 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
545
546 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
547 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
548 MockObjectCopyRequest mock_object_copy_request;
549
550 InSequence seq;
9f95a23c
TL
551 MockDiffRequest mock_diff_request;
552 expect_diff_send(mock_diff_request, {}, -EINVAL);
11fdf7f2
TL
553 expect_get_image_size(mock_src_image_ctx, 1 << m_src_image_ctx->order);
554 expect_get_image_size(mock_src_image_ctx, 0);
f67539c2 555 expect_object_copy_send(mock_object_copy_request, 0);
11fdf7f2 556
1911f103 557 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
558 C_SaferCond ctx;
559 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
560 &mock_dst_image_ctx,
9f95a23c 561 0, snap_id_end, 0, false, boost::none,
11fdf7f2
TL
562 m_snap_seqs, &no_op, &ctx);
563 request->send();
564
565 ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request));
566 request->cancel();
567
568 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0));
569 ASSERT_EQ(-ECANCELED, ctx.wait());
570}
571
572TEST_F(TestMockDeepCopyImageCopyRequest, Cancel_Inflight_Sync) {
573 std::string max_ops_str;
574 ASSERT_EQ(0, _rados.conf_get("rbd_concurrent_management_ops", max_ops_str));
575 ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops", "3"));
576 BOOST_SCOPE_EXIT( (max_ops_str) ) {
577 ASSERT_EQ(0, _rados.conf_set("rbd_concurrent_management_ops",
578 max_ops_str.c_str()));
579 } BOOST_SCOPE_EXIT_END;
580
581 librados::snap_t snap_id_end;
582 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
583
584 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
585 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
586 MockObjectCopyRequest mock_object_copy_request;
587
588 InSequence seq;
9f95a23c
TL
589 MockDiffRequest mock_diff_request;
590 expect_diff_send(mock_diff_request, {}, -EINVAL);
11fdf7f2
TL
591 expect_get_image_size(mock_src_image_ctx, 6 * (1 << m_src_image_ctx->order));
592 expect_get_image_size(mock_src_image_ctx, m_image_size);
593
594 EXPECT_CALL(mock_object_copy_request, send()).Times(6);
595
1911f103 596 struct Handler : public librbd::deep_copy::NoOpHandler {
11fdf7f2
TL
597 librbd::deep_copy::ObjectNumber object_number;
598
599 int update_progress(uint64_t object_no, uint64_t end_object_no) override {
600 object_number = object_number ? *object_number + 1 : 0;
601 return 0;
602 }
1911f103 603 } handler;
11fdf7f2
TL
604
605 C_SaferCond ctx;
606 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
607 &mock_dst_image_ctx,
9f95a23c 608 0, snap_id_end, 0, false, boost::none,
1911f103 609 m_snap_seqs, &handler, &ctx);
11fdf7f2
TL
610 request->send();
611
612 ASSERT_EQ(m_snap_map, wait_for_snap_map(mock_object_copy_request));
613
614 Context *cancel_ctx = nullptr;
615 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 0, nullptr, 0));
616 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 1, nullptr, 0));
617 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 2, nullptr, 0));
618 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 3, &cancel_ctx,
619 0));
620 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 4, nullptr, 0));
621 ASSERT_TRUE(complete_object_copy(mock_object_copy_request, 5, nullptr, 0));
622
623 request->cancel();
624 cancel_ctx->complete(0);
625
626 ASSERT_EQ(-ECANCELED, ctx.wait());
1911f103 627 ASSERT_EQ(5u, handler.object_number.get());
11fdf7f2
TL
628}
629
630TEST_F(TestMockDeepCopyImageCopyRequest, MissingSnap) {
631 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
632 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
633
1911f103 634 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
635 C_SaferCond ctx;
636 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
637 &mock_dst_image_ctx,
9f95a23c 638 0, 123, 0, false, boost::none,
11fdf7f2
TL
639 m_snap_seqs, &no_op, &ctx);
640 request->send();
641 ASSERT_EQ(-EINVAL, ctx.wait());
642}
643
644TEST_F(TestMockDeepCopyImageCopyRequest, MissingFromSnap) {
645 librados::snap_t snap_id_end;
646 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
647
648 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
649 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
650
1911f103 651 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
652 C_SaferCond ctx;
653 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
654 &mock_dst_image_ctx,
9f95a23c
TL
655 123, snap_id_end, 0, false,
656 boost::none, m_snap_seqs, &no_op,
657 &ctx);
11fdf7f2
TL
658 request->send();
659 ASSERT_EQ(-EINVAL, ctx.wait());
660}
661
662TEST_F(TestMockDeepCopyImageCopyRequest, EmptySnapMap) {
663 librados::snap_t snap_id_start;
664 librados::snap_t snap_id_end;
665 ASSERT_EQ(0, create_snap("snap1", &snap_id_start));
666 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
667
668 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
669 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
670
1911f103 671 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
672 C_SaferCond ctx;
673 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
674 &mock_dst_image_ctx,
9f95a23c 675 snap_id_start, snap_id_end, 0, false,
11fdf7f2
TL
676 boost::none, {{0, 0}}, &no_op, &ctx);
677 request->send();
678 ASSERT_EQ(-EINVAL, ctx.wait());
679}
680
681TEST_F(TestMockDeepCopyImageCopyRequest, EmptySnapSeqs) {
682 librados::snap_t snap_id_start;
683 librados::snap_t snap_id_end;
684 ASSERT_EQ(0, create_snap("snap1", &snap_id_start));
685 ASSERT_EQ(0, create_snap("copy", &snap_id_end));
686
687 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
688 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
689
1911f103 690 librbd::deep_copy::NoOpHandler no_op;
11fdf7f2
TL
691 C_SaferCond ctx;
692 auto request = new MockImageCopyRequest(&mock_src_image_ctx,
693 &mock_dst_image_ctx,
9f95a23c 694 snap_id_start, snap_id_end, 0, false,
11fdf7f2
TL
695 boost::none, {}, &no_op, &ctx);
696 request->send();
697 ASSERT_EQ(-EINVAL, ctx.wait());
698}
699
700} // namespace deep_copy
701} // namespace librbd