]> git.proxmox.com Git - ceph.git/blob - 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
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
19 namespace librbd {
20
21 namespace {
22
23 struct MockTestImageCtx : public librbd::MockImageCtx {
24 MockTestImageCtx(librbd::ImageCtx &image_ctx)
25 : librbd::MockImageCtx(image_ctx) {
26 }
27 };
28
29 } // anonymous namespace
30
31 namespace journal {
32
33 template <>
34 struct TypeTraits<librbd::MockTestImageCtx> {
35 typedef ::journal::MockJournaler Journaler;
36 };
37
38 } // namespace journal
39 } // namespace librbd
40
41 // template definitions
42 template class rbd::mirror::ImageSync<librbd::MockTestImageCtx>;
43 #include "tools/rbd_mirror/ImageSync.cc"
44
45 namespace rbd {
46 namespace mirror {
47
48 template<>
49 struct 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
55 namespace image_sync {
56
57 template <>
58 class ImageCopyRequest<librbd::MockTestImageCtx> {
59 public:
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
90 template <>
91 class SnapshotCopyRequest<librbd::MockTestImageCtx> {
92 public:
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
122 template <>
123 class SyncPointCreateRequest<librbd::MockTestImageCtx> {
124 public:
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
144 template <>
145 class SyncPointPruneRequest<librbd::MockTestImageCtx> {
146 public:
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
168 ImageCopyRequest<librbd::MockTestImageCtx>* ImageCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
169 SnapshotCopyRequest<librbd::MockTestImageCtx>* SnapshotCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
170 SyncPointCreateRequest<librbd::MockTestImageCtx>* SyncPointCreateRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
171 SyncPointPruneRequest<librbd::MockTestImageCtx>* SyncPointPruneRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
172
173 } // namespace image_sync
174
175 using ::testing::_;
176 using ::testing::InSequence;
177 using ::testing::Invoke;
178 using ::testing::Return;
179 using ::testing::ReturnNew;
180 using ::testing::WithArg;
181 using ::testing::InvokeWithoutArgs;
182
183 class TestMockImageSync : public TestMockFixture {
184 public:
185 typedef ImageSync<librbd::MockTestImageCtx> MockImageSync;
186 typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
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
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
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,
301 MockInstanceWatcher &mock_instance_watcher,
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,
306 m_threads->work_queue, &mock_instance_watcher,
307 ctx);
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
315 TEST_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;
319 MockInstanceWatcher mock_instance_watcher;
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
325 librbd::MockExclusiveLock mock_exclusive_lock;
326 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
327
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;
333 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
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);
337 expect_start_op(mock_exclusive_lock);
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);
342 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
343
344 C_SaferCond ctx;
345 MockImageSync *request = create_request(mock_remote_image_ctx,
346 mock_local_image_ctx, mock_journaler,
347 mock_instance_watcher, &ctx);
348 request->send();
349 ASSERT_EQ(0, ctx.wait());
350 }
351
352 TEST_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;
356 MockInstanceWatcher mock_instance_watcher;
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
367 librbd::MockExclusiveLock mock_exclusive_lock;
368 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
369
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;
375 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
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);
379 expect_start_op(mock_exclusive_lock);
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);
384 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
385
386 C_SaferCond ctx;
387 MockImageSync *request = create_request(mock_remote_image_ctx,
388 mock_local_image_ctx, mock_journaler,
389 mock_instance_watcher, &ctx);
390 request->send();
391 ASSERT_EQ(0, ctx.wait());
392 }
393
394 TEST_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
433 TEST_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;
437 MockInstanceWatcher mock_instance_watcher;
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
443 librbd::MockExclusiveLock mock_exclusive_lock;
444 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
445
446 m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", boost::none}};
447
448 InSequence seq;
449 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
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 }));
458 expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
459 false);
460 EXPECT_CALL(mock_image_copy_request, cancel());
461 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
462
463 C_SaferCond ctx;
464 MockImageSync *request = create_request(mock_remote_image_ctx,
465 mock_local_image_ctx, mock_journaler,
466 mock_instance_watcher, &ctx);
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
479 TEST_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;
483 MockInstanceWatcher mock_instance_watcher;
484 MockSnapshotCopyRequest mock_snapshot_copy_request;
485 MockSyncPointCreateRequest mock_sync_point_create_request;
486
487 librbd::MockExclusiveLock mock_exclusive_lock;
488 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
489
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,
496 mock_local_image_ctx, mock_journaler,
497 mock_instance_watcher, &ctx);
498 InSequence seq;
499 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
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 }))));
508 expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
509 false);
510 EXPECT_CALL(mock_snapshot_copy_request, cancel());
511 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
512
513 request->send();
514 ASSERT_EQ(-ECANCELED, ctx.wait());
515 }
516
517 TEST_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;
521 MockInstanceWatcher mock_instance_watcher;
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
527 librbd::MockExclusiveLock mock_exclusive_lock;
528 mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock;
529
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,
536 mock_local_image_ctx, mock_journaler,
537 mock_instance_watcher, &ctx);
538 InSequence seq;
539 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
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 }))));
549 expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
550 false);
551 EXPECT_CALL(mock_image_copy_request, cancel());
552 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
553
554 request->send();
555 ASSERT_EQ(-ECANCELED, ctx.wait());
556 }
557
558 } // namespace mirror
559 } // namespace rbd