]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/rbd_mirror/test_mock_ImageSync.cc
743418325ced0d1d65802ed057b3d3063d13453c
[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/DeepCopyRequest.h"
7 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
8 #include "test/librbd/mock/MockImageCtx.h"
9 #include "test/rbd_mirror/mock/image_sync/MockSyncPointHandler.h"
10 #include "tools/rbd_mirror/ImageSync.h"
11 #include "tools/rbd_mirror/Threads.h"
12 #include "tools/rbd_mirror/image_sync/SyncPointCreateRequest.h"
13 #include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.h"
14
15 namespace librbd {
16
17 namespace {
18
19 struct MockTestImageCtx : public librbd::MockImageCtx {
20 explicit MockTestImageCtx(librbd::ImageCtx &image_ctx)
21 : librbd::MockImageCtx(image_ctx) {
22 }
23 };
24
25 } // anonymous namespace
26
27 template <>
28 class DeepCopyRequest<librbd::MockTestImageCtx> {
29 public:
30 static DeepCopyRequest* s_instance;
31 Context *on_finish;
32
33 static DeepCopyRequest* create(
34 librbd::MockTestImageCtx *src_image_ctx,
35 librbd::MockTestImageCtx *dst_image_ctx,
36 librados::snap_t src_snap_id_start, librados::snap_t src_snap_id_end,
37 librados::snap_t dst_snap_id_start, bool flatten,
38 const librbd::deep_copy::ObjectNumber &object_number,
39 ContextWQ *work_queue, SnapSeqs *snap_seqs, ProgressContext *prog_ctx,
40 Context *on_finish) {
41 ceph_assert(s_instance != nullptr);
42 s_instance->on_finish = on_finish;
43 return s_instance;
44 }
45
46 DeepCopyRequest() {
47 s_instance = this;
48 }
49
50 void put() {
51 }
52
53 void get() {
54 }
55
56 MOCK_METHOD0(cancel, void());
57 MOCK_METHOD0(send, void());
58 };
59
60 DeepCopyRequest<librbd::MockTestImageCtx>* DeepCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
61
62 } // namespace librbd
63
64 // template definitions
65 template class rbd::mirror::ImageSync<librbd::MockTestImageCtx>;
66 #include "tools/rbd_mirror/ImageSync.cc"
67
68 namespace rbd {
69 namespace mirror {
70
71 template <>
72 struct Threads<librbd::MockTestImageCtx> {
73 ceph::mutex &timer_lock;
74 SafeTimer *timer;
75 ContextWQ *work_queue;
76
77 Threads(Threads<librbd::ImageCtx> *threads)
78 : timer_lock(threads->timer_lock), timer(threads->timer),
79 work_queue(threads->work_queue) {
80 }
81 };
82
83 template<>
84 struct InstanceWatcher<librbd::MockTestImageCtx> {
85 MOCK_METHOD2(notify_sync_request, void(const std::string, Context *));
86 MOCK_METHOD1(cancel_sync_request, bool(const std::string &));
87 MOCK_METHOD1(notify_sync_complete, void(const std::string &));
88 };
89
90 namespace image_sync {
91
92 template <>
93 class SyncPointCreateRequest<librbd::MockTestImageCtx> {
94 public:
95 static SyncPointCreateRequest *s_instance;
96 Context *on_finish;
97
98 static SyncPointCreateRequest* create(librbd::MockTestImageCtx *remote_image_ctx,
99 const std::string &mirror_uuid,
100 image_sync::SyncPointHandler* sync_point_handler,
101 Context *on_finish) {
102 ceph_assert(s_instance != nullptr);
103 s_instance->on_finish = on_finish;
104 return s_instance;
105 }
106
107 SyncPointCreateRequest() {
108 s_instance = this;
109 }
110 MOCK_METHOD0(send, void());
111 };
112
113 template <>
114 class SyncPointPruneRequest<librbd::MockTestImageCtx> {
115 public:
116 static SyncPointPruneRequest *s_instance;
117 Context *on_finish;
118 bool sync_complete;
119
120 static SyncPointPruneRequest* create(librbd::MockTestImageCtx *remote_image_ctx,
121 bool sync_complete,
122 image_sync::SyncPointHandler* sync_point_handler,
123 Context *on_finish) {
124 ceph_assert(s_instance != nullptr);
125 s_instance->on_finish = on_finish;
126 s_instance->sync_complete = sync_complete;
127 return s_instance;
128 }
129
130 SyncPointPruneRequest() {
131 s_instance = this;
132 }
133 MOCK_METHOD0(send, void());
134 };
135
136 SyncPointCreateRequest<librbd::MockTestImageCtx>* SyncPointCreateRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
137 SyncPointPruneRequest<librbd::MockTestImageCtx>* SyncPointPruneRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
138
139 } // namespace image_sync
140
141 using ::testing::_;
142 using ::testing::DoAll;
143 using ::testing::InSequence;
144 using ::testing::Invoke;
145 using ::testing::Return;
146 using ::testing::StrEq;
147 using ::testing::WithArg;
148 using ::testing::InvokeWithoutArgs;
149
150 class TestMockImageSync : public TestMockFixture {
151 public:
152 typedef Threads<librbd::MockTestImageCtx> MockThreads;
153 typedef ImageSync<librbd::MockTestImageCtx> MockImageSync;
154 typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
155 typedef image_sync::SyncPointCreateRequest<librbd::MockTestImageCtx> MockSyncPointCreateRequest;
156 typedef image_sync::SyncPointPruneRequest<librbd::MockTestImageCtx> MockSyncPointPruneRequest;
157 typedef image_sync::MockSyncPointHandler MockSyncPointHandler;
158 typedef librbd::DeepCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest;
159
160 void SetUp() override {
161 TestMockFixture::SetUp();
162
163 librbd::RBD rbd;
164 ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size));
165 ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx));
166
167 ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size));
168 ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx));
169 }
170
171 void expect_get_snap_id(librbd::MockTestImageCtx &mock_image_ctx) {
172 EXPECT_CALL(mock_image_ctx, get_snap_id(_, _))
173 .WillOnce(Return(123));
174 }
175
176 void expect_notify_sync_request(MockInstanceWatcher &mock_instance_watcher,
177 const std::string &sync_id, int r) {
178 EXPECT_CALL(mock_instance_watcher, notify_sync_request(sync_id, _))
179 .WillOnce(Invoke([this, r](const std::string &, Context *on_sync_start) {
180 m_threads->work_queue->queue(on_sync_start, r);
181 }));
182 }
183
184 void expect_cancel_sync_request(MockInstanceWatcher &mock_instance_watcher,
185 const std::string &sync_id, bool canceled) {
186 EXPECT_CALL(mock_instance_watcher, cancel_sync_request(sync_id))
187 .WillOnce(Return(canceled));
188 }
189
190 void expect_notify_sync_complete(MockInstanceWatcher &mock_instance_watcher,
191 const std::string &sync_id) {
192 EXPECT_CALL(mock_instance_watcher, notify_sync_complete(sync_id));
193 }
194
195 void expect_create_sync_point(librbd::MockTestImageCtx &mock_local_image_ctx,
196 MockSyncPointCreateRequest &mock_sync_point_create_request,
197 int r) {
198 EXPECT_CALL(mock_sync_point_create_request, send())
199 .WillOnce(Invoke([this, &mock_local_image_ctx, &mock_sync_point_create_request, r]() {
200 if (r == 0) {
201 mock_local_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(),
202 "snap1"}] = 123;
203 m_sync_points.emplace_back(cls::rbd::UserSnapshotNamespace(),
204 "snap1", "", boost::none);
205 }
206 m_threads->work_queue->queue(mock_sync_point_create_request.on_finish, r);
207 }));
208 }
209
210 void expect_copy_image(MockImageCopyRequest &mock_image_copy_request, int r) {
211 EXPECT_CALL(mock_image_copy_request, send())
212 .WillOnce(Invoke([this, &mock_image_copy_request, r]() {
213 m_threads->work_queue->queue(mock_image_copy_request.on_finish, r);
214 }));
215 }
216
217 void expect_flush_sync_point(MockSyncPointHandler& mock_sync_point_handler,
218 int r) {
219 EXPECT_CALL(mock_sync_point_handler, update_sync_points(_, _, false, _))
220 .WillOnce(WithArg<3>(CompleteContext(r)));
221 }
222
223 void expect_prune_sync_point(MockSyncPointPruneRequest &mock_sync_point_prune_request,
224 bool sync_complete, int r) {
225 EXPECT_CALL(mock_sync_point_prune_request, send())
226 .WillOnce(Invoke([this, &mock_sync_point_prune_request, sync_complete, r]() {
227 ASSERT_EQ(sync_complete, mock_sync_point_prune_request.sync_complete);
228 if (r == 0 && !m_sync_points.empty()) {
229 if (sync_complete) {
230 m_sync_points.pop_front();
231 } else {
232 while (m_sync_points.size() > 1) {
233 m_sync_points.pop_back();
234 }
235 }
236 }
237 m_threads->work_queue->queue(mock_sync_point_prune_request.on_finish, r);
238 }));
239 }
240
241 void expect_get_snap_seqs(MockSyncPointHandler& mock_sync_point_handler) {
242 EXPECT_CALL(mock_sync_point_handler, get_snap_seqs())
243 .WillRepeatedly(Return(librbd::SnapSeqs{}));
244 }
245
246 void expect_get_sync_points(MockSyncPointHandler& mock_sync_point_handler) {
247 EXPECT_CALL(mock_sync_point_handler, get_sync_points())
248 .WillRepeatedly(Invoke([this]() {
249 return m_sync_points;
250 }));
251 }
252
253 MockImageSync *create_request(MockThreads& mock_threads,
254 librbd::MockTestImageCtx &mock_remote_image_ctx,
255 librbd::MockTestImageCtx &mock_local_image_ctx,
256 MockSyncPointHandler& mock_sync_point_handler,
257 MockInstanceWatcher &mock_instance_watcher,
258 Context *ctx) {
259 return new MockImageSync(&mock_threads, &mock_local_image_ctx,
260 &mock_remote_image_ctx,
261 "mirror-uuid", &mock_sync_point_handler,
262 &mock_instance_watcher, nullptr, ctx);
263 }
264
265 librbd::ImageCtx *m_remote_image_ctx;
266 librbd::ImageCtx *m_local_image_ctx;
267
268 image_sync::SyncPoints m_sync_points;
269 };
270
271 TEST_F(TestMockImageSync, SimpleSync) {
272 MockThreads mock_threads(m_threads);
273 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
274 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
275 MockSyncPointHandler mock_sync_point_handler;
276 MockInstanceWatcher mock_instance_watcher;
277 MockImageCopyRequest mock_image_copy_request;
278 MockSyncPointCreateRequest mock_sync_point_create_request;
279 MockSyncPointPruneRequest mock_sync_point_prune_request;
280
281 expect_get_snap_seqs(mock_sync_point_handler);
282 expect_get_sync_points(mock_sync_point_handler);
283
284 InSequence seq;
285 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
286 expect_create_sync_point(mock_local_image_ctx, mock_sync_point_create_request, 0);
287 expect_get_snap_id(mock_remote_image_ctx);
288 expect_copy_image(mock_image_copy_request, 0);
289 expect_flush_sync_point(mock_sync_point_handler, 0);
290 expect_prune_sync_point(mock_sync_point_prune_request, true, 0);
291 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
292
293 C_SaferCond ctx;
294 MockImageSync *request = create_request(mock_threads, mock_remote_image_ctx,
295 mock_local_image_ctx,
296 mock_sync_point_handler,
297 mock_instance_watcher, &ctx);
298 request->send();
299 ASSERT_EQ(0, ctx.wait());
300 }
301
302 TEST_F(TestMockImageSync, RestartSync) {
303 MockThreads mock_threads(m_threads);
304 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
305 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
306 MockSyncPointHandler mock_sync_point_handler;
307 MockInstanceWatcher mock_instance_watcher;
308 MockImageCopyRequest mock_image_copy_request;
309 MockSyncPointCreateRequest mock_sync_point_create_request;
310 MockSyncPointPruneRequest mock_sync_point_prune_request;
311
312 m_sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", "", boost::none},
313 {cls::rbd::UserSnapshotNamespace(), "snap2", "snap1", boost::none}};
314 mock_local_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(), "snap1"}] = 123;
315 mock_local_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(), "snap2"}] = 234;
316
317 expect_test_features(mock_local_image_ctx);
318 expect_get_snap_seqs(mock_sync_point_handler);
319 expect_get_sync_points(mock_sync_point_handler);
320
321 InSequence seq;
322 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
323 expect_prune_sync_point(mock_sync_point_prune_request, false, 0);
324 expect_get_snap_id(mock_remote_image_ctx);
325 expect_copy_image(mock_image_copy_request, 0);
326 expect_flush_sync_point(mock_sync_point_handler, 0);
327 expect_prune_sync_point(mock_sync_point_prune_request, true, 0);
328 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
329
330 C_SaferCond ctx;
331 MockImageSync *request = create_request(mock_threads, mock_remote_image_ctx,
332 mock_local_image_ctx,
333 mock_sync_point_handler,
334 mock_instance_watcher, &ctx);
335 request->send();
336 ASSERT_EQ(0, ctx.wait());
337 }
338
339 TEST_F(TestMockImageSync, CancelNotifySyncRequest) {
340 MockThreads mock_threads(m_threads);
341 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
342 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
343 MockSyncPointHandler mock_sync_point_handler;
344 MockInstanceWatcher mock_instance_watcher;
345
346 expect_get_snap_seqs(mock_sync_point_handler);
347 expect_get_sync_points(mock_sync_point_handler);
348
349 InSequence seq;
350 Context *on_sync_start = nullptr;
351 C_SaferCond notify_sync_ctx;
352 EXPECT_CALL(mock_instance_watcher,
353 notify_sync_request(mock_local_image_ctx.id, _))
354 .WillOnce(Invoke([&on_sync_start, &notify_sync_ctx](
355 const std::string &, Context *ctx) {
356 on_sync_start = ctx;
357 notify_sync_ctx.complete(0);
358 }));
359 EXPECT_CALL(mock_instance_watcher,
360 cancel_sync_request(mock_local_image_ctx.id))
361 .WillOnce(Invoke([&on_sync_start](const std::string &) {
362 EXPECT_NE(nullptr, on_sync_start);
363 on_sync_start->complete(-ECANCELED);
364 return true;
365 }));
366
367 C_SaferCond ctx;
368 MockImageSync *request = create_request(mock_threads, mock_remote_image_ctx,
369 mock_local_image_ctx,
370 mock_sync_point_handler,
371 mock_instance_watcher, &ctx);
372 request->get();
373 request->send();
374
375 // cancel the notify sync request once it starts
376 ASSERT_EQ(0, notify_sync_ctx.wait());
377 request->cancel();
378 request->put();
379
380 ASSERT_EQ(-ECANCELED, ctx.wait());
381 }
382
383 TEST_F(TestMockImageSync, CancelImageCopy) {
384 MockThreads mock_threads(m_threads);
385 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
386 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
387 MockSyncPointHandler mock_sync_point_handler;
388 MockInstanceWatcher mock_instance_watcher;
389 MockImageCopyRequest mock_image_copy_request;
390 MockSyncPointCreateRequest mock_sync_point_create_request;
391 MockSyncPointPruneRequest mock_sync_point_prune_request;
392
393 m_sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", "", boost::none}};
394 expect_get_snap_seqs(mock_sync_point_handler);
395 expect_get_sync_points(mock_sync_point_handler);
396
397 InSequence seq;
398 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
399 expect_prune_sync_point(mock_sync_point_prune_request, false, 0);
400 expect_get_snap_id(mock_remote_image_ctx);
401
402 C_SaferCond image_copy_ctx;
403 EXPECT_CALL(mock_image_copy_request, send())
404 .WillOnce(Invoke([&image_copy_ctx]() {
405 image_copy_ctx.complete(0);
406 }));
407 expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
408 false);
409 EXPECT_CALL(mock_image_copy_request, cancel());
410 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
411
412 C_SaferCond ctx;
413 MockImageSync *request = create_request(mock_threads, mock_remote_image_ctx,
414 mock_local_image_ctx,
415 mock_sync_point_handler,
416 mock_instance_watcher, &ctx);
417 request->get();
418 request->send();
419
420 // cancel the image copy once it starts
421 ASSERT_EQ(0, image_copy_ctx.wait());
422 request->cancel();
423 request->put();
424 m_threads->work_queue->queue(mock_image_copy_request.on_finish, 0);
425
426 ASSERT_EQ(-ECANCELED, ctx.wait());
427 }
428
429 TEST_F(TestMockImageSync, CancelAfterCopyImage) {
430 MockThreads mock_threads(m_threads);
431 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
432 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
433 MockSyncPointHandler mock_sync_point_handler;
434 MockInstanceWatcher mock_instance_watcher;
435 MockImageCopyRequest mock_image_copy_request;
436 MockSyncPointCreateRequest mock_sync_point_create_request;
437 MockSyncPointPruneRequest mock_sync_point_prune_request;
438
439 C_SaferCond ctx;
440 MockImageSync *request = create_request(mock_threads, mock_remote_image_ctx,
441 mock_local_image_ctx,
442 mock_sync_point_handler,
443 mock_instance_watcher, &ctx);
444
445 expect_get_snap_seqs(mock_sync_point_handler);
446 expect_get_sync_points(mock_sync_point_handler);
447
448 InSequence seq;
449 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
450 expect_create_sync_point(mock_local_image_ctx, mock_sync_point_create_request, 0);
451 expect_get_snap_id(mock_remote_image_ctx);
452 EXPECT_CALL(mock_image_copy_request, send())
453 .WillOnce((DoAll(InvokeWithoutArgs([request]() {
454 request->cancel();
455 }),
456 Invoke([this, &mock_image_copy_request]() {
457 m_threads->work_queue->queue(mock_image_copy_request.on_finish, 0);
458 }))));
459 expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
460 false);
461 EXPECT_CALL(mock_image_copy_request, cancel());
462 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
463
464 request->send();
465 ASSERT_EQ(-ECANCELED, ctx.wait());
466 }
467
468 } // namespace mirror
469 } // namespace rbd