]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/rbd_mirror/test_mock_ImageSync.cc
import 15.2.0 Octopus source
[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,
11fdf7f2
TL
39 ContextWQ *work_queue, SnapSeqs *snap_seqs, ProgressContext *prog_ctx,
40 Context *on_finish) {
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
TL
64// template definitions
65template class rbd::mirror::ImageSync<librbd::MockTestImageCtx>;
66#include "tools/rbd_mirror/ImageSync.cc"
7c673cae 67
11fdf7f2
TL
68namespace rbd {
69namespace mirror {
7c673cae 70
9f95a23c
TL
71template <>
72struct 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
11fdf7f2
TL
83template<>
84struct 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 &));
7c673cae
FG
88};
89
11fdf7f2
TL
90namespace image_sync {
91
7c673cae
FG
92template <>
93class SyncPointCreateRequest<librbd::MockTestImageCtx> {
94public:
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,
9f95a23c 100 image_sync::SyncPointHandler* sync_point_handler,
7c673cae 101 Context *on_finish) {
11fdf7f2 102 ceph_assert(s_instance != nullptr);
7c673cae
FG
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
113template <>
114class SyncPointPruneRequest<librbd::MockTestImageCtx> {
115public:
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,
9f95a23c 122 image_sync::SyncPointHandler* sync_point_handler,
7c673cae 123 Context *on_finish) {
11fdf7f2 124 ceph_assert(s_instance != nullptr);
7c673cae
FG
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
7c673cae
FG
136SyncPointCreateRequest<librbd::MockTestImageCtx>* SyncPointCreateRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
137SyncPointPruneRequest<librbd::MockTestImageCtx>* SyncPointPruneRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
138
139} // namespace image_sync
140
141using ::testing::_;
9f95a23c 142using ::testing::DoAll;
7c673cae
FG
143using ::testing::InSequence;
144using ::testing::Invoke;
145using ::testing::Return;
11fdf7f2 146using ::testing::StrEq;
7c673cae
FG
147using ::testing::WithArg;
148using ::testing::InvokeWithoutArgs;
149
150class TestMockImageSync : public TestMockFixture {
151public:
9f95a23c 152 typedef Threads<librbd::MockTestImageCtx> MockThreads;
7c673cae 153 typedef ImageSync<librbd::MockTestImageCtx> MockImageSync;
31f18b77 154 typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
7c673cae
FG
155 typedef image_sync::SyncPointCreateRequest<librbd::MockTestImageCtx> MockSyncPointCreateRequest;
156 typedef image_sync::SyncPointPruneRequest<librbd::MockTestImageCtx> MockSyncPointPruneRequest;
9f95a23c 157 typedef image_sync::MockSyncPointHandler MockSyncPointHandler;
11fdf7f2 158 typedef librbd::DeepCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest;
7c673cae
FG
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
11fdf7f2
TL
171 void expect_get_snap_id(librbd::MockTestImageCtx &mock_image_ctx) {
172 EXPECT_CALL(mock_image_ctx, get_snap_id(_, _))
173 .WillOnce(Return(123));
31f18b77
FG
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
7c673cae
FG
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;
9f95a23c
TL
203 m_sync_points.emplace_back(cls::rbd::UserSnapshotNamespace(),
204 "snap1", "", boost::none);
7c673cae
FG
205 }
206 m_threads->work_queue->queue(mock_sync_point_create_request.on_finish, r);
207 }));
208 }
209
7c673cae
FG
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
9f95a23c
TL
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)));
7c673cae
FG
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);
9f95a23c 228 if (r == 0 && !m_sync_points.empty()) {
7c673cae 229 if (sync_complete) {
9f95a23c 230 m_sync_points.pop_front();
7c673cae 231 } else {
9f95a23c
TL
232 while (m_sync_points.size() > 1) {
233 m_sync_points.pop_back();
7c673cae
FG
234 }
235 }
236 }
237 m_threads->work_queue->queue(mock_sync_point_prune_request.on_finish, r);
238 }));
239 }
240
9f95a23c
TL
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,
7c673cae 255 librbd::MockTestImageCtx &mock_local_image_ctx,
9f95a23c 256 MockSyncPointHandler& mock_sync_point_handler,
31f18b77 257 MockInstanceWatcher &mock_instance_watcher,
7c673cae 258 Context *ctx) {
9f95a23c
TL
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);
7c673cae
FG
263 }
264
265 librbd::ImageCtx *m_remote_image_ctx;
266 librbd::ImageCtx *m_local_image_ctx;
9f95a23c
TL
267
268 image_sync::SyncPoints m_sync_points;
7c673cae
FG
269};
270
271TEST_F(TestMockImageSync, SimpleSync) {
9f95a23c 272 MockThreads mock_threads(m_threads);
7c673cae
FG
273 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
274 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
9f95a23c 275 MockSyncPointHandler mock_sync_point_handler;
31f18b77 276 MockInstanceWatcher mock_instance_watcher;
7c673cae 277 MockImageCopyRequest mock_image_copy_request;
7c673cae
FG
278 MockSyncPointCreateRequest mock_sync_point_create_request;
279 MockSyncPointPruneRequest mock_sync_point_prune_request;
7c673cae 280
9f95a23c
TL
281 expect_get_snap_seqs(mock_sync_point_handler);
282 expect_get_sync_points(mock_sync_point_handler);
283
7c673cae 284 InSequence seq;
31f18b77 285 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae 286 expect_create_sync_point(mock_local_image_ctx, mock_sync_point_create_request, 0);
11fdf7f2 287 expect_get_snap_id(mock_remote_image_ctx);
7c673cae 288 expect_copy_image(mock_image_copy_request, 0);
9f95a23c 289 expect_flush_sync_point(mock_sync_point_handler, 0);
7c673cae 290 expect_prune_sync_point(mock_sync_point_prune_request, true, 0);
31f18b77 291 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
292
293 C_SaferCond ctx;
9f95a23c
TL
294 MockImageSync *request = create_request(mock_threads, mock_remote_image_ctx,
295 mock_local_image_ctx,
296 mock_sync_point_handler,
31f18b77 297 mock_instance_watcher, &ctx);
7c673cae
FG
298 request->send();
299 ASSERT_EQ(0, ctx.wait());
300}
301
302TEST_F(TestMockImageSync, RestartSync) {
9f95a23c 303 MockThreads mock_threads(m_threads);
7c673cae
FG
304 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
305 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
9f95a23c 306 MockSyncPointHandler mock_sync_point_handler;
31f18b77 307 MockInstanceWatcher mock_instance_watcher;
7c673cae 308 MockImageCopyRequest mock_image_copy_request;
7c673cae
FG
309 MockSyncPointCreateRequest mock_sync_point_create_request;
310 MockSyncPointPruneRequest mock_sync_point_prune_request;
311
9f95a23c
TL
312 m_sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", "", boost::none},
313 {cls::rbd::UserSnapshotNamespace(), "snap2", "snap1", boost::none}};
7c673cae
FG
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
7c673cae 317 expect_test_features(mock_local_image_ctx);
9f95a23c
TL
318 expect_get_snap_seqs(mock_sync_point_handler);
319 expect_get_sync_points(mock_sync_point_handler);
7c673cae
FG
320
321 InSequence seq;
31f18b77 322 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae 323 expect_prune_sync_point(mock_sync_point_prune_request, false, 0);
11fdf7f2 324 expect_get_snap_id(mock_remote_image_ctx);
7c673cae 325 expect_copy_image(mock_image_copy_request, 0);
9f95a23c 326 expect_flush_sync_point(mock_sync_point_handler, 0);
7c673cae 327 expect_prune_sync_point(mock_sync_point_prune_request, true, 0);
31f18b77 328 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
329
330 C_SaferCond ctx;
9f95a23c
TL
331 MockImageSync *request = create_request(mock_threads, mock_remote_image_ctx,
332 mock_local_image_ctx,
333 mock_sync_point_handler,
31f18b77 334 mock_instance_watcher, &ctx);
7c673cae
FG
335 request->send();
336 ASSERT_EQ(0, ctx.wait());
337}
338
31f18b77 339TEST_F(TestMockImageSync, CancelNotifySyncRequest) {
9f95a23c 340 MockThreads mock_threads(m_threads);
31f18b77
FG
341 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
342 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
9f95a23c 343 MockSyncPointHandler mock_sync_point_handler;
31f18b77
FG
344 MockInstanceWatcher mock_instance_watcher;
345
9f95a23c
TL
346 expect_get_snap_seqs(mock_sync_point_handler);
347 expect_get_sync_points(mock_sync_point_handler);
348
31f18b77
FG
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, _))
11fdf7f2 354 .WillOnce(Invoke([&on_sync_start, &notify_sync_ctx](
31f18b77
FG
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))
11fdf7f2 361 .WillOnce(Invoke([&on_sync_start](const std::string &) {
31f18b77
FG
362 EXPECT_NE(nullptr, on_sync_start);
363 on_sync_start->complete(-ECANCELED);
364 return true;
365 }));
366
367 C_SaferCond ctx;
9f95a23c
TL
368 MockImageSync *request = create_request(mock_threads, mock_remote_image_ctx,
369 mock_local_image_ctx,
370 mock_sync_point_handler,
31f18b77
FG
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
7c673cae 383TEST_F(TestMockImageSync, CancelImageCopy) {
9f95a23c 384 MockThreads mock_threads(m_threads);
7c673cae
FG
385 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
386 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
9f95a23c 387 MockSyncPointHandler mock_sync_point_handler;
31f18b77 388 MockInstanceWatcher mock_instance_watcher;
7c673cae 389 MockImageCopyRequest mock_image_copy_request;
7c673cae
FG
390 MockSyncPointCreateRequest mock_sync_point_create_request;
391 MockSyncPointPruneRequest mock_sync_point_prune_request;
392
9f95a23c
TL
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);
7c673cae
FG
396
397 InSequence seq;
31f18b77 398 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae 399 expect_prune_sync_point(mock_sync_point_prune_request, false, 0);
11fdf7f2 400 expect_get_snap_id(mock_remote_image_ctx);
7c673cae
FG
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 }));
31f18b77
FG
407 expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
408 false);
7c673cae 409 EXPECT_CALL(mock_image_copy_request, cancel());
31f18b77 410 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
411
412 C_SaferCond ctx;
9f95a23c
TL
413 MockImageSync *request = create_request(mock_threads, mock_remote_image_ctx,
414 mock_local_image_ctx,
415 mock_sync_point_handler,
31f18b77 416 mock_instance_watcher, &ctx);
7c673cae
FG
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
7c673cae 429TEST_F(TestMockImageSync, CancelAfterCopyImage) {
9f95a23c 430 MockThreads mock_threads(m_threads);
7c673cae
FG
431 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
432 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
9f95a23c 433 MockSyncPointHandler mock_sync_point_handler;
31f18b77 434 MockInstanceWatcher mock_instance_watcher;
7c673cae 435 MockImageCopyRequest mock_image_copy_request;
7c673cae
FG
436 MockSyncPointCreateRequest mock_sync_point_create_request;
437 MockSyncPointPruneRequest mock_sync_point_prune_request;
438
7c673cae 439 C_SaferCond ctx;
9f95a23c
TL
440 MockImageSync *request = create_request(mock_threads, mock_remote_image_ctx,
441 mock_local_image_ctx,
442 mock_sync_point_handler,
31f18b77 443 mock_instance_watcher, &ctx);
9f95a23c
TL
444
445 expect_get_snap_seqs(mock_sync_point_handler);
446 expect_get_sync_points(mock_sync_point_handler);
447
7c673cae 448 InSequence seq;
31f18b77 449 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae 450 expect_create_sync_point(mock_local_image_ctx, mock_sync_point_create_request, 0);
11fdf7f2 451 expect_get_snap_id(mock_remote_image_ctx);
7c673cae
FG
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 }))));
31f18b77
FG
459 expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
460 false);
7c673cae 461 EXPECT_CALL(mock_image_copy_request, cancel());
31f18b77 462 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
463
464 request->send();
465 ASSERT_EQ(-ECANCELED, ctx.wait());
466}
467
468} // namespace mirror
469} // namespace rbd