]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/rbd_mirror/test_mock_ImageSync.cc
update sources to v12.1.0
[ceph.git] / ceph / src / test / rbd_mirror / test_mock_ImageSync.cc
CommitLineData
7c673cae
FG
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/rbd_mirror/test_mock_fixture.h"
5#include "include/rbd/librbd.hpp"
6#include "librbd/journal/Types.h"
7#include "librbd/journal/TypeTraits.h"
8#include "test/journal/mock/MockJournaler.h"
9#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
10#include "test/librbd/mock/MockImageCtx.h"
11#include "test/librbd/mock/MockObjectMap.h"
12#include "tools/rbd_mirror/ImageSync.h"
13#include "tools/rbd_mirror/Threads.h"
14#include "tools/rbd_mirror/image_sync/ImageCopyRequest.h"
15#include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.h"
16#include "tools/rbd_mirror/image_sync/SyncPointCreateRequest.h"
17#include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.h"
18
19namespace librbd {
20
21namespace {
22
23struct MockTestImageCtx : public librbd::MockImageCtx {
24 MockTestImageCtx(librbd::ImageCtx &image_ctx)
25 : librbd::MockImageCtx(image_ctx) {
26 }
27};
28
29} // anonymous namespace
30
31namespace journal {
32
33template <>
34struct TypeTraits<librbd::MockTestImageCtx> {
35 typedef ::journal::MockJournaler Journaler;
36};
37
38} // namespace journal
39} // namespace librbd
40
41// template definitions
42template class rbd::mirror::ImageSync<librbd::MockTestImageCtx>;
43#include "tools/rbd_mirror/ImageSync.cc"
44
45namespace rbd {
46namespace mirror {
47
31f18b77
FG
48template<>
49struct InstanceWatcher<librbd::MockTestImageCtx> {
50 MOCK_METHOD2(notify_sync_request, void(const std::string, Context *));
51 MOCK_METHOD1(cancel_sync_request, bool(const std::string &));
52 MOCK_METHOD1(notify_sync_complete, void(const std::string &));
53};
54
7c673cae
FG
55namespace image_sync {
56
57template <>
58class ImageCopyRequest<librbd::MockTestImageCtx> {
59public:
60 static ImageCopyRequest* s_instance;
61 Context *on_finish;
62
63 static ImageCopyRequest* create(librbd::MockTestImageCtx *local_image_ctx,
64 librbd::MockTestImageCtx *remote_image_ctx,
65 SafeTimer *timer, Mutex *timer_lock,
66 journal::MockJournaler *journaler,
67 librbd::journal::MirrorPeerClientMeta *client_meta,
68 librbd::journal::MirrorPeerSyncPoint *sync_point,
69 Context *on_finish,
70 rbd::mirror::ProgressContext *progress_ctx = nullptr) {
71 assert(s_instance != nullptr);
72 s_instance->on_finish = on_finish;
73 return s_instance;
74 }
75
76 ImageCopyRequest() {
77 s_instance = this;
78 }
79
80 void put() {
81 }
82
83 void get() {
84 }
85
86 MOCK_METHOD0(cancel, void());
87 MOCK_METHOD0(send, void());
88};
89
90template <>
91class SnapshotCopyRequest<librbd::MockTestImageCtx> {
92public:
93 static SnapshotCopyRequest* s_instance;
94 Context *on_finish;
95
96 static SnapshotCopyRequest* create(librbd::MockTestImageCtx *local_image_ctx,
97 librbd::MockTestImageCtx *remote_image_ctx,
98 SnapshotCopyRequest<librbd::ImageCtx>::SnapMap *snap_map,
99 journal::MockJournaler *journaler,
100 librbd::journal::MirrorPeerClientMeta *client_meta,
101 ContextWQ *work_queue,
102 Context *on_finish) {
103 assert(s_instance != nullptr);
104 s_instance->on_finish = on_finish;
105 return s_instance;
106 }
107
108 SnapshotCopyRequest() {
109 s_instance = this;
110 }
111
112 void put() {
113 }
114
115 void get() {
116 }
117
118 MOCK_METHOD0(send, void());
119 MOCK_METHOD0(cancel, void());
120};
121
122template <>
123class SyncPointCreateRequest<librbd::MockTestImageCtx> {
124public:
125 static SyncPointCreateRequest *s_instance;
126 Context *on_finish;
127
128 static SyncPointCreateRequest* create(librbd::MockTestImageCtx *remote_image_ctx,
129 const std::string &mirror_uuid,
130 journal::MockJournaler *journaler,
131 librbd::journal::MirrorPeerClientMeta *client_meta,
132 Context *on_finish) {
133 assert(s_instance != nullptr);
134 s_instance->on_finish = on_finish;
135 return s_instance;
136 }
137
138 SyncPointCreateRequest() {
139 s_instance = this;
140 }
141 MOCK_METHOD0(send, void());
142};
143
144template <>
145class SyncPointPruneRequest<librbd::MockTestImageCtx> {
146public:
147 static SyncPointPruneRequest *s_instance;
148 Context *on_finish;
149 bool sync_complete;
150
151 static SyncPointPruneRequest* create(librbd::MockTestImageCtx *remote_image_ctx,
152 bool sync_complete,
153 journal::MockJournaler *journaler,
154 librbd::journal::MirrorPeerClientMeta *client_meta,
155 Context *on_finish) {
156 assert(s_instance != nullptr);
157 s_instance->on_finish = on_finish;
158 s_instance->sync_complete = sync_complete;
159 return s_instance;
160 }
161
162 SyncPointPruneRequest() {
163 s_instance = this;
164 }
165 MOCK_METHOD0(send, void());
166};
167
168ImageCopyRequest<librbd::MockTestImageCtx>* ImageCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
169SnapshotCopyRequest<librbd::MockTestImageCtx>* SnapshotCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
170SyncPointCreateRequest<librbd::MockTestImageCtx>* SyncPointCreateRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
171SyncPointPruneRequest<librbd::MockTestImageCtx>* SyncPointPruneRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
172
173} // namespace image_sync
174
175using ::testing::_;
176using ::testing::InSequence;
177using ::testing::Invoke;
178using ::testing::Return;
31f18b77 179using ::testing::ReturnNew;
7c673cae
FG
180using ::testing::WithArg;
181using ::testing::InvokeWithoutArgs;
182
183class TestMockImageSync : public TestMockFixture {
184public:
185 typedef ImageSync<librbd::MockTestImageCtx> MockImageSync;
31f18b77 186 typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
7c673cae
FG
187 typedef image_sync::ImageCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest;
188 typedef image_sync::SnapshotCopyRequest<librbd::MockTestImageCtx> MockSnapshotCopyRequest;
189 typedef image_sync::SyncPointCreateRequest<librbd::MockTestImageCtx> MockSyncPointCreateRequest;
190 typedef image_sync::SyncPointPruneRequest<librbd::MockTestImageCtx> MockSyncPointPruneRequest;
191
192 void SetUp() override {
193 TestMockFixture::SetUp();
194
195 librbd::RBD rbd;
196 ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size));
197 ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx));
198
199 ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size));
200 ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx));
201 }
202
31f18b77
FG
203 void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) {
204 EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce(
205 ReturnNew<FunctionContext>([](int) {}));
206 }
207
208 void expect_notify_sync_request(MockInstanceWatcher &mock_instance_watcher,
209 const std::string &sync_id, int r) {
210 EXPECT_CALL(mock_instance_watcher, notify_sync_request(sync_id, _))
211 .WillOnce(Invoke([this, r](const std::string &, Context *on_sync_start) {
212 m_threads->work_queue->queue(on_sync_start, r);
213 }));
214 }
215
216 void expect_cancel_sync_request(MockInstanceWatcher &mock_instance_watcher,
217 const std::string &sync_id, bool canceled) {
218 EXPECT_CALL(mock_instance_watcher, cancel_sync_request(sync_id))
219 .WillOnce(Return(canceled));
220 }
221
222 void expect_notify_sync_complete(MockInstanceWatcher &mock_instance_watcher,
223 const std::string &sync_id) {
224 EXPECT_CALL(mock_instance_watcher, notify_sync_complete(sync_id));
225 }
226
7c673cae
FG
227 void expect_create_sync_point(librbd::MockTestImageCtx &mock_local_image_ctx,
228 MockSyncPointCreateRequest &mock_sync_point_create_request,
229 int r) {
230 EXPECT_CALL(mock_sync_point_create_request, send())
231 .WillOnce(Invoke([this, &mock_local_image_ctx, &mock_sync_point_create_request, r]() {
232 if (r == 0) {
233 mock_local_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(),
234 "snap1"}] = 123;
235 m_client_meta.sync_points.emplace_back(cls::rbd::UserSnapshotNamespace(),
236 "snap1",
237 boost::none);
238 }
239 m_threads->work_queue->queue(mock_sync_point_create_request.on_finish, r);
240 }));
241 }
242
243 void expect_copy_snapshots(MockSnapshotCopyRequest &mock_snapshot_copy_request, int r) {
244 EXPECT_CALL(mock_snapshot_copy_request, send())
245 .WillOnce(Invoke([this, &mock_snapshot_copy_request, r]() {
246 m_threads->work_queue->queue(mock_snapshot_copy_request.on_finish, r);
247 }));
248 }
249
250 void expect_copy_image(MockImageCopyRequest &mock_image_copy_request, int r) {
251 EXPECT_CALL(mock_image_copy_request, send())
252 .WillOnce(Invoke([this, &mock_image_copy_request, r]() {
253 m_threads->work_queue->queue(mock_image_copy_request.on_finish, r);
254 }));
255 }
256
257 void expect_rollback_object_map(librbd::MockObjectMap &mock_object_map, int r) {
258 if ((m_local_image_ctx->features & RBD_FEATURE_OBJECT_MAP) != 0) {
259 EXPECT_CALL(mock_object_map, rollback(_, _))
260 .WillOnce(WithArg<1>(Invoke([this, r](Context *ctx) {
261 m_threads->work_queue->queue(ctx, r);
262 })));
263 }
264 }
265
266 void expect_create_object_map(librbd::MockTestImageCtx &mock_image_ctx,
267 librbd::MockObjectMap *mock_object_map) {
268 EXPECT_CALL(mock_image_ctx, create_object_map(CEPH_NOSNAP))
269 .WillOnce(Return(mock_object_map));
270 }
271
272 void expect_open_object_map(librbd::MockTestImageCtx &mock_image_ctx,
273 librbd::MockObjectMap &mock_object_map) {
274 EXPECT_CALL(mock_object_map, open(_))
275 .WillOnce(Invoke([this](Context *ctx) {
276 m_threads->work_queue->queue(ctx, 0);
277 }));
278 }
279
280 void expect_prune_sync_point(MockSyncPointPruneRequest &mock_sync_point_prune_request,
281 bool sync_complete, int r) {
282 EXPECT_CALL(mock_sync_point_prune_request, send())
283 .WillOnce(Invoke([this, &mock_sync_point_prune_request, sync_complete, r]() {
284 ASSERT_EQ(sync_complete, mock_sync_point_prune_request.sync_complete);
285 if (r == 0 && !m_client_meta.sync_points.empty()) {
286 if (sync_complete) {
287 m_client_meta.sync_points.pop_front();
288 } else {
289 while (m_client_meta.sync_points.size() > 1) {
290 m_client_meta.sync_points.pop_back();
291 }
292 }
293 }
294 m_threads->work_queue->queue(mock_sync_point_prune_request.on_finish, r);
295 }));
296 }
297
298 MockImageSync *create_request(librbd::MockTestImageCtx &mock_remote_image_ctx,
299 librbd::MockTestImageCtx &mock_local_image_ctx,
300 journal::MockJournaler &mock_journaler,
31f18b77 301 MockInstanceWatcher &mock_instance_watcher,
7c673cae
FG
302 Context *ctx) {
303 return new MockImageSync(&mock_local_image_ctx, &mock_remote_image_ctx,
304 m_threads->timer, &m_threads->timer_lock,
305 "mirror-uuid", &mock_journaler, &m_client_meta,
31f18b77
FG
306 m_threads->work_queue, &mock_instance_watcher,
307 ctx);
7c673cae
FG
308 }
309
310 librbd::ImageCtx *m_remote_image_ctx;
311 librbd::ImageCtx *m_local_image_ctx;
312 librbd::journal::MirrorPeerClientMeta m_client_meta;
313};
314
315TEST_F(TestMockImageSync, SimpleSync) {
316 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
317 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
318 journal::MockJournaler mock_journaler;
31f18b77 319 MockInstanceWatcher mock_instance_watcher;
7c673cae
FG
320 MockImageCopyRequest mock_image_copy_request;
321 MockSnapshotCopyRequest mock_snapshot_copy_request;
322 MockSyncPointCreateRequest mock_sync_point_create_request;
323 MockSyncPointPruneRequest mock_sync_point_prune_request;
324
31f18b77
FG
325 librbd::MockExclusiveLock mock_exclusive_lock;
326 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
327
7c673cae
FG
328 librbd::MockObjectMap *mock_object_map = new librbd::MockObjectMap();
329 mock_local_image_ctx.object_map = mock_object_map;
330 expect_test_features(mock_local_image_ctx);
331
332 InSequence seq;
31f18b77 333 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae
FG
334 expect_create_sync_point(mock_local_image_ctx, mock_sync_point_create_request, 0);
335 expect_copy_snapshots(mock_snapshot_copy_request, 0);
336 expect_copy_image(mock_image_copy_request, 0);
31f18b77 337 expect_start_op(mock_exclusive_lock);
7c673cae
FG
338 expect_rollback_object_map(*mock_object_map, 0);
339 expect_create_object_map(mock_local_image_ctx, mock_object_map);
340 expect_open_object_map(mock_local_image_ctx, *mock_object_map);
341 expect_prune_sync_point(mock_sync_point_prune_request, true, 0);
31f18b77 342 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
343
344 C_SaferCond ctx;
345 MockImageSync *request = create_request(mock_remote_image_ctx,
31f18b77
FG
346 mock_local_image_ctx, mock_journaler,
347 mock_instance_watcher, &ctx);
7c673cae
FG
348 request->send();
349 ASSERT_EQ(0, ctx.wait());
350}
351
352TEST_F(TestMockImageSync, RestartSync) {
353 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
354 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
355 journal::MockJournaler mock_journaler;
31f18b77 356 MockInstanceWatcher mock_instance_watcher;
7c673cae
FG
357 MockImageCopyRequest mock_image_copy_request;
358 MockSnapshotCopyRequest mock_snapshot_copy_request;
359 MockSyncPointCreateRequest mock_sync_point_create_request;
360 MockSyncPointPruneRequest mock_sync_point_prune_request;
361
362 m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", boost::none},
363 {cls::rbd::UserSnapshotNamespace(), "snap2", "snap1", boost::none}};
364 mock_local_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(), "snap1"}] = 123;
365 mock_local_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(), "snap2"}] = 234;
366
31f18b77
FG
367 librbd::MockExclusiveLock mock_exclusive_lock;
368 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
369
7c673cae
FG
370 librbd::MockObjectMap *mock_object_map = new librbd::MockObjectMap();
371 mock_local_image_ctx.object_map = mock_object_map;
372 expect_test_features(mock_local_image_ctx);
373
374 InSequence seq;
31f18b77 375 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae
FG
376 expect_prune_sync_point(mock_sync_point_prune_request, false, 0);
377 expect_copy_snapshots(mock_snapshot_copy_request, 0);
378 expect_copy_image(mock_image_copy_request, 0);
31f18b77 379 expect_start_op(mock_exclusive_lock);
7c673cae
FG
380 expect_rollback_object_map(*mock_object_map, 0);
381 expect_create_object_map(mock_local_image_ctx, mock_object_map);
382 expect_open_object_map(mock_local_image_ctx, *mock_object_map);
383 expect_prune_sync_point(mock_sync_point_prune_request, true, 0);
31f18b77 384 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
385
386 C_SaferCond ctx;
387 MockImageSync *request = create_request(mock_remote_image_ctx,
31f18b77
FG
388 mock_local_image_ctx, mock_journaler,
389 mock_instance_watcher, &ctx);
7c673cae
FG
390 request->send();
391 ASSERT_EQ(0, ctx.wait());
392}
393
31f18b77
FG
394TEST_F(TestMockImageSync, CancelNotifySyncRequest) {
395 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
396 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
397 journal::MockJournaler mock_journaler;
398 MockInstanceWatcher mock_instance_watcher;
399
400 InSequence seq;
401 Context *on_sync_start = nullptr;
402 C_SaferCond notify_sync_ctx;
403 EXPECT_CALL(mock_instance_watcher,
404 notify_sync_request(mock_local_image_ctx.id, _))
405 .WillOnce(Invoke([this, &on_sync_start, &notify_sync_ctx](
406 const std::string &, Context *ctx) {
407 on_sync_start = ctx;
408 notify_sync_ctx.complete(0);
409 }));
410 EXPECT_CALL(mock_instance_watcher,
411 cancel_sync_request(mock_local_image_ctx.id))
412 .WillOnce(Invoke([this, &on_sync_start](const std::string &) {
413 EXPECT_NE(nullptr, on_sync_start);
414 on_sync_start->complete(-ECANCELED);
415 return true;
416 }));
417
418 C_SaferCond ctx;
419 MockImageSync *request = create_request(mock_remote_image_ctx,
420 mock_local_image_ctx, mock_journaler,
421 mock_instance_watcher, &ctx);
422 request->get();
423 request->send();
424
425 // cancel the notify sync request once it starts
426 ASSERT_EQ(0, notify_sync_ctx.wait());
427 request->cancel();
428 request->put();
429
430 ASSERT_EQ(-ECANCELED, ctx.wait());
431}
432
7c673cae
FG
433TEST_F(TestMockImageSync, CancelImageCopy) {
434 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
435 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
436 journal::MockJournaler mock_journaler;
31f18b77 437 MockInstanceWatcher mock_instance_watcher;
7c673cae
FG
438 MockImageCopyRequest mock_image_copy_request;
439 MockSnapshotCopyRequest mock_snapshot_copy_request;
440 MockSyncPointCreateRequest mock_sync_point_create_request;
441 MockSyncPointPruneRequest mock_sync_point_prune_request;
442
31f18b77
FG
443 librbd::MockExclusiveLock mock_exclusive_lock;
444 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
445
7c673cae
FG
446 m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", boost::none}};
447
448 InSequence seq;
31f18b77 449 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae
FG
450 expect_prune_sync_point(mock_sync_point_prune_request, false, 0);
451 expect_copy_snapshots(mock_snapshot_copy_request, 0);
452
453 C_SaferCond image_copy_ctx;
454 EXPECT_CALL(mock_image_copy_request, send())
455 .WillOnce(Invoke([&image_copy_ctx]() {
456 image_copy_ctx.complete(0);
457 }));
31f18b77
FG
458 expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
459 false);
7c673cae 460 EXPECT_CALL(mock_image_copy_request, cancel());
31f18b77 461 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
462
463 C_SaferCond ctx;
464 MockImageSync *request = create_request(mock_remote_image_ctx,
31f18b77
FG
465 mock_local_image_ctx, mock_journaler,
466 mock_instance_watcher, &ctx);
7c673cae
FG
467 request->get();
468 request->send();
469
470 // cancel the image copy once it starts
471 ASSERT_EQ(0, image_copy_ctx.wait());
472 request->cancel();
473 request->put();
474 m_threads->work_queue->queue(mock_image_copy_request.on_finish, 0);
475
476 ASSERT_EQ(-ECANCELED, ctx.wait());
477}
478
479TEST_F(TestMockImageSync, CancelAfterCopySnapshots) {
480 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
481 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
482 journal::MockJournaler mock_journaler;
31f18b77 483 MockInstanceWatcher mock_instance_watcher;
7c673cae
FG
484 MockSnapshotCopyRequest mock_snapshot_copy_request;
485 MockSyncPointCreateRequest mock_sync_point_create_request;
486
31f18b77
FG
487 librbd::MockExclusiveLock mock_exclusive_lock;
488 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
489
7c673cae
FG
490 librbd::MockObjectMap *mock_object_map = new librbd::MockObjectMap();
491 mock_local_image_ctx.object_map = mock_object_map;
492 expect_test_features(mock_local_image_ctx);
493
494 C_SaferCond ctx;
495 MockImageSync *request = create_request(mock_remote_image_ctx,
31f18b77
FG
496 mock_local_image_ctx, mock_journaler,
497 mock_instance_watcher, &ctx);
7c673cae 498 InSequence seq;
31f18b77 499 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae
FG
500 expect_create_sync_point(mock_local_image_ctx, mock_sync_point_create_request, 0);
501 EXPECT_CALL(mock_snapshot_copy_request, send())
502 .WillOnce((DoAll(InvokeWithoutArgs([request]() {
503 request->cancel();
504 }),
505 Invoke([this, &mock_snapshot_copy_request]() {
506 m_threads->work_queue->queue(mock_snapshot_copy_request.on_finish, 0);
507 }))));
31f18b77
FG
508 expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
509 false);
7c673cae 510 EXPECT_CALL(mock_snapshot_copy_request, cancel());
31f18b77 511 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
512
513 request->send();
514 ASSERT_EQ(-ECANCELED, ctx.wait());
515}
516
517TEST_F(TestMockImageSync, CancelAfterCopyImage) {
518 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
519 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
520 journal::MockJournaler mock_journaler;
31f18b77 521 MockInstanceWatcher mock_instance_watcher;
7c673cae
FG
522 MockImageCopyRequest mock_image_copy_request;
523 MockSnapshotCopyRequest mock_snapshot_copy_request;
524 MockSyncPointCreateRequest mock_sync_point_create_request;
525 MockSyncPointPruneRequest mock_sync_point_prune_request;
526
31f18b77
FG
527 librbd::MockExclusiveLock mock_exclusive_lock;
528 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
529
7c673cae
FG
530 librbd::MockObjectMap *mock_object_map = new librbd::MockObjectMap();
531 mock_local_image_ctx.object_map = mock_object_map;
532 expect_test_features(mock_local_image_ctx);
533
534 C_SaferCond ctx;
535 MockImageSync *request = create_request(mock_remote_image_ctx,
31f18b77
FG
536 mock_local_image_ctx, mock_journaler,
537 mock_instance_watcher, &ctx);
7c673cae 538 InSequence seq;
31f18b77 539 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae
FG
540 expect_create_sync_point(mock_local_image_ctx, mock_sync_point_create_request, 0);
541 expect_copy_snapshots(mock_snapshot_copy_request, 0);
542 EXPECT_CALL(mock_image_copy_request, send())
543 .WillOnce((DoAll(InvokeWithoutArgs([request]() {
544 request->cancel();
545 }),
546 Invoke([this, &mock_image_copy_request]() {
547 m_threads->work_queue->queue(mock_image_copy_request.on_finish, 0);
548 }))));
31f18b77
FG
549 expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
550 false);
7c673cae 551 EXPECT_CALL(mock_image_copy_request, cancel());
31f18b77 552 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
553
554 request->send();
555 ASSERT_EQ(-ECANCELED, ctx.wait());
556}
557
558} // namespace mirror
559} // namespace rbd