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