]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/rbd_mirror/test_mock_ImageSync.cc
import 14.2.4 nautilus point release
[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 "librbd/journal/Types.h"
8#include "librbd/journal/TypeTraits.h"
9#include "test/journal/mock/MockJournaler.h"
10#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
11#include "test/librbd/mock/MockImageCtx.h"
7c673cae
FG
12#include "tools/rbd_mirror/ImageSync.h"
13#include "tools/rbd_mirror/Threads.h"
7c673cae
FG
14#include "tools/rbd_mirror/image_sync/SyncPointCreateRequest.h"
15#include "tools/rbd_mirror/image_sync/SyncPointPruneRequest.h"
16
17namespace librbd {
18
19namespace {
20
21struct MockTestImageCtx : public librbd::MockImageCtx {
11fdf7f2 22 explicit MockTestImageCtx(librbd::ImageCtx &image_ctx)
7c673cae
FG
23 : librbd::MockImageCtx(image_ctx) {
24 }
25};
26
27} // anonymous namespace
28
29namespace journal {
30
31template <>
32struct TypeTraits<librbd::MockTestImageCtx> {
33 typedef ::journal::MockJournaler Journaler;
34};
35
36} // namespace journal
7c673cae
FG
37
38template <>
11fdf7f2 39class DeepCopyRequest<librbd::MockTestImageCtx> {
7c673cae 40public:
11fdf7f2 41 static DeepCopyRequest* s_instance;
7c673cae
FG
42 Context *on_finish;
43
11fdf7f2
TL
44 static DeepCopyRequest* create(
45 librbd::MockTestImageCtx *src_image_ctx,
46 librbd::MockTestImageCtx *dst_image_ctx,
47 librados::snap_t snap_id_start, librados::snap_t snap_id_end,
48 bool flatten, const librbd::deep_copy::ObjectNumber &object_number,
49 ContextWQ *work_queue, SnapSeqs *snap_seqs, ProgressContext *prog_ctx,
50 Context *on_finish) {
51 ceph_assert(s_instance != nullptr);
7c673cae
FG
52 s_instance->on_finish = on_finish;
53 return s_instance;
54 }
55
11fdf7f2 56 DeepCopyRequest() {
7c673cae
FG
57 s_instance = this;
58 }
59
60 void put() {
61 }
62
63 void get() {
64 }
65
66 MOCK_METHOD0(cancel, void());
67 MOCK_METHOD0(send, void());
68};
69
11fdf7f2 70DeepCopyRequest<librbd::MockTestImageCtx>* DeepCopyRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
b32b8144 71
11fdf7f2 72} // namespace librbd
7c673cae 73
11fdf7f2
TL
74// template definitions
75template class rbd::mirror::ImageSync<librbd::MockTestImageCtx>;
76#include "tools/rbd_mirror/ImageSync.cc"
7c673cae 77
11fdf7f2
TL
78namespace rbd {
79namespace mirror {
7c673cae 80
11fdf7f2
TL
81template<>
82struct InstanceWatcher<librbd::MockTestImageCtx> {
83 MOCK_METHOD2(notify_sync_request, void(const std::string, Context *));
84 MOCK_METHOD1(cancel_sync_request, bool(const std::string &));
85 MOCK_METHOD1(notify_sync_complete, void(const std::string &));
7c673cae
FG
86};
87
11fdf7f2
TL
88namespace image_sync {
89
7c673cae
FG
90template <>
91class SyncPointCreateRequest<librbd::MockTestImageCtx> {
92public:
93 static SyncPointCreateRequest *s_instance;
94 Context *on_finish;
95
96 static SyncPointCreateRequest* create(librbd::MockTestImageCtx *remote_image_ctx,
97 const std::string &mirror_uuid,
98 journal::MockJournaler *journaler,
99 librbd::journal::MirrorPeerClientMeta *client_meta,
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,
121 journal::MockJournaler *journaler,
122 librbd::journal::MirrorPeerClientMeta *client_meta,
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::_;
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:
151 typedef ImageSync<librbd::MockTestImageCtx> MockImageSync;
31f18b77 152 typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
7c673cae
FG
153 typedef image_sync::SyncPointCreateRequest<librbd::MockTestImageCtx> MockSyncPointCreateRequest;
154 typedef image_sync::SyncPointPruneRequest<librbd::MockTestImageCtx> MockSyncPointPruneRequest;
11fdf7f2 155 typedef librbd::DeepCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest;
7c673cae
FG
156
157 void SetUp() override {
158 TestMockFixture::SetUp();
159
160 librbd::RBD rbd;
161 ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size));
162 ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx));
163
164 ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size));
165 ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx));
166 }
167
11fdf7f2
TL
168 void expect_get_snap_id(librbd::MockTestImageCtx &mock_image_ctx) {
169 EXPECT_CALL(mock_image_ctx, get_snap_id(_, _))
170 .WillOnce(Return(123));
31f18b77
FG
171 }
172
173 void expect_notify_sync_request(MockInstanceWatcher &mock_instance_watcher,
174 const std::string &sync_id, int r) {
175 EXPECT_CALL(mock_instance_watcher, notify_sync_request(sync_id, _))
176 .WillOnce(Invoke([this, r](const std::string &, Context *on_sync_start) {
177 m_threads->work_queue->queue(on_sync_start, r);
178 }));
179 }
180
181 void expect_cancel_sync_request(MockInstanceWatcher &mock_instance_watcher,
182 const std::string &sync_id, bool canceled) {
183 EXPECT_CALL(mock_instance_watcher, cancel_sync_request(sync_id))
184 .WillOnce(Return(canceled));
185 }
186
187 void expect_notify_sync_complete(MockInstanceWatcher &mock_instance_watcher,
188 const std::string &sync_id) {
189 EXPECT_CALL(mock_instance_watcher, notify_sync_complete(sync_id));
190 }
191
7c673cae
FG
192 void expect_create_sync_point(librbd::MockTestImageCtx &mock_local_image_ctx,
193 MockSyncPointCreateRequest &mock_sync_point_create_request,
194 int r) {
195 EXPECT_CALL(mock_sync_point_create_request, send())
196 .WillOnce(Invoke([this, &mock_local_image_ctx, &mock_sync_point_create_request, r]() {
197 if (r == 0) {
198 mock_local_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(),
199 "snap1"}] = 123;
200 m_client_meta.sync_points.emplace_back(cls::rbd::UserSnapshotNamespace(),
201 "snap1",
202 boost::none);
203 }
204 m_threads->work_queue->queue(mock_sync_point_create_request.on_finish, r);
205 }));
206 }
207
7c673cae
FG
208 void expect_copy_image(MockImageCopyRequest &mock_image_copy_request, int r) {
209 EXPECT_CALL(mock_image_copy_request, send())
210 .WillOnce(Invoke([this, &mock_image_copy_request, r]() {
211 m_threads->work_queue->queue(mock_image_copy_request.on_finish, r);
212 }));
213 }
214
11fdf7f2
TL
215 void expect_flush_sync_point(journal::MockJournaler &mock_journaler, int r) {
216 EXPECT_CALL(mock_journaler, update_client(_, _))
217 .WillOnce(WithArg<1>(CompleteContext(r)));
7c673cae
FG
218 }
219
220 void expect_prune_sync_point(MockSyncPointPruneRequest &mock_sync_point_prune_request,
221 bool sync_complete, int r) {
222 EXPECT_CALL(mock_sync_point_prune_request, send())
223 .WillOnce(Invoke([this, &mock_sync_point_prune_request, sync_complete, r]() {
224 ASSERT_EQ(sync_complete, mock_sync_point_prune_request.sync_complete);
225 if (r == 0 && !m_client_meta.sync_points.empty()) {
226 if (sync_complete) {
227 m_client_meta.sync_points.pop_front();
228 } else {
229 while (m_client_meta.sync_points.size() > 1) {
230 m_client_meta.sync_points.pop_back();
231 }
232 }
233 }
234 m_threads->work_queue->queue(mock_sync_point_prune_request.on_finish, r);
235 }));
236 }
237
238 MockImageSync *create_request(librbd::MockTestImageCtx &mock_remote_image_ctx,
239 librbd::MockTestImageCtx &mock_local_image_ctx,
240 journal::MockJournaler &mock_journaler,
31f18b77 241 MockInstanceWatcher &mock_instance_watcher,
7c673cae
FG
242 Context *ctx) {
243 return new MockImageSync(&mock_local_image_ctx, &mock_remote_image_ctx,
244 m_threads->timer, &m_threads->timer_lock,
245 "mirror-uuid", &mock_journaler, &m_client_meta,
31f18b77
FG
246 m_threads->work_queue, &mock_instance_watcher,
247 ctx);
7c673cae
FG
248 }
249
250 librbd::ImageCtx *m_remote_image_ctx;
251 librbd::ImageCtx *m_local_image_ctx;
252 librbd::journal::MirrorPeerClientMeta m_client_meta;
253};
254
255TEST_F(TestMockImageSync, SimpleSync) {
256 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
257 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
258 journal::MockJournaler mock_journaler;
31f18b77 259 MockInstanceWatcher mock_instance_watcher;
7c673cae 260 MockImageCopyRequest mock_image_copy_request;
7c673cae
FG
261 MockSyncPointCreateRequest mock_sync_point_create_request;
262 MockSyncPointPruneRequest mock_sync_point_prune_request;
7c673cae
FG
263
264 InSequence seq;
31f18b77 265 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae 266 expect_create_sync_point(mock_local_image_ctx, mock_sync_point_create_request, 0);
11fdf7f2 267 expect_get_snap_id(mock_remote_image_ctx);
7c673cae 268 expect_copy_image(mock_image_copy_request, 0);
11fdf7f2 269 expect_flush_sync_point(mock_journaler, 0);
7c673cae 270 expect_prune_sync_point(mock_sync_point_prune_request, true, 0);
31f18b77 271 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
272
273 C_SaferCond ctx;
274 MockImageSync *request = create_request(mock_remote_image_ctx,
31f18b77
FG
275 mock_local_image_ctx, mock_journaler,
276 mock_instance_watcher, &ctx);
7c673cae
FG
277 request->send();
278 ASSERT_EQ(0, ctx.wait());
279}
280
281TEST_F(TestMockImageSync, RestartSync) {
282 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
283 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
284 journal::MockJournaler mock_journaler;
31f18b77 285 MockInstanceWatcher mock_instance_watcher;
7c673cae 286 MockImageCopyRequest mock_image_copy_request;
7c673cae
FG
287 MockSyncPointCreateRequest mock_sync_point_create_request;
288 MockSyncPointPruneRequest mock_sync_point_prune_request;
289
290 m_client_meta.sync_points = {{cls::rbd::UserSnapshotNamespace(), "snap1", boost::none},
291 {cls::rbd::UserSnapshotNamespace(), "snap2", "snap1", boost::none}};
292 mock_local_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(), "snap1"}] = 123;
293 mock_local_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(), "snap2"}] = 234;
294
7c673cae
FG
295 expect_test_features(mock_local_image_ctx);
296
297 InSequence seq;
31f18b77 298 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae 299 expect_prune_sync_point(mock_sync_point_prune_request, false, 0);
11fdf7f2 300 expect_get_snap_id(mock_remote_image_ctx);
7c673cae 301 expect_copy_image(mock_image_copy_request, 0);
11fdf7f2 302 expect_flush_sync_point(mock_journaler, 0);
7c673cae 303 expect_prune_sync_point(mock_sync_point_prune_request, true, 0);
31f18b77 304 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
305
306 C_SaferCond ctx;
307 MockImageSync *request = create_request(mock_remote_image_ctx,
31f18b77
FG
308 mock_local_image_ctx, mock_journaler,
309 mock_instance_watcher, &ctx);
7c673cae
FG
310 request->send();
311 ASSERT_EQ(0, ctx.wait());
312}
313
31f18b77
FG
314TEST_F(TestMockImageSync, CancelNotifySyncRequest) {
315 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
316 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
317 journal::MockJournaler mock_journaler;
318 MockInstanceWatcher mock_instance_watcher;
319
320 InSequence seq;
321 Context *on_sync_start = nullptr;
322 C_SaferCond notify_sync_ctx;
323 EXPECT_CALL(mock_instance_watcher,
324 notify_sync_request(mock_local_image_ctx.id, _))
11fdf7f2 325 .WillOnce(Invoke([&on_sync_start, &notify_sync_ctx](
31f18b77
FG
326 const std::string &, Context *ctx) {
327 on_sync_start = ctx;
328 notify_sync_ctx.complete(0);
329 }));
330 EXPECT_CALL(mock_instance_watcher,
331 cancel_sync_request(mock_local_image_ctx.id))
11fdf7f2 332 .WillOnce(Invoke([&on_sync_start](const std::string &) {
31f18b77
FG
333 EXPECT_NE(nullptr, on_sync_start);
334 on_sync_start->complete(-ECANCELED);
335 return true;
336 }));
337
338 C_SaferCond ctx;
339 MockImageSync *request = create_request(mock_remote_image_ctx,
340 mock_local_image_ctx, mock_journaler,
341 mock_instance_watcher, &ctx);
342 request->get();
343 request->send();
344
345 // cancel the notify sync request once it starts
346 ASSERT_EQ(0, notify_sync_ctx.wait());
347 request->cancel();
348 request->put();
349
350 ASSERT_EQ(-ECANCELED, ctx.wait());
351}
352
7c673cae
FG
353TEST_F(TestMockImageSync, CancelImageCopy) {
354 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
355 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
356 journal::MockJournaler mock_journaler;
31f18b77 357 MockInstanceWatcher mock_instance_watcher;
7c673cae 358 MockImageCopyRequest mock_image_copy_request;
7c673cae
FG
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
364 InSequence seq;
31f18b77 365 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae 366 expect_prune_sync_point(mock_sync_point_prune_request, false, 0);
11fdf7f2 367 expect_get_snap_id(mock_remote_image_ctx);
7c673cae
FG
368
369 C_SaferCond image_copy_ctx;
370 EXPECT_CALL(mock_image_copy_request, send())
371 .WillOnce(Invoke([&image_copy_ctx]() {
372 image_copy_ctx.complete(0);
373 }));
31f18b77
FG
374 expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
375 false);
7c673cae 376 EXPECT_CALL(mock_image_copy_request, cancel());
31f18b77 377 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
378
379 C_SaferCond ctx;
380 MockImageSync *request = create_request(mock_remote_image_ctx,
31f18b77
FG
381 mock_local_image_ctx, mock_journaler,
382 mock_instance_watcher, &ctx);
7c673cae
FG
383 request->get();
384 request->send();
385
386 // cancel the image copy once it starts
387 ASSERT_EQ(0, image_copy_ctx.wait());
388 request->cancel();
389 request->put();
390 m_threads->work_queue->queue(mock_image_copy_request.on_finish, 0);
391
392 ASSERT_EQ(-ECANCELED, ctx.wait());
393}
394
7c673cae
FG
395TEST_F(TestMockImageSync, CancelAfterCopyImage) {
396 librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
397 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
398 journal::MockJournaler mock_journaler;
31f18b77 399 MockInstanceWatcher mock_instance_watcher;
7c673cae 400 MockImageCopyRequest mock_image_copy_request;
7c673cae
FG
401 MockSyncPointCreateRequest mock_sync_point_create_request;
402 MockSyncPointPruneRequest mock_sync_point_prune_request;
403
7c673cae
FG
404 C_SaferCond ctx;
405 MockImageSync *request = create_request(mock_remote_image_ctx,
31f18b77
FG
406 mock_local_image_ctx, mock_journaler,
407 mock_instance_watcher, &ctx);
7c673cae 408 InSequence seq;
31f18b77 409 expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0);
7c673cae 410 expect_create_sync_point(mock_local_image_ctx, mock_sync_point_create_request, 0);
11fdf7f2 411 expect_get_snap_id(mock_remote_image_ctx);
7c673cae
FG
412 EXPECT_CALL(mock_image_copy_request, send())
413 .WillOnce((DoAll(InvokeWithoutArgs([request]() {
414 request->cancel();
415 }),
416 Invoke([this, &mock_image_copy_request]() {
417 m_threads->work_queue->queue(mock_image_copy_request.on_finish, 0);
418 }))));
31f18b77
FG
419 expect_cancel_sync_request(mock_instance_watcher, mock_local_image_ctx.id,
420 false);
7c673cae 421 EXPECT_CALL(mock_image_copy_request, cancel());
31f18b77 422 expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id);
7c673cae
FG
423
424 request->send();
425 ASSERT_EQ(-ECANCELED, ctx.wait());
426}
427
428} // namespace mirror
429} // namespace rbd