1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
19 struct MockTestImageCtx
: public librbd::MockImageCtx
{
20 explicit MockTestImageCtx(librbd::ImageCtx
&image_ctx
)
21 : librbd::MockImageCtx(image_ctx
) {
25 } // anonymous namespace
28 class DeepCopyRequest
<librbd::MockTestImageCtx
> {
30 static DeepCopyRequest
* s_instance
;
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
,
41 ceph_assert(s_instance
!= nullptr);
42 s_instance
->on_finish
= on_finish
;
56 MOCK_METHOD0(cancel
, void());
57 MOCK_METHOD0(send
, void());
60 DeepCopyRequest
<librbd::MockTestImageCtx
>* DeepCopyRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
64 // template definitions
65 template class rbd::mirror::ImageSync
<librbd::MockTestImageCtx
>;
66 #include "tools/rbd_mirror/ImageSync.cc"
72 struct Threads
<librbd::MockTestImageCtx
> {
73 ceph::mutex
&timer_lock
;
75 ContextWQ
*work_queue
;
77 Threads(Threads
<librbd::ImageCtx
> *threads
)
78 : timer_lock(threads
->timer_lock
), timer(threads
->timer
),
79 work_queue(threads
->work_queue
) {
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
&));
90 namespace image_sync
{
93 class SyncPointCreateRequest
<librbd::MockTestImageCtx
> {
95 static SyncPointCreateRequest
*s_instance
;
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
;
107 SyncPointCreateRequest() {
110 MOCK_METHOD0(send
, void());
114 class SyncPointPruneRequest
<librbd::MockTestImageCtx
> {
116 static SyncPointPruneRequest
*s_instance
;
120 static SyncPointPruneRequest
* create(librbd::MockTestImageCtx
*remote_image_ctx
,
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
;
130 SyncPointPruneRequest() {
133 MOCK_METHOD0(send
, void());
136 SyncPointCreateRequest
<librbd::MockTestImageCtx
>* SyncPointCreateRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
137 SyncPointPruneRequest
<librbd::MockTestImageCtx
>* SyncPointPruneRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
139 } // namespace image_sync
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
;
150 class TestMockImageSync
: public TestMockFixture
{
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
;
160 void SetUp() override
{
161 TestMockFixture::SetUp();
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
));
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
));
171 void expect_get_snap_id(librbd::MockTestImageCtx
&mock_image_ctx
) {
172 EXPECT_CALL(mock_image_ctx
, get_snap_id(_
, _
))
173 .WillOnce(Return(123));
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
);
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
));
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
));
195 void expect_create_sync_point(librbd::MockTestImageCtx
&mock_local_image_ctx
,
196 MockSyncPointCreateRequest
&mock_sync_point_create_request
,
198 EXPECT_CALL(mock_sync_point_create_request
, send())
199 .WillOnce(Invoke([this, &mock_local_image_ctx
, &mock_sync_point_create_request
, r
]() {
201 mock_local_image_ctx
.snap_ids
[{cls::rbd::UserSnapshotNamespace(),
203 m_sync_points
.emplace_back(cls::rbd::UserSnapshotNamespace(),
204 "snap1", "", boost::none
);
206 m_threads
->work_queue
->queue(mock_sync_point_create_request
.on_finish
, r
);
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
);
217 void expect_flush_sync_point(MockSyncPointHandler
& mock_sync_point_handler
,
219 EXPECT_CALL(mock_sync_point_handler
, update_sync_points(_
, _
, false, _
))
220 .WillOnce(WithArg
<3>(CompleteContext(r
)));
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()) {
230 m_sync_points
.pop_front();
232 while (m_sync_points
.size() > 1) {
233 m_sync_points
.pop_back();
237 m_threads
->work_queue
->queue(mock_sync_point_prune_request
.on_finish
, r
);
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
{}));
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
;
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
,
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
);
265 librbd::ImageCtx
*m_remote_image_ctx
;
266 librbd::ImageCtx
*m_local_image_ctx
;
268 image_sync::SyncPoints m_sync_points
;
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
;
281 expect_get_snap_seqs(mock_sync_point_handler
);
282 expect_get_sync_points(mock_sync_point_handler
);
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
);
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
);
299 ASSERT_EQ(0, ctx
.wait());
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
;
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;
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
);
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
);
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
);
336 ASSERT_EQ(0, ctx
.wait());
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
;
346 expect_get_snap_seqs(mock_sync_point_handler
);
347 expect_get_sync_points(mock_sync_point_handler
);
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
, ¬ify_sync_ctx
](
355 const std::string
&, Context
*ctx
) {
357 notify_sync_ctx
.complete(0);
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
);
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
);
375 // cancel the notify sync request once it starts
376 ASSERT_EQ(0, notify_sync_ctx
.wait());
380 ASSERT_EQ(-ECANCELED
, ctx
.wait());
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
;
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
);
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
);
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);
407 expect_cancel_sync_request(mock_instance_watcher
, mock_local_image_ctx
.id
,
409 EXPECT_CALL(mock_image_copy_request
, cancel());
410 expect_notify_sync_complete(mock_instance_watcher
, mock_local_image_ctx
.id
);
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
);
420 // cancel the image copy once it starts
421 ASSERT_EQ(0, image_copy_ctx
.wait());
424 m_threads
->work_queue
->queue(mock_image_copy_request
.on_finish
, 0);
426 ASSERT_EQ(-ECANCELED
, ctx
.wait());
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
;
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
);
445 expect_get_snap_seqs(mock_sync_point_handler
);
446 expect_get_sync_points(mock_sync_point_handler
);
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
]() {
456 Invoke([this, &mock_image_copy_request
]() {
457 m_threads
->work_queue
->queue(mock_image_copy_request
.on_finish
, 0);
459 expect_cancel_sync_request(mock_instance_watcher
, mock_local_image_ctx
.id
,
461 EXPECT_CALL(mock_image_copy_request
, cancel());
462 expect_notify_sync_complete(mock_instance_watcher
, mock_local_image_ctx
.id
);
465 ASSERT_EQ(-ECANCELED
, ctx
.wait());
468 } // namespace mirror