]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
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 "librbd/deep_copy/ImageCopyRequest.h" | |
6 | #include "librbd/deep_copy/SnapshotCopyRequest.h" | |
7 | #include "librbd/mirror/snapshot/CreateNonPrimaryRequest.h" | |
8 | #include "librbd/mirror/snapshot/GetImageStateRequest.h" | |
9 | #include "librbd/mirror/snapshot/ImageMeta.h" | |
10 | #include "librbd/mirror/snapshot/UnlinkPeerRequest.h" | |
11 | #include "tools/rbd_mirror/InstanceWatcher.h" | |
12 | #include "tools/rbd_mirror/Threads.h" | |
13 | #include "tools/rbd_mirror/image_replayer/CloseImageRequest.h" | |
14 | #include "tools/rbd_mirror/image_replayer/ReplayerListener.h" | |
15 | #include "tools/rbd_mirror/image_replayer/Utils.h" | |
16 | #include "tools/rbd_mirror/image_replayer/snapshot/ApplyImageStateRequest.h" | |
17 | #include "tools/rbd_mirror/image_replayer/snapshot/Replayer.h" | |
18 | #include "tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h" | |
19 | #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" | |
20 | #include "test/librbd/mock/MockImageCtx.h" | |
1911f103 | 21 | #include "test/librbd/mock/MockOperations.h" |
9f95a23c TL |
22 | #include "test/rbd_mirror/mock/MockContextWQ.h" |
23 | #include "test/rbd_mirror/mock/MockSafeTimer.h" | |
24 | ||
25 | namespace librbd { | |
26 | namespace { | |
27 | ||
28 | struct MockTestImageCtx : public librbd::MockImageCtx { | |
29 | explicit MockTestImageCtx(librbd::ImageCtx &image_ctx) | |
30 | : librbd::MockImageCtx(image_ctx) { | |
31 | } | |
32 | }; | |
33 | ||
34 | } // anonymous namespace | |
35 | ||
36 | namespace deep_copy { | |
37 | ||
38 | template <> | |
39 | struct ImageCopyRequest<MockTestImageCtx> { | |
40 | uint64_t src_snap_id_start; | |
41 | uint64_t src_snap_id_end; | |
42 | uint64_t dst_snap_id_start; | |
43 | librbd::deep_copy::ObjectNumber object_number; | |
44 | librbd::SnapSeqs snap_seqs; | |
45 | ||
46 | static ImageCopyRequest* s_instance; | |
47 | static ImageCopyRequest* create(MockTestImageCtx *src_image_ctx, | |
48 | MockTestImageCtx *dst_image_ctx, | |
49 | librados::snap_t src_snap_id_start, | |
50 | librados::snap_t src_snap_id_end, | |
51 | librados::snap_t dst_snap_id_start, | |
52 | bool flatten, | |
53 | const ObjectNumber &object_number, | |
54 | const SnapSeqs &snap_seqs, | |
1911f103 | 55 | Handler *handler, |
9f95a23c TL |
56 | Context *on_finish) { |
57 | ceph_assert(s_instance != nullptr); | |
58 | s_instance->src_snap_id_start = src_snap_id_start; | |
59 | s_instance->src_snap_id_end = src_snap_id_end; | |
60 | s_instance->dst_snap_id_start = dst_snap_id_start; | |
61 | s_instance->object_number = object_number; | |
62 | s_instance->snap_seqs = snap_seqs; | |
63 | s_instance->on_finish = on_finish; | |
64 | return s_instance; | |
65 | } | |
66 | ||
67 | Context* on_finish = nullptr; | |
68 | ||
69 | ImageCopyRequest() { | |
70 | s_instance = this; | |
71 | } | |
72 | ||
73 | MOCK_METHOD0(send, void()); | |
74 | }; | |
75 | ||
76 | template <> | |
77 | struct SnapshotCopyRequest<MockTestImageCtx> { | |
78 | librados::snap_t src_snap_id_start; | |
79 | librados::snap_t src_snap_id_end; | |
80 | librados::snap_t dst_snap_id_start; | |
81 | SnapSeqs* snap_seqs = nullptr; | |
82 | ||
83 | static SnapshotCopyRequest* s_instance; | |
84 | static SnapshotCopyRequest* create(MockTestImageCtx *src_image_ctx, | |
85 | MockTestImageCtx *dst_image_ctx, | |
86 | librados::snap_t src_snap_id_start, | |
87 | librados::snap_t src_snap_id_end, | |
88 | librados::snap_t dst_snap_id_start, | |
89 | bool flatten, | |
90 | ::MockContextWQ *work_queue, | |
91 | SnapSeqs *snap_seqs, | |
92 | Context *on_finish) { | |
93 | ceph_assert(s_instance != nullptr); | |
94 | s_instance->src_snap_id_start = src_snap_id_start; | |
95 | s_instance->src_snap_id_end = src_snap_id_end; | |
96 | s_instance->dst_snap_id_start = dst_snap_id_start; | |
97 | s_instance->snap_seqs = snap_seqs; | |
98 | s_instance->on_finish = on_finish; | |
99 | return s_instance; | |
100 | } | |
101 | ||
102 | Context* on_finish = nullptr; | |
103 | ||
104 | SnapshotCopyRequest() { | |
105 | s_instance = this; | |
106 | } | |
107 | ||
108 | MOCK_METHOD0(send, void()); | |
109 | }; | |
110 | ||
111 | ImageCopyRequest<MockTestImageCtx>* ImageCopyRequest<MockTestImageCtx>::s_instance = nullptr; | |
112 | SnapshotCopyRequest<MockTestImageCtx>* SnapshotCopyRequest<MockTestImageCtx>::s_instance = nullptr; | |
113 | ||
114 | } // namespace deep_copy | |
115 | ||
116 | namespace mirror { | |
117 | namespace snapshot { | |
118 | ||
119 | template <> | |
120 | struct CreateNonPrimaryRequest<MockTestImageCtx> { | |
121 | bool demoted = false; | |
122 | std::string primary_mirror_uuid; | |
123 | uint64_t primary_snap_id; | |
124 | SnapSeqs snap_seqs; | |
125 | uint64_t* snap_id = nullptr; | |
126 | ||
127 | static CreateNonPrimaryRequest* s_instance; | |
128 | static CreateNonPrimaryRequest* create(MockTestImageCtx *image_ctx, | |
129 | bool demoted, | |
130 | const std::string &primary_mirror_uuid, | |
131 | uint64_t primary_snap_id, | |
132 | const SnapSeqs& snap_seqs, | |
133 | const ImageState &image_state, | |
134 | uint64_t *snap_id, | |
135 | Context *on_finish) { | |
136 | ceph_assert(s_instance != nullptr); | |
137 | s_instance->demoted = demoted; | |
138 | s_instance->primary_mirror_uuid = primary_mirror_uuid; | |
139 | s_instance->primary_snap_id = primary_snap_id; | |
140 | s_instance->snap_seqs = snap_seqs; | |
141 | s_instance->snap_id = snap_id; | |
142 | s_instance->on_finish = on_finish; | |
143 | return s_instance; | |
144 | } | |
145 | ||
146 | Context* on_finish = nullptr; | |
147 | ||
148 | CreateNonPrimaryRequest() { | |
149 | s_instance = this; | |
150 | } | |
151 | ||
152 | MOCK_METHOD0(send, void()); | |
153 | }; | |
154 | ||
155 | template <> | |
156 | struct GetImageStateRequest<MockTestImageCtx> { | |
157 | uint64_t snap_id = CEPH_NOSNAP; | |
158 | ||
159 | static GetImageStateRequest* s_instance; | |
160 | static GetImageStateRequest* create(MockTestImageCtx *image_ctx, | |
161 | uint64_t snap_id, | |
162 | ImageState *image_state, | |
163 | Context *on_finish) { | |
164 | ceph_assert(s_instance != nullptr); | |
165 | s_instance->snap_id = snap_id; | |
166 | s_instance->on_finish = on_finish; | |
167 | return s_instance; | |
168 | } | |
169 | ||
170 | Context* on_finish = nullptr; | |
171 | ||
172 | GetImageStateRequest() { | |
173 | s_instance = this; | |
174 | } | |
175 | ||
176 | MOCK_METHOD0(send, void()); | |
177 | }; | |
178 | ||
179 | template <> | |
180 | struct ImageMeta<MockTestImageCtx> { | |
181 | MOCK_METHOD1(load, void(Context*)); | |
182 | ||
183 | bool resync_requested = false; | |
184 | }; | |
185 | ||
186 | template <> | |
187 | struct UnlinkPeerRequest<MockTestImageCtx> { | |
188 | uint64_t snap_id; | |
189 | std::string mirror_peer_uuid; | |
190 | ||
191 | static UnlinkPeerRequest* s_instance; | |
192 | static UnlinkPeerRequest*create (MockTestImageCtx *image_ctx, | |
193 | uint64_t snap_id, | |
194 | const std::string &mirror_peer_uuid, | |
195 | Context *on_finish) { | |
196 | ceph_assert(s_instance != nullptr); | |
197 | s_instance->snap_id = snap_id; | |
198 | s_instance->mirror_peer_uuid = mirror_peer_uuid; | |
199 | s_instance->on_finish = on_finish; | |
200 | return s_instance; | |
201 | } | |
202 | ||
203 | Context* on_finish = nullptr; | |
204 | ||
205 | UnlinkPeerRequest() { | |
206 | s_instance = this; | |
207 | } | |
208 | ||
209 | MOCK_METHOD0(send, void()); | |
210 | }; | |
211 | ||
212 | CreateNonPrimaryRequest<MockTestImageCtx>* CreateNonPrimaryRequest<MockTestImageCtx>::s_instance = nullptr; | |
213 | GetImageStateRequest<MockTestImageCtx>* GetImageStateRequest<MockTestImageCtx>::s_instance = nullptr; | |
214 | UnlinkPeerRequest<MockTestImageCtx>* UnlinkPeerRequest<MockTestImageCtx>::s_instance = nullptr; | |
215 | ||
216 | } // namespace snapshot | |
217 | } // namespace mirror | |
218 | } // namespace librbd | |
219 | ||
220 | namespace rbd { | |
221 | namespace mirror { | |
222 | ||
223 | template <> | |
224 | struct InstanceWatcher<librbd::MockTestImageCtx> { | |
225 | MOCK_METHOD1(cancel_sync_request, void(const std::string&)); | |
226 | MOCK_METHOD2(notify_sync_request, void(const std::string&, | |
227 | Context*)); | |
228 | MOCK_METHOD1(notify_sync_complete, void(const std::string&)); | |
229 | }; | |
230 | ||
231 | template <> | |
232 | struct Threads<librbd::MockTestImageCtx> { | |
233 | MockSafeTimer *timer; | |
234 | ceph::mutex &timer_lock; | |
235 | ||
236 | MockContextWQ *work_queue; | |
237 | ||
238 | Threads(Threads<librbd::ImageCtx>* threads) | |
239 | : timer(new MockSafeTimer()), | |
240 | timer_lock(threads->timer_lock), | |
241 | work_queue(new MockContextWQ()) { | |
242 | } | |
243 | ~Threads() { | |
244 | delete timer; | |
245 | delete work_queue; | |
246 | } | |
247 | }; | |
248 | ||
249 | namespace { | |
250 | ||
251 | struct MockReplayerListener : public image_replayer::ReplayerListener { | |
252 | MOCK_METHOD0(handle_notification, void()); | |
253 | }; | |
254 | ||
255 | } // anonymous namespace | |
256 | ||
257 | namespace image_replayer { | |
258 | ||
259 | template<> | |
260 | struct CloseImageRequest<librbd::MockTestImageCtx> { | |
261 | static CloseImageRequest* s_instance; | |
262 | librbd::MockTestImageCtx **image_ctx = nullptr; | |
263 | Context *on_finish = nullptr; | |
264 | ||
265 | static CloseImageRequest* create(librbd::MockTestImageCtx **image_ctx, | |
266 | Context *on_finish) { | |
267 | ceph_assert(s_instance != nullptr); | |
268 | s_instance->image_ctx = image_ctx; | |
269 | s_instance->on_finish = on_finish; | |
270 | return s_instance; | |
271 | } | |
272 | ||
273 | CloseImageRequest() { | |
274 | ceph_assert(s_instance == nullptr); | |
275 | s_instance = this; | |
276 | } | |
277 | ||
278 | ~CloseImageRequest() { | |
279 | ceph_assert(s_instance == this); | |
280 | s_instance = nullptr; | |
281 | } | |
282 | ||
283 | MOCK_METHOD0(send, void()); | |
284 | }; | |
285 | ||
286 | CloseImageRequest<librbd::MockTestImageCtx>* CloseImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
287 | ||
288 | namespace snapshot { | |
289 | ||
290 | template <> | |
291 | struct ApplyImageStateRequest<librbd::MockTestImageCtx> { | |
292 | Context* on_finish = nullptr; | |
293 | ||
294 | static ApplyImageStateRequest* s_instance; | |
295 | static ApplyImageStateRequest* create( | |
296 | const std::string& local_mirror_uuid, | |
297 | const std::string& remote_mirror_uuid, | |
298 | librbd::MockTestImageCtx* local_image_ctx, | |
299 | librbd::MockTestImageCtx* remote_image_ctx, | |
300 | const librbd::mirror::snapshot::ImageState& image_state, | |
301 | Context* on_finish) { | |
302 | ceph_assert(s_instance != nullptr); | |
303 | s_instance->on_finish = on_finish; | |
304 | return s_instance; | |
305 | } | |
306 | ||
307 | ApplyImageStateRequest() { | |
308 | s_instance = this; | |
309 | } | |
310 | ||
311 | MOCK_METHOD0(send, void()); | |
312 | }; | |
313 | ||
314 | template<> | |
315 | struct StateBuilder<librbd::MockTestImageCtx> { | |
316 | StateBuilder(librbd::MockTestImageCtx& local_image_ctx, | |
317 | librbd::MockTestImageCtx& remote_image_ctx, | |
318 | librbd::mirror::snapshot::ImageMeta<librbd::MockTestImageCtx>& | |
319 | local_image_meta) | |
320 | : local_image_ctx(&local_image_ctx), | |
321 | remote_image_ctx(&remote_image_ctx), | |
322 | local_image_meta(&local_image_meta) { | |
323 | } | |
324 | ||
325 | librbd::MockTestImageCtx* local_image_ctx; | |
326 | librbd::MockTestImageCtx* remote_image_ctx; | |
327 | ||
328 | std::string remote_mirror_uuid = "remote mirror uuid"; | |
329 | ||
330 | librbd::mirror::snapshot::ImageMeta<librbd::MockTestImageCtx>* | |
331 | local_image_meta = nullptr; | |
332 | }; | |
333 | ||
334 | ApplyImageStateRequest<librbd::MockTestImageCtx>* ApplyImageStateRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
335 | ||
336 | } // namespace snapshot | |
337 | } // namespace image_replayer | |
338 | } // namespace mirror | |
339 | } // namespace rbd | |
340 | ||
341 | #include "tools/rbd_mirror/image_replayer/snapshot/Replayer.cc" | |
342 | ||
343 | namespace rbd { | |
344 | namespace mirror { | |
345 | namespace image_replayer { | |
346 | namespace snapshot { | |
347 | ||
348 | using ::testing::_; | |
349 | using ::testing::DoAll; | |
350 | using ::testing::InSequence; | |
351 | using ::testing::Invoke; | |
352 | using ::testing::Return; | |
353 | using ::testing::ReturnArg; | |
354 | using ::testing::StrEq; | |
355 | using ::testing::WithArg; | |
356 | ||
357 | class TestMockImageReplayerSnapshotReplayer : public TestMockFixture { | |
358 | public: | |
359 | typedef Replayer<librbd::MockTestImageCtx> MockReplayer; | |
360 | typedef ApplyImageStateRequest<librbd::MockTestImageCtx> MockApplyImageStateRequest; | |
361 | typedef StateBuilder<librbd::MockTestImageCtx> MockStateBuilder; | |
362 | typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher; | |
363 | typedef Threads<librbd::MockTestImageCtx> MockThreads; | |
364 | typedef CloseImageRequest<librbd::MockTestImageCtx> MockCloseImageRequest; | |
365 | typedef librbd::deep_copy::ImageCopyRequest<librbd::MockTestImageCtx> MockImageCopyRequest; | |
366 | typedef librbd::deep_copy::SnapshotCopyRequest<librbd::MockTestImageCtx> MockSnapshotCopyRequest; | |
367 | typedef librbd::mirror::snapshot::CreateNonPrimaryRequest<librbd::MockTestImageCtx> MockCreateNonPrimaryRequest; | |
368 | typedef librbd::mirror::snapshot::GetImageStateRequest<librbd::MockTestImageCtx> MockGetImageStateRequest; | |
369 | typedef librbd::mirror::snapshot::ImageMeta<librbd::MockTestImageCtx> MockImageMeta; | |
370 | typedef librbd::mirror::snapshot::UnlinkPeerRequest<librbd::MockTestImageCtx> MockUnlinkPeerRequest; | |
371 | ||
372 | void SetUp() override { | |
373 | TestMockFixture::SetUp(); | |
374 | ||
375 | librbd::RBD rbd; | |
376 | ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size)); | |
377 | ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx)); | |
378 | ||
379 | ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, | |
380 | m_image_size)); | |
381 | ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, | |
382 | &m_remote_image_ctx)); | |
383 | } | |
384 | ||
385 | void expect_work_queue_repeatedly(MockThreads &mock_threads) { | |
386 | EXPECT_CALL(*mock_threads.work_queue, queue(_, _)) | |
387 | .WillRepeatedly(Invoke([this](Context *ctx, int r) { | |
388 | m_threads->work_queue->queue(ctx, r); | |
389 | })); | |
390 | } | |
391 | ||
392 | void expect_add_event_after_repeatedly(MockThreads &mock_threads) { | |
393 | EXPECT_CALL(*mock_threads.timer, add_event_after(_, _)) | |
394 | .WillRepeatedly( | |
395 | DoAll(Invoke([this](double seconds, Context *ctx) { | |
396 | m_threads->timer->add_event_after(seconds, ctx); | |
397 | }), | |
398 | ReturnArg<1>())); | |
399 | EXPECT_CALL(*mock_threads.timer, cancel_event(_)) | |
400 | .WillRepeatedly( | |
401 | Invoke([this](Context *ctx) { | |
402 | return m_threads->timer->cancel_event(ctx); | |
403 | })); | |
404 | } | |
405 | ||
406 | void expect_register_update_watcher(librbd::MockTestImageCtx& mock_image_ctx, | |
407 | librbd::UpdateWatchCtx** update_watch_ctx, | |
408 | uint64_t watch_handle, int r) { | |
409 | EXPECT_CALL(*mock_image_ctx.state, register_update_watcher(_, _)) | |
410 | .WillOnce(Invoke([update_watch_ctx, watch_handle, r] | |
411 | (librbd::UpdateWatchCtx* ctx, uint64_t* handle) { | |
412 | if (r >= 0) { | |
413 | *update_watch_ctx = ctx; | |
414 | *handle = watch_handle; | |
415 | } | |
416 | return r; | |
417 | })); | |
418 | } | |
419 | ||
420 | void expect_unregister_update_watcher(librbd::MockTestImageCtx& mock_image_ctx, | |
421 | uint64_t watch_handle, int r) { | |
422 | EXPECT_CALL(*mock_image_ctx.state, unregister_update_watcher(watch_handle, _)) | |
423 | .WillOnce(WithArg<1>(Invoke([this, r](Context* ctx) { | |
424 | m_threads->work_queue->queue(ctx, r); | |
425 | }))); | |
426 | } | |
427 | ||
428 | void expect_load_image_meta(MockImageMeta& mock_image_meta, | |
429 | bool resync_requested, int r) { | |
430 | EXPECT_CALL(mock_image_meta, load(_)) | |
431 | .WillOnce(Invoke([this, &mock_image_meta, resync_requested, r](Context* ctx) { | |
432 | mock_image_meta.resync_requested = resync_requested; | |
433 | m_threads->work_queue->queue(ctx, r); | |
434 | })); | |
435 | } | |
436 | ||
437 | void expect_is_refresh_required(librbd::MockTestImageCtx& mock_image_ctx, | |
438 | bool is_required) { | |
439 | EXPECT_CALL(*mock_image_ctx.state, is_refresh_required()) | |
440 | .WillOnce(Return(is_required)); | |
441 | } | |
442 | ||
443 | void expect_refresh(librbd::MockTestImageCtx& mock_image_ctx, | |
444 | const std::map<uint64_t, librbd::SnapInfo>& snaps, | |
445 | int r) { | |
446 | EXPECT_CALL(*mock_image_ctx.state, refresh(_)) | |
447 | .WillOnce(Invoke([this, &mock_image_ctx, snaps, r](Context* ctx) { | |
448 | mock_image_ctx.snap_info = snaps; | |
449 | m_threads->work_queue->queue(ctx, r); | |
450 | })); | |
451 | } | |
452 | ||
453 | void expect_notify_update(librbd::MockTestImageCtx& mock_image_ctx) { | |
454 | EXPECT_CALL(mock_image_ctx, notify_update(_)) | |
455 | .WillOnce(Invoke([this](Context* ctx) { | |
456 | m_threads->work_queue->queue(ctx, 0); | |
457 | })); | |
458 | } | |
459 | ||
1911f103 TL |
460 | void expect_prune_non_primary_snapshot(librbd::MockTestImageCtx& mock_image_ctx, |
461 | uint64_t snap_id, int r) { | |
462 | EXPECT_CALL(mock_image_ctx, get_snap_info(snap_id)) | |
463 | .WillOnce(Invoke([&mock_image_ctx](uint64_t snap_id) -> librbd::SnapInfo* { | |
464 | auto it = mock_image_ctx.snap_info.find(snap_id); | |
465 | if (it == mock_image_ctx.snap_info.end()) { | |
466 | return nullptr; | |
467 | } | |
468 | return &it->second; | |
469 | })); | |
470 | EXPECT_CALL(*mock_image_ctx.operations, snap_remove(_, _, _)) | |
471 | .WillOnce(WithArg<2>(Invoke([this, r](Context* ctx) { | |
472 | m_threads->work_queue->queue(ctx, r); | |
473 | }))); | |
474 | } | |
475 | ||
9f95a23c TL |
476 | void expect_snapshot_copy(MockSnapshotCopyRequest& mock_snapshot_copy_request, |
477 | uint64_t src_snap_id_start, | |
478 | uint64_t src_snap_id_end, | |
479 | uint64_t dst_snap_id_start, | |
480 | const librbd::SnapSeqs& snap_seqs, int r) { | |
481 | EXPECT_CALL(mock_snapshot_copy_request, send()) | |
482 | .WillOnce(Invoke([this, &req=mock_snapshot_copy_request, | |
483 | src_snap_id_start, src_snap_id_end, dst_snap_id_start, | |
484 | snap_seqs, r]() { | |
485 | ASSERT_EQ(src_snap_id_start, req.src_snap_id_start); | |
486 | ASSERT_EQ(src_snap_id_end, req.src_snap_id_end); | |
487 | ASSERT_EQ(dst_snap_id_start, req.dst_snap_id_start); | |
488 | *req.snap_seqs = snap_seqs; | |
489 | m_threads->work_queue->queue(req.on_finish, r); | |
490 | })); | |
491 | } | |
492 | ||
493 | void expect_get_image_state(MockGetImageStateRequest& mock_get_image_state_request, | |
494 | uint64_t snap_id, int r) { | |
495 | EXPECT_CALL(mock_get_image_state_request, send()) | |
496 | .WillOnce(Invoke([this, &req=mock_get_image_state_request, snap_id, r]() { | |
497 | ASSERT_EQ(snap_id, req.snap_id); | |
498 | m_threads->work_queue->queue(req.on_finish, r); | |
499 | })); | |
500 | } | |
501 | ||
502 | void expect_create_non_primary_request(MockCreateNonPrimaryRequest& mock_create_non_primary_request, | |
503 | bool demoted, | |
504 | const std::string& primary_mirror_uuid, | |
505 | uint64_t primary_snap_id, | |
506 | const librbd::SnapSeqs& snap_seqs, | |
507 | uint64_t snap_id, int r) { | |
508 | EXPECT_CALL(mock_create_non_primary_request, send()) | |
509 | .WillOnce(Invoke([this, &req=mock_create_non_primary_request, demoted, | |
510 | primary_mirror_uuid, primary_snap_id, snap_seqs, | |
511 | snap_id, r]() { | |
512 | ASSERT_EQ(demoted, req.demoted); | |
513 | ASSERT_EQ(primary_mirror_uuid, req.primary_mirror_uuid); | |
514 | ASSERT_EQ(primary_snap_id, req.primary_snap_id); | |
515 | ASSERT_EQ(snap_seqs, req.snap_seqs); | |
516 | *req.snap_id = snap_id; | |
517 | m_threads->work_queue->queue(req.on_finish, r); | |
518 | })); | |
519 | } | |
520 | ||
521 | void expect_notify_sync_request(MockInstanceWatcher& mock_instance_watcher, | |
522 | const std::string& image_id, int r) { | |
523 | EXPECT_CALL(mock_instance_watcher, notify_sync_request(image_id, _)) | |
524 | .WillOnce(WithArg<1>(Invoke([this, r](Context* ctx) { | |
525 | m_threads->work_queue->queue(ctx, r); | |
526 | }))); | |
527 | } | |
528 | ||
529 | void expect_notify_sync_complete(MockInstanceWatcher& mock_instance_watcher, | |
530 | const std::string& image_id) { | |
531 | EXPECT_CALL(mock_instance_watcher, notify_sync_complete(image_id)); | |
532 | } | |
533 | ||
534 | void expect_image_copy(MockImageCopyRequest& mock_image_copy_request, | |
535 | uint64_t src_snap_id_start, uint64_t src_snap_id_end, | |
536 | uint64_t dst_snap_id_start, | |
537 | const librbd::deep_copy::ObjectNumber& object_number, | |
538 | const librbd::SnapSeqs& snap_seqs, int r) { | |
539 | EXPECT_CALL(mock_image_copy_request, send()) | |
540 | .WillOnce(Invoke([this, &req=mock_image_copy_request, src_snap_id_start, | |
541 | src_snap_id_end, dst_snap_id_start, object_number, | |
542 | snap_seqs, r]() { | |
543 | ASSERT_EQ(src_snap_id_start, req.src_snap_id_start); | |
544 | ASSERT_EQ(src_snap_id_end, req.src_snap_id_end); | |
545 | ASSERT_EQ(dst_snap_id_start, req.dst_snap_id_start); | |
546 | ASSERT_EQ(object_number, req.object_number); | |
547 | ASSERT_EQ(snap_seqs, req.snap_seqs); | |
548 | m_threads->work_queue->queue(req.on_finish, r); | |
549 | })); | |
550 | } | |
551 | ||
552 | void expect_unlink_peer(MockUnlinkPeerRequest& mock_unlink_peer_request, | |
553 | uint64_t snap_id, const std::string& mirror_peer_uuid, | |
554 | int r) { | |
555 | EXPECT_CALL(mock_unlink_peer_request, send()) | |
556 | .WillOnce(Invoke([this, &req=mock_unlink_peer_request, snap_id, | |
557 | mirror_peer_uuid, r]() { | |
558 | ASSERT_EQ(snap_id, req.snap_id); | |
559 | ASSERT_EQ(mirror_peer_uuid, req.mirror_peer_uuid); | |
560 | m_threads->work_queue->queue(req.on_finish, r); | |
561 | })); | |
562 | } | |
563 | ||
564 | void expect_apply_image_state( | |
565 | MockApplyImageStateRequest& mock_request, int r) { | |
566 | EXPECT_CALL(mock_request, send()) | |
567 | .WillOnce(Invoke([this, &req=mock_request, r]() { | |
568 | m_threads->work_queue->queue(req.on_finish, r); | |
569 | })); | |
570 | } | |
571 | ||
572 | void expect_mirror_image_snapshot_set_copy_progress( | |
573 | librbd::MockTestImageCtx& mock_test_image_ctx, uint64_t snap_id, | |
574 | bool completed, uint64_t last_copied_object, int r) { | |
575 | bufferlist bl; | |
576 | encode(snap_id, bl); | |
577 | encode(completed, bl); | |
578 | encode(last_copied_object, bl); | |
579 | ||
580 | EXPECT_CALL(get_mock_io_ctx(mock_test_image_ctx.md_ctx), | |
581 | exec(mock_test_image_ctx.header_oid, _, StrEq("rbd"), | |
582 | StrEq("mirror_image_snapshot_set_copy_progress"), | |
583 | ContentsEqual(bl), _, _)) | |
584 | .WillOnce(Return(r)); | |
585 | } | |
586 | ||
587 | void expect_send(MockCloseImageRequest &mock_close_image_request, int r) { | |
588 | EXPECT_CALL(mock_close_image_request, send()) | |
589 | .WillOnce(Invoke([this, &mock_close_image_request, r]() { | |
590 | *mock_close_image_request.image_ctx = nullptr; | |
591 | m_threads->work_queue->queue(mock_close_image_request.on_finish, r); | |
592 | })); | |
593 | } | |
594 | ||
595 | void expect_notification(MockThreads& mock_threads, | |
596 | MockReplayerListener& mock_replayer_listener) { | |
597 | EXPECT_CALL(mock_replayer_listener, handle_notification()) | |
598 | .WillRepeatedly(Invoke([this]() { | |
599 | std::unique_lock locker{m_lock}; | |
600 | ++m_notifications; | |
601 | m_cond.notify_all(); | |
602 | })); | |
603 | } | |
604 | ||
605 | int wait_for_notification(uint32_t count) { | |
606 | std::unique_lock locker{m_lock}; | |
607 | for (uint32_t idx = 0; idx < count; ++idx) { | |
608 | while (m_notifications == 0) { | |
609 | if (m_cond.wait_for(locker, 10s) == std::cv_status::timeout) { | |
610 | return -ETIMEDOUT; | |
611 | } | |
612 | } | |
613 | --m_notifications; | |
614 | } | |
615 | return 0; | |
616 | } | |
617 | ||
618 | int init_entry_replayer(MockReplayer& mock_replayer, | |
619 | MockThreads& mock_threads, | |
620 | librbd::MockTestImageCtx& mock_local_image_ctx, | |
621 | librbd::MockTestImageCtx& mock_remote_image_ctx, | |
622 | MockReplayerListener& mock_replayer_listener, | |
623 | MockImageMeta& mock_image_meta, | |
624 | librbd::UpdateWatchCtx** update_watch_ctx) { | |
625 | expect_register_update_watcher(mock_local_image_ctx, update_watch_ctx, 123, | |
626 | 0); | |
627 | expect_register_update_watcher(mock_remote_image_ctx, update_watch_ctx, 234, | |
628 | 0); | |
629 | expect_load_image_meta(mock_image_meta, false, 0); | |
630 | expect_is_refresh_required(mock_local_image_ctx, false); | |
631 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
632 | ||
633 | C_SaferCond init_ctx; | |
634 | mock_replayer.init(&init_ctx); | |
635 | int r = init_ctx.wait(); | |
636 | if (r < 0) { | |
637 | return r; | |
638 | } | |
639 | ||
640 | return wait_for_notification(2); | |
641 | } | |
642 | ||
643 | int shut_down_entry_replayer(MockReplayer& mock_replayer, | |
644 | MockThreads& mock_threads, | |
645 | librbd::MockTestImageCtx& mock_local_image_ctx, | |
646 | librbd::MockTestImageCtx& mock_remote_image_ctx) { | |
647 | expect_unregister_update_watcher(mock_remote_image_ctx, 234, 0); | |
648 | expect_unregister_update_watcher(mock_local_image_ctx, 123, 0); | |
649 | ||
650 | C_SaferCond shutdown_ctx; | |
651 | mock_replayer.shut_down(&shutdown_ctx); | |
652 | return shutdown_ctx.wait(); | |
653 | } | |
654 | ||
655 | librbd::ImageCtx* m_local_image_ctx = nullptr; | |
656 | librbd::ImageCtx* m_remote_image_ctx = nullptr; | |
657 | ||
658 | PoolMetaCache m_pool_meta_cache{g_ceph_context}; | |
659 | ||
660 | ceph::mutex m_lock = ceph::make_mutex( | |
661 | "TestMockImageReplayerSnapshotReplayer"); | |
662 | ceph::condition_variable m_cond; | |
663 | uint32_t m_notifications = 0; | |
664 | }; | |
665 | ||
666 | TEST_F(TestMockImageReplayerSnapshotReplayer, InitShutDown) { | |
667 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
668 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
669 | ||
670 | MockThreads mock_threads(m_threads); | |
671 | expect_work_queue_repeatedly(mock_threads); | |
672 | ||
673 | MockReplayerListener mock_replayer_listener; | |
674 | expect_notification(mock_threads, mock_replayer_listener); | |
675 | ||
676 | InSequence seq; | |
677 | ||
678 | MockInstanceWatcher mock_instance_watcher; | |
679 | MockImageMeta mock_image_meta; | |
680 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
681 | mock_remote_image_ctx, | |
682 | mock_image_meta); | |
683 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
684 | "local mirror uuid", &m_pool_meta_cache, | |
685 | &mock_state_builder, &mock_replayer_listener}; | |
686 | m_pool_meta_cache.set_remote_pool_meta( | |
687 | m_remote_io_ctx.get_id(), | |
688 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
689 | ||
690 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
691 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
692 | mock_local_image_ctx, | |
693 | mock_remote_image_ctx, | |
694 | mock_replayer_listener, | |
695 | mock_image_meta, | |
696 | &update_watch_ctx)); | |
697 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
698 | mock_local_image_ctx, | |
699 | mock_remote_image_ctx)); | |
700 | } | |
701 | ||
702 | TEST_F(TestMockImageReplayerSnapshotReplayer, SyncSnapshot) { | |
703 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
704 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
705 | ||
706 | // it should sync two snapshots and skip two (user and mirror w/o matching | |
707 | // peer uuid) | |
708 | mock_remote_image_ctx.snap_info = { | |
709 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
710 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, | |
1911f103 | 711 | "", CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
712 | 0, {}, 0, 0, {}}}, |
713 | {2U, librbd::SnapInfo{"snap2", cls::rbd::UserSnapshotNamespace{}, | |
714 | 0, {}, 0, 0, {}}}, | |
715 | {3U, librbd::SnapInfo{"snap3", cls::rbd::MirrorSnapshotNamespace{ | |
716 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {""}, | |
1911f103 | 717 | "", CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
718 | 0, {}, 0, 0, {}}}, |
719 | {4U, librbd::SnapInfo{"snap4", cls::rbd::MirrorSnapshotNamespace{ | |
720 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, | |
1911f103 | 721 | "", CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
722 | 0, {}, 0, 0, {}}}}; |
723 | ||
724 | MockThreads mock_threads(m_threads); | |
725 | expect_work_queue_repeatedly(mock_threads); | |
726 | ||
727 | MockReplayerListener mock_replayer_listener; | |
728 | expect_notification(mock_threads, mock_replayer_listener); | |
729 | ||
730 | InSequence seq; | |
731 | ||
732 | MockInstanceWatcher mock_instance_watcher; | |
733 | MockImageMeta mock_image_meta; | |
734 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
735 | mock_remote_image_ctx, | |
736 | mock_image_meta); | |
737 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
738 | "local mirror uuid", &m_pool_meta_cache, | |
739 | &mock_state_builder, &mock_replayer_listener}; | |
740 | m_pool_meta_cache.set_remote_pool_meta( | |
741 | m_remote_io_ctx.get_id(), | |
742 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
743 | ||
744 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
745 | ||
746 | // init | |
747 | expect_register_update_watcher(mock_local_image_ctx, &update_watch_ctx, 123, | |
748 | 0); | |
749 | expect_register_update_watcher(mock_remote_image_ctx, &update_watch_ctx, 234, | |
750 | 0); | |
751 | ||
752 | // sync snap1 | |
753 | expect_load_image_meta(mock_image_meta, false, 0); | |
754 | expect_is_refresh_required(mock_local_image_ctx, false); | |
755 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
756 | MockSnapshotCopyRequest mock_snapshot_copy_request; | |
757 | expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, | |
758 | 0); | |
759 | MockGetImageStateRequest mock_get_image_state_request; | |
760 | expect_get_image_state(mock_get_image_state_request, 1, 0); | |
761 | MockCreateNonPrimaryRequest mock_create_non_primary_request; | |
762 | expect_create_non_primary_request(mock_create_non_primary_request, | |
763 | false, "remote mirror uuid", 1, | |
764 | {{1, CEPH_NOSNAP}}, 11, 0); | |
765 | expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); | |
766 | MockImageCopyRequest mock_image_copy_request; | |
767 | expect_image_copy(mock_image_copy_request, 0, 1, 0, {}, | |
768 | {{1, CEPH_NOSNAP}}, 0); | |
769 | MockApplyImageStateRequest mock_apply_state_request; | |
770 | expect_apply_image_state(mock_apply_state_request, 0); | |
771 | expect_mirror_image_snapshot_set_copy_progress( | |
772 | mock_local_image_ctx, 11, true, 0, 0); | |
773 | expect_notify_update(mock_local_image_ctx); | |
774 | expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); | |
775 | ||
776 | // sync snap4 | |
777 | expect_load_image_meta(mock_image_meta, false, 0); | |
778 | expect_is_refresh_required(mock_local_image_ctx, true); | |
779 | expect_refresh( | |
780 | mock_local_image_ctx, { | |
781 | {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
782 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", | |
1911f103 | 783 | 1, true, 0, {{1, CEPH_NOSNAP}}}, |
9f95a23c TL |
784 | 0, {}, 0, 0, {}}}, |
785 | }, 0); | |
786 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
787 | expect_snapshot_copy(mock_snapshot_copy_request, 1, 4, 11, | |
1911f103 | 788 | {{1, 11}, {2, 12}, {4, CEPH_NOSNAP}}, 0); |
9f95a23c TL |
789 | expect_get_image_state(mock_get_image_state_request, 4, 0); |
790 | expect_create_non_primary_request(mock_create_non_primary_request, | |
791 | false, "remote mirror uuid", 4, | |
1911f103 TL |
792 | {{1, 11}, {2, 12}, {4, CEPH_NOSNAP}}, 14, |
793 | 0); | |
9f95a23c TL |
794 | expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); |
795 | expect_image_copy(mock_image_copy_request, 1, 4, 11, {}, | |
1911f103 | 796 | {{1, 11}, {2, 12}, {4, CEPH_NOSNAP}}, 0); |
9f95a23c TL |
797 | expect_apply_image_state(mock_apply_state_request, 0); |
798 | expect_mirror_image_snapshot_set_copy_progress( | |
799 | mock_local_image_ctx, 14, true, 0, 0); | |
800 | expect_notify_update(mock_local_image_ctx); | |
801 | MockUnlinkPeerRequest mock_unlink_peer_request; | |
802 | expect_unlink_peer(mock_unlink_peer_request, 1, "remote mirror peer uuid", | |
803 | 0); | |
804 | expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); | |
805 | ||
1911f103 | 806 | // prune non-primary snap1 |
9f95a23c TL |
807 | expect_load_image_meta(mock_image_meta, false, 0); |
808 | expect_is_refresh_required(mock_local_image_ctx, true); | |
809 | expect_refresh( | |
810 | mock_local_image_ctx, { | |
811 | {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
812 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", | |
813 | 1, true, 0, {}}, | |
814 | 0, {}, 0, 0, {}}}, | |
1911f103 TL |
815 | {12U, librbd::SnapInfo{"snap2", cls::rbd::UserSnapshotNamespace{}, |
816 | 0, {}, 0, 0, {}}}, | |
817 | {14U, librbd::SnapInfo{"snap4", cls::rbd::MirrorSnapshotNamespace{ | |
818 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", | |
819 | 4, true, 0, {}}, | |
820 | 0, {}, 0, 0, {}}}, | |
821 | }, 0); | |
822 | expect_is_refresh_required(mock_remote_image_ctx, true); | |
823 | expect_refresh( | |
824 | mock_remote_image_ctx, { | |
825 | {2U, librbd::SnapInfo{"snap2", cls::rbd::UserSnapshotNamespace{}, | |
826 | 0, {}, 0, 0, {}}}, | |
827 | {3U, librbd::SnapInfo{"snap3", cls::rbd::MirrorSnapshotNamespace{ | |
828 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {""}, | |
829 | "", CEPH_NOSNAP, true, 0, {}}, | |
830 | 0, {}, 0, 0, {}}}, | |
831 | {4U, librbd::SnapInfo{"snap4", cls::rbd::MirrorSnapshotNamespace{ | |
832 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, | |
833 | "", CEPH_NOSNAP, true, 0, {}}, | |
834 | 0, {}, 0, 0, {}}} | |
835 | }, 0); | |
836 | expect_prune_non_primary_snapshot(mock_local_image_ctx, 11, 0); | |
837 | ||
838 | // idle | |
839 | expect_load_image_meta(mock_image_meta, false, 0); | |
840 | expect_is_refresh_required(mock_local_image_ctx, true); | |
841 | expect_refresh( | |
842 | mock_local_image_ctx, { | |
9f95a23c TL |
843 | {14U, librbd::SnapInfo{"snap4", cls::rbd::MirrorSnapshotNamespace{ |
844 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", | |
845 | 4, true, 0, {}}, | |
846 | 0, {}, 0, 0, {}}}, | |
847 | }, 0); | |
848 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
849 | ||
850 | // fire init | |
851 | C_SaferCond init_ctx; | |
852 | mock_replayer.init(&init_ctx); | |
853 | ASSERT_EQ(0, init_ctx.wait()); | |
854 | ||
855 | // wait for sync to complete | |
856 | ASSERT_EQ(0, wait_for_notification(4)); | |
857 | ||
858 | // shut down | |
859 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
860 | mock_local_image_ctx, | |
861 | mock_remote_image_ctx)); | |
862 | } | |
863 | ||
864 | TEST_F(TestMockImageReplayerSnapshotReplayer, InterruptedSync) { | |
865 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
866 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
867 | ||
868 | MockThreads mock_threads(m_threads); | |
869 | expect_work_queue_repeatedly(mock_threads); | |
870 | ||
871 | MockReplayerListener mock_replayer_listener; | |
872 | expect_notification(mock_threads, mock_replayer_listener); | |
873 | ||
874 | InSequence seq; | |
875 | ||
876 | MockInstanceWatcher mock_instance_watcher; | |
877 | MockImageMeta mock_image_meta; | |
878 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
879 | mock_remote_image_ctx, | |
880 | mock_image_meta); | |
881 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
882 | "local mirror uuid", &m_pool_meta_cache, | |
883 | &mock_state_builder, &mock_replayer_listener}; | |
884 | m_pool_meta_cache.set_remote_pool_meta( | |
885 | m_remote_io_ctx.get_id(), | |
886 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
887 | ||
888 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
889 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
890 | mock_local_image_ctx, | |
891 | mock_remote_image_ctx, | |
892 | mock_replayer_listener, | |
893 | mock_image_meta, | |
894 | &update_watch_ctx)); | |
895 | ||
896 | // inject a incomplete sync snapshot | |
897 | mock_remote_image_ctx.snap_info = { | |
898 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
899 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, | |
1911f103 | 900 | "", CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
901 | 0, {}, 0, 0, {}}}}; |
902 | mock_local_image_ctx.snap_info = { | |
903 | {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
904 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", | |
905 | 1, false, 123, {{1, CEPH_NOSNAP}}}, | |
906 | 0, {}, 0, 0, {}}}}; | |
907 | ||
908 | // re-sync snap1 | |
909 | expect_load_image_meta(mock_image_meta, false, 0); | |
910 | expect_is_refresh_required(mock_local_image_ctx, false); | |
911 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
912 | MockGetImageStateRequest mock_get_image_state_request; | |
913 | expect_get_image_state(mock_get_image_state_request, 11, 0); | |
914 | expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); | |
915 | MockImageCopyRequest mock_image_copy_request; | |
916 | expect_image_copy(mock_image_copy_request, 0, 1, 0, | |
917 | librbd::deep_copy::ObjectNumber{123U}, | |
918 | {{1, CEPH_NOSNAP}}, 0); | |
919 | MockApplyImageStateRequest mock_apply_state_request; | |
920 | expect_apply_image_state(mock_apply_state_request, 0); | |
921 | expect_mirror_image_snapshot_set_copy_progress( | |
922 | mock_local_image_ctx, 11, true, 123, 0); | |
923 | expect_notify_update(mock_local_image_ctx); | |
1911f103 | 924 | expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); |
9f95a23c TL |
925 | |
926 | // idle | |
927 | expect_load_image_meta(mock_image_meta, false, 0); | |
928 | expect_is_refresh_required(mock_local_image_ctx, true); | |
929 | expect_refresh( | |
930 | mock_local_image_ctx, { | |
931 | {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
932 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", | |
933 | 1, true, 0, {}}, | |
934 | 0, {}, 0, 0, {}}}, | |
935 | }, 0); | |
936 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
937 | ||
938 | // wake-up replayer | |
939 | update_watch_ctx->handle_notify(); | |
940 | ||
941 | // wait for sync to complete | |
942 | ASSERT_EQ(0, wait_for_notification(2)); | |
943 | ||
944 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
945 | mock_local_image_ctx, | |
946 | mock_remote_image_ctx)); | |
947 | } | |
948 | ||
949 | TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteImageDemoted) { | |
950 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
951 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
952 | ||
953 | MockThreads mock_threads(m_threads); | |
954 | expect_work_queue_repeatedly(mock_threads); | |
955 | ||
956 | MockReplayerListener mock_replayer_listener; | |
957 | expect_notification(mock_threads, mock_replayer_listener); | |
958 | ||
959 | InSequence seq; | |
960 | ||
961 | MockInstanceWatcher mock_instance_watcher; | |
962 | MockImageMeta mock_image_meta; | |
963 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
964 | mock_remote_image_ctx, | |
965 | mock_image_meta); | |
966 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
967 | "local mirror uuid", &m_pool_meta_cache, | |
968 | &mock_state_builder, &mock_replayer_listener}; | |
969 | m_pool_meta_cache.set_remote_pool_meta( | |
970 | m_remote_io_ctx.get_id(), | |
971 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
972 | ||
973 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
974 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
975 | mock_local_image_ctx, | |
976 | mock_remote_image_ctx, | |
977 | mock_replayer_listener, | |
978 | mock_image_meta, | |
979 | &update_watch_ctx)); | |
980 | ||
981 | // inject a demotion snapshot | |
982 | mock_remote_image_ctx.snap_info = { | |
983 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
984 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, | |
1911f103 | 985 | {"remote mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
986 | 0, {}, 0, 0, {}}}}; |
987 | ||
988 | // sync snap1 | |
989 | expect_load_image_meta(mock_image_meta, false, 0); | |
990 | expect_is_refresh_required(mock_local_image_ctx, false); | |
991 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
992 | MockSnapshotCopyRequest mock_snapshot_copy_request; | |
993 | expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, | |
994 | 0); | |
995 | MockGetImageStateRequest mock_get_image_state_request; | |
996 | expect_get_image_state(mock_get_image_state_request, 1, 0); | |
997 | MockCreateNonPrimaryRequest mock_create_non_primary_request; | |
998 | expect_create_non_primary_request(mock_create_non_primary_request, | |
999 | true, "remote mirror uuid", 1, | |
1000 | {{1, CEPH_NOSNAP}}, 11, 0); | |
1001 | expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); | |
1002 | MockImageCopyRequest mock_image_copy_request; | |
1003 | expect_image_copy(mock_image_copy_request, 0, 1, 0, {}, | |
1004 | {{1, CEPH_NOSNAP}}, 0); | |
1005 | MockApplyImageStateRequest mock_apply_state_request; | |
1006 | expect_apply_image_state(mock_apply_state_request, 0); | |
1007 | expect_mirror_image_snapshot_set_copy_progress( | |
1008 | mock_local_image_ctx, 11, true, 0, 0); | |
1009 | expect_notify_update(mock_local_image_ctx); | |
1911f103 | 1010 | expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); |
9f95a23c TL |
1011 | |
1012 | // idle | |
1013 | expect_load_image_meta(mock_image_meta, false, 0); | |
1014 | expect_is_refresh_required(mock_local_image_ctx, true); | |
1015 | expect_refresh( | |
1016 | mock_local_image_ctx, { | |
1017 | {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
1018 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", | |
1019 | 1, true, 0, {}}, | |
1020 | 0, {}, 0, 0, {}}}, | |
1021 | }, 0); | |
1022 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
1023 | ||
1024 | // wake-up replayer | |
1025 | update_watch_ctx->handle_notify(); | |
1026 | ||
1027 | // wait for sync to complete and expect replay complete | |
1028 | ASSERT_EQ(0, wait_for_notification(2)); | |
1029 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1030 | ||
1031 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1032 | mock_local_image_ctx, | |
1033 | mock_remote_image_ctx)); | |
1034 | } | |
1035 | ||
1036 | TEST_F(TestMockImageReplayerSnapshotReplayer, LocalImagePromoted) { | |
1037 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1038 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1039 | ||
1040 | MockThreads mock_threads(m_threads); | |
1041 | expect_work_queue_repeatedly(mock_threads); | |
1042 | ||
1043 | MockReplayerListener mock_replayer_listener; | |
1044 | expect_notification(mock_threads, mock_replayer_listener); | |
1045 | ||
1046 | InSequence seq; | |
1047 | ||
1048 | MockInstanceWatcher mock_instance_watcher; | |
1049 | MockImageMeta mock_image_meta; | |
1050 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1051 | mock_remote_image_ctx, | |
1052 | mock_image_meta); | |
1053 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1054 | "local mirror uuid", &m_pool_meta_cache, | |
1055 | &mock_state_builder, &mock_replayer_listener}; | |
1056 | m_pool_meta_cache.set_remote_pool_meta( | |
1057 | m_remote_io_ctx.get_id(), | |
1058 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1059 | ||
1060 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1061 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1062 | mock_local_image_ctx, | |
1063 | mock_remote_image_ctx, | |
1064 | mock_replayer_listener, | |
1065 | mock_image_meta, | |
1066 | &update_watch_ctx)); | |
1067 | ||
1068 | // inject a promotion snapshot | |
1069 | mock_local_image_ctx.snap_info = { | |
1070 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
1071 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, | |
1911f103 | 1072 | {"remote mirror peer uuid"}, "", CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
1073 | 0, {}, 0, 0, {}}}}; |
1074 | ||
1075 | // idle | |
1076 | expect_load_image_meta(mock_image_meta, false, 0); | |
1077 | expect_is_refresh_required(mock_local_image_ctx, false); | |
1078 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
1079 | ||
1080 | // wake-up replayer | |
1081 | update_watch_ctx->handle_notify(); | |
1082 | ||
1083 | // wait for sync to complete and expect replay complete | |
1084 | ASSERT_EQ(0, wait_for_notification(1)); | |
1085 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1086 | ||
1087 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1088 | mock_local_image_ctx, | |
1089 | mock_remote_image_ctx)); | |
1090 | } | |
1091 | ||
1092 | TEST_F(TestMockImageReplayerSnapshotReplayer, ResyncRequested) { | |
1093 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1094 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1095 | ||
1096 | MockThreads mock_threads(m_threads); | |
1097 | expect_work_queue_repeatedly(mock_threads); | |
1098 | ||
1099 | MockReplayerListener mock_replayer_listener; | |
1100 | expect_notification(mock_threads, mock_replayer_listener); | |
1101 | ||
1102 | InSequence seq; | |
1103 | ||
1104 | MockInstanceWatcher mock_instance_watcher; | |
1105 | MockImageMeta mock_image_meta; | |
1106 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1107 | mock_remote_image_ctx, | |
1108 | mock_image_meta); | |
1109 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1110 | "local mirror uuid", &m_pool_meta_cache, | |
1111 | &mock_state_builder, &mock_replayer_listener}; | |
1112 | m_pool_meta_cache.set_remote_pool_meta( | |
1113 | m_remote_io_ctx.get_id(), | |
1114 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1115 | ||
1116 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1117 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1118 | mock_local_image_ctx, | |
1119 | mock_remote_image_ctx, | |
1120 | mock_replayer_listener, | |
1121 | mock_image_meta, | |
1122 | &update_watch_ctx)); | |
1123 | ||
1124 | // idle | |
1125 | expect_load_image_meta(mock_image_meta, true, 0); | |
1126 | ||
1127 | // wake-up replayer | |
1128 | update_watch_ctx->handle_notify(); | |
1129 | ||
1130 | // wait for sync to complete and expect replay complete | |
1131 | ASSERT_EQ(0, wait_for_notification(1)); | |
1132 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1133 | ||
1134 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1135 | mock_local_image_ctx, | |
1136 | mock_remote_image_ctx)); | |
1137 | } | |
1138 | ||
1139 | TEST_F(TestMockImageReplayerSnapshotReplayer, RegisterLocalUpdateWatcherError) { | |
1140 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1141 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1142 | ||
1143 | MockThreads mock_threads(m_threads); | |
1144 | expect_work_queue_repeatedly(mock_threads); | |
1145 | ||
1146 | InSequence seq; | |
1147 | ||
1148 | MockInstanceWatcher mock_instance_watcher; | |
1149 | MockImageMeta mock_image_meta; | |
1150 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1151 | mock_remote_image_ctx, | |
1152 | mock_image_meta); | |
1153 | MockReplayerListener mock_replayer_listener; | |
1154 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1155 | "local mirror uuid", &m_pool_meta_cache, | |
1156 | &mock_state_builder, &mock_replayer_listener}; | |
1157 | m_pool_meta_cache.set_remote_pool_meta( | |
1158 | m_remote_io_ctx.get_id(), | |
1159 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1160 | ||
1161 | // init | |
1162 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1163 | expect_register_update_watcher(mock_local_image_ctx, &update_watch_ctx, 123, | |
1164 | -EINVAL); | |
1165 | ||
1166 | // fire init | |
1167 | C_SaferCond init_ctx; | |
1168 | mock_replayer.init(&init_ctx); | |
1169 | ASSERT_EQ(-EINVAL, init_ctx.wait()); | |
1170 | } | |
1171 | ||
1172 | TEST_F(TestMockImageReplayerSnapshotReplayer, RegisterRemoteUpdateWatcherError) { | |
1173 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1174 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1175 | ||
1176 | MockThreads mock_threads(m_threads); | |
1177 | expect_work_queue_repeatedly(mock_threads); | |
1178 | ||
1179 | InSequence seq; | |
1180 | ||
1181 | MockInstanceWatcher mock_instance_watcher; | |
1182 | MockImageMeta mock_image_meta; | |
1183 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1184 | mock_remote_image_ctx, | |
1185 | mock_image_meta); | |
1186 | MockReplayerListener mock_replayer_listener; | |
1187 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1188 | "local mirror uuid", &m_pool_meta_cache, | |
1189 | &mock_state_builder, &mock_replayer_listener}; | |
1190 | m_pool_meta_cache.set_remote_pool_meta( | |
1191 | m_remote_io_ctx.get_id(), | |
1192 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1193 | ||
1194 | // init | |
1195 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1196 | expect_register_update_watcher(mock_local_image_ctx, &update_watch_ctx, 123, | |
1197 | 0); | |
1198 | expect_register_update_watcher(mock_remote_image_ctx, &update_watch_ctx, 234, | |
1199 | -EINVAL); | |
1200 | ||
1201 | expect_unregister_update_watcher(mock_local_image_ctx, 123, 0); | |
1202 | ||
1203 | // fire init | |
1204 | C_SaferCond init_ctx; | |
1205 | mock_replayer.init(&init_ctx); | |
1206 | ASSERT_EQ(-EINVAL, init_ctx.wait()); | |
1207 | } | |
1208 | ||
1209 | TEST_F(TestMockImageReplayerSnapshotReplayer, UnregisterRemoteUpdateWatcherError) { | |
1210 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1211 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1212 | ||
1213 | MockThreads mock_threads(m_threads); | |
1214 | expect_work_queue_repeatedly(mock_threads); | |
1215 | ||
1216 | MockReplayerListener mock_replayer_listener; | |
1217 | expect_notification(mock_threads, mock_replayer_listener); | |
1218 | ||
1219 | InSequence seq; | |
1220 | ||
1221 | MockInstanceWatcher mock_instance_watcher; | |
1222 | MockImageMeta mock_image_meta; | |
1223 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1224 | mock_remote_image_ctx, | |
1225 | mock_image_meta); | |
1226 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1227 | "local mirror uuid", &m_pool_meta_cache, | |
1228 | &mock_state_builder, &mock_replayer_listener}; | |
1229 | m_pool_meta_cache.set_remote_pool_meta( | |
1230 | m_remote_io_ctx.get_id(), | |
1231 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1232 | ||
1233 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1234 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1235 | mock_local_image_ctx, | |
1236 | mock_remote_image_ctx, | |
1237 | mock_replayer_listener, | |
1238 | mock_image_meta, | |
1239 | &update_watch_ctx)); | |
1240 | ||
1241 | ||
1242 | // shut down | |
1243 | expect_unregister_update_watcher(mock_remote_image_ctx, 234, -EINVAL); | |
1244 | expect_unregister_update_watcher(mock_local_image_ctx, 123, 0); | |
1245 | ||
1246 | C_SaferCond shutdown_ctx; | |
1247 | mock_replayer.shut_down(&shutdown_ctx); | |
1248 | ASSERT_EQ(-EINVAL, shutdown_ctx.wait()); | |
1249 | } | |
1250 | ||
1251 | TEST_F(TestMockImageReplayerSnapshotReplayer, UnregisterLocalUpdateWatcherError) { | |
1252 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1253 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1254 | ||
1255 | MockThreads mock_threads(m_threads); | |
1256 | expect_work_queue_repeatedly(mock_threads); | |
1257 | ||
1258 | MockReplayerListener mock_replayer_listener; | |
1259 | expect_notification(mock_threads, mock_replayer_listener); | |
1260 | ||
1261 | InSequence seq; | |
1262 | ||
1263 | MockInstanceWatcher mock_instance_watcher; | |
1264 | MockImageMeta mock_image_meta; | |
1265 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1266 | mock_remote_image_ctx, | |
1267 | mock_image_meta); | |
1268 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1269 | "local mirror uuid", &m_pool_meta_cache, | |
1270 | &mock_state_builder, &mock_replayer_listener}; | |
1271 | m_pool_meta_cache.set_remote_pool_meta( | |
1272 | m_remote_io_ctx.get_id(), | |
1273 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1274 | ||
1275 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1276 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1277 | mock_local_image_ctx, | |
1278 | mock_remote_image_ctx, | |
1279 | mock_replayer_listener, | |
1280 | mock_image_meta, | |
1281 | &update_watch_ctx)); | |
1282 | ||
1283 | ||
1284 | // shut down | |
1285 | expect_unregister_update_watcher(mock_remote_image_ctx, 234, 0); | |
1286 | expect_unregister_update_watcher(mock_local_image_ctx, 123, -EINVAL); | |
1287 | ||
1288 | C_SaferCond shutdown_ctx; | |
1289 | mock_replayer.shut_down(&shutdown_ctx); | |
1290 | ASSERT_EQ(-EINVAL, shutdown_ctx.wait()); | |
1291 | } | |
1292 | ||
1293 | TEST_F(TestMockImageReplayerSnapshotReplayer, LoadImageMetaError) { | |
1294 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1295 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1296 | ||
1297 | MockThreads mock_threads(m_threads); | |
1298 | expect_work_queue_repeatedly(mock_threads); | |
1299 | ||
1300 | MockReplayerListener mock_replayer_listener; | |
1301 | expect_notification(mock_threads, mock_replayer_listener); | |
1302 | ||
1303 | InSequence seq; | |
1304 | ||
1305 | MockInstanceWatcher mock_instance_watcher; | |
1306 | MockImageMeta mock_image_meta; | |
1307 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1308 | mock_remote_image_ctx, | |
1309 | mock_image_meta); | |
1310 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1311 | "local mirror uuid", &m_pool_meta_cache, | |
1312 | &mock_state_builder, &mock_replayer_listener}; | |
1313 | m_pool_meta_cache.set_remote_pool_meta( | |
1314 | m_remote_io_ctx.get_id(), | |
1315 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1316 | ||
1317 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1318 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1319 | mock_local_image_ctx, | |
1320 | mock_remote_image_ctx, | |
1321 | mock_replayer_listener, | |
1322 | mock_image_meta, | |
1323 | &update_watch_ctx)); | |
1324 | ||
1325 | // sync | |
1326 | expect_load_image_meta(mock_image_meta, false, -EINVAL); | |
1327 | ||
1328 | // wake-up replayer | |
1329 | update_watch_ctx->handle_notify(); | |
1330 | ||
1331 | // wait for sync to complete and expect replay complete | |
1332 | ASSERT_EQ(0, wait_for_notification(1)); | |
1333 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1334 | ASSERT_EQ(-EINVAL, mock_replayer.get_error_code()); | |
1335 | ||
1336 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1337 | mock_local_image_ctx, | |
1338 | mock_remote_image_ctx)); | |
1339 | } | |
1340 | ||
1341 | TEST_F(TestMockImageReplayerSnapshotReplayer, RefreshLocalImageError) { | |
1342 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1343 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1344 | ||
1345 | MockThreads mock_threads(m_threads); | |
1346 | expect_work_queue_repeatedly(mock_threads); | |
1347 | ||
1348 | MockReplayerListener mock_replayer_listener; | |
1349 | expect_notification(mock_threads, mock_replayer_listener); | |
1350 | ||
1351 | InSequence seq; | |
1352 | ||
1353 | MockInstanceWatcher mock_instance_watcher; | |
1354 | MockImageMeta mock_image_meta; | |
1355 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1356 | mock_remote_image_ctx, | |
1357 | mock_image_meta); | |
1358 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1359 | "local mirror uuid", &m_pool_meta_cache, | |
1360 | &mock_state_builder, &mock_replayer_listener}; | |
1361 | m_pool_meta_cache.set_remote_pool_meta( | |
1362 | m_remote_io_ctx.get_id(), | |
1363 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1364 | ||
1365 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1366 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1367 | mock_local_image_ctx, | |
1368 | mock_remote_image_ctx, | |
1369 | mock_replayer_listener, | |
1370 | mock_image_meta, | |
1371 | &update_watch_ctx)); | |
1372 | ||
1373 | // sync | |
1374 | expect_load_image_meta(mock_image_meta, false, 0); | |
1375 | expect_is_refresh_required(mock_local_image_ctx, true); | |
1376 | expect_refresh(mock_local_image_ctx, {}, -EINVAL); | |
1377 | ||
1378 | // wake-up replayer | |
1379 | update_watch_ctx->handle_notify(); | |
1380 | ||
1381 | // wait for sync to complete and expect replay complete | |
1382 | ASSERT_EQ(0, wait_for_notification(1)); | |
1383 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1384 | ASSERT_EQ(-EINVAL, mock_replayer.get_error_code()); | |
1385 | ||
1386 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1387 | mock_local_image_ctx, | |
1388 | mock_remote_image_ctx)); | |
1389 | } | |
1390 | ||
1391 | TEST_F(TestMockImageReplayerSnapshotReplayer, RefreshRemoteImageError) { | |
1392 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1393 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1394 | ||
1395 | MockThreads mock_threads(m_threads); | |
1396 | expect_work_queue_repeatedly(mock_threads); | |
1397 | ||
1398 | MockReplayerListener mock_replayer_listener; | |
1399 | expect_notification(mock_threads, mock_replayer_listener); | |
1400 | ||
1401 | InSequence seq; | |
1402 | ||
1403 | MockInstanceWatcher mock_instance_watcher; | |
1404 | MockImageMeta mock_image_meta; | |
1405 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1406 | mock_remote_image_ctx, | |
1407 | mock_image_meta); | |
1408 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1409 | "local mirror uuid", &m_pool_meta_cache, | |
1410 | &mock_state_builder, &mock_replayer_listener}; | |
1411 | m_pool_meta_cache.set_remote_pool_meta( | |
1412 | m_remote_io_ctx.get_id(), | |
1413 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1414 | ||
1415 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1416 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1417 | mock_local_image_ctx, | |
1418 | mock_remote_image_ctx, | |
1419 | mock_replayer_listener, | |
1420 | mock_image_meta, | |
1421 | &update_watch_ctx)); | |
1422 | ||
1423 | // sync | |
1424 | expect_load_image_meta(mock_image_meta, false, 0); | |
1425 | expect_is_refresh_required(mock_local_image_ctx, false); | |
1426 | expect_is_refresh_required(mock_remote_image_ctx, true); | |
1427 | expect_refresh(mock_remote_image_ctx, {}, -EINVAL); | |
1428 | ||
1429 | // wake-up replayer | |
1430 | update_watch_ctx->handle_notify(); | |
1431 | ||
1432 | // wait for sync to complete and expect replay complete | |
1433 | ASSERT_EQ(0, wait_for_notification(1)); | |
1434 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1435 | ASSERT_EQ(-EINVAL, mock_replayer.get_error_code()); | |
1436 | ||
1437 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1438 | mock_local_image_ctx, | |
1439 | mock_remote_image_ctx)); | |
1440 | } | |
1441 | ||
1442 | TEST_F(TestMockImageReplayerSnapshotReplayer, CopySnapshotsError) { | |
1443 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1444 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1445 | ||
1446 | MockThreads mock_threads(m_threads); | |
1447 | expect_work_queue_repeatedly(mock_threads); | |
1448 | ||
1449 | MockReplayerListener mock_replayer_listener; | |
1450 | expect_notification(mock_threads, mock_replayer_listener); | |
1451 | ||
1452 | InSequence seq; | |
1453 | ||
1454 | MockInstanceWatcher mock_instance_watcher; | |
1455 | MockImageMeta mock_image_meta; | |
1456 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1457 | mock_remote_image_ctx, | |
1458 | mock_image_meta); | |
1459 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1460 | "local mirror uuid", &m_pool_meta_cache, | |
1461 | &mock_state_builder, &mock_replayer_listener}; | |
1462 | m_pool_meta_cache.set_remote_pool_meta( | |
1463 | m_remote_io_ctx.get_id(), | |
1464 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1465 | ||
1466 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1467 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1468 | mock_local_image_ctx, | |
1469 | mock_remote_image_ctx, | |
1470 | mock_replayer_listener, | |
1471 | mock_image_meta, | |
1472 | &update_watch_ctx)); | |
1473 | ||
1474 | // inject snapshot | |
1475 | mock_remote_image_ctx.snap_info = { | |
1476 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
1477 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, "", | |
1911f103 | 1478 | CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
1479 | 0, {}, 0, 0, {}}}}; |
1480 | ||
1481 | // sync snap1 | |
1482 | expect_load_image_meta(mock_image_meta, false, 0); | |
1483 | expect_is_refresh_required(mock_local_image_ctx, false); | |
1484 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
1485 | MockSnapshotCopyRequest mock_snapshot_copy_request; | |
1486 | expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, | |
1487 | -EINVAL); | |
1488 | ||
1489 | // wake-up replayer | |
1490 | update_watch_ctx->handle_notify(); | |
1491 | ||
1492 | // wait for sync to complete and expect replay complete | |
1493 | ASSERT_EQ(0, wait_for_notification(1)); | |
1494 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1495 | ASSERT_EQ(-EINVAL, mock_replayer.get_error_code()); | |
1496 | ||
1497 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1498 | mock_local_image_ctx, | |
1499 | mock_remote_image_ctx)); | |
1500 | } | |
1501 | ||
1502 | TEST_F(TestMockImageReplayerSnapshotReplayer, GetImageStateError) { | |
1503 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1504 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1505 | ||
1506 | MockThreads mock_threads(m_threads); | |
1507 | expect_work_queue_repeatedly(mock_threads); | |
1508 | ||
1509 | MockReplayerListener mock_replayer_listener; | |
1510 | expect_notification(mock_threads, mock_replayer_listener); | |
1511 | ||
1512 | InSequence seq; | |
1513 | ||
1514 | MockInstanceWatcher mock_instance_watcher; | |
1515 | MockImageMeta mock_image_meta; | |
1516 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1517 | mock_remote_image_ctx, | |
1518 | mock_image_meta); | |
1519 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1520 | "local mirror uuid", &m_pool_meta_cache, | |
1521 | &mock_state_builder, &mock_replayer_listener}; | |
1522 | m_pool_meta_cache.set_remote_pool_meta( | |
1523 | m_remote_io_ctx.get_id(), | |
1524 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1525 | ||
1526 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1527 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1528 | mock_local_image_ctx, | |
1529 | mock_remote_image_ctx, | |
1530 | mock_replayer_listener, | |
1531 | mock_image_meta, | |
1532 | &update_watch_ctx)); | |
1533 | ||
1534 | // inject snapshot | |
1535 | mock_remote_image_ctx.snap_info = { | |
1536 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
1537 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, "", | |
1911f103 | 1538 | CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
1539 | 0, {}, 0, 0, {}}}}; |
1540 | ||
1541 | // sync snap1 | |
1542 | expect_load_image_meta(mock_image_meta, false, 0); | |
1543 | expect_is_refresh_required(mock_local_image_ctx, false); | |
1544 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
1545 | MockSnapshotCopyRequest mock_snapshot_copy_request; | |
1546 | expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, | |
1547 | 0); | |
1548 | MockGetImageStateRequest mock_get_image_state_request; | |
1549 | expect_get_image_state(mock_get_image_state_request, 1, -EINVAL); | |
1550 | ||
1551 | // wake-up replayer | |
1552 | update_watch_ctx->handle_notify(); | |
1553 | ||
1554 | // wait for sync to complete and expect replay complete | |
1555 | ASSERT_EQ(0, wait_for_notification(1)); | |
1556 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1557 | ASSERT_EQ(-EINVAL, mock_replayer.get_error_code()); | |
1558 | ||
1559 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1560 | mock_local_image_ctx, | |
1561 | mock_remote_image_ctx)); | |
1562 | } | |
1563 | ||
1564 | TEST_F(TestMockImageReplayerSnapshotReplayer, CreateNonPrimarySnapshotError) { | |
1565 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1566 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1567 | ||
1568 | MockThreads mock_threads(m_threads); | |
1569 | expect_work_queue_repeatedly(mock_threads); | |
1570 | ||
1571 | MockReplayerListener mock_replayer_listener; | |
1572 | expect_notification(mock_threads, mock_replayer_listener); | |
1573 | ||
1574 | InSequence seq; | |
1575 | ||
1576 | MockInstanceWatcher mock_instance_watcher; | |
1577 | MockImageMeta mock_image_meta; | |
1578 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1579 | mock_remote_image_ctx, | |
1580 | mock_image_meta); | |
1581 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1582 | "local mirror uuid", &m_pool_meta_cache, | |
1583 | &mock_state_builder, &mock_replayer_listener}; | |
1584 | m_pool_meta_cache.set_remote_pool_meta( | |
1585 | m_remote_io_ctx.get_id(), | |
1586 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1587 | ||
1588 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1589 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1590 | mock_local_image_ctx, | |
1591 | mock_remote_image_ctx, | |
1592 | mock_replayer_listener, | |
1593 | mock_image_meta, | |
1594 | &update_watch_ctx)); | |
1595 | ||
1596 | // inject snapshot | |
1597 | mock_remote_image_ctx.snap_info = { | |
1598 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
1599 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, "", | |
1911f103 | 1600 | CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
1601 | 0, {}, 0, 0, {}}}}; |
1602 | ||
1603 | // sync snap1 | |
1604 | expect_load_image_meta(mock_image_meta, false, 0); | |
1605 | expect_is_refresh_required(mock_local_image_ctx, false); | |
1606 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
1607 | MockSnapshotCopyRequest mock_snapshot_copy_request; | |
1608 | expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, | |
1609 | 0); | |
1610 | MockGetImageStateRequest mock_get_image_state_request; | |
1611 | expect_get_image_state(mock_get_image_state_request, 1, 0); | |
1612 | MockCreateNonPrimaryRequest mock_create_non_primary_request; | |
1613 | expect_create_non_primary_request(mock_create_non_primary_request, | |
1614 | false, "remote mirror uuid", 1, | |
1615 | {{1, CEPH_NOSNAP}}, 11, -EINVAL); | |
1616 | ||
1617 | // wake-up replayer | |
1618 | update_watch_ctx->handle_notify(); | |
1619 | ||
1620 | // wait for sync to complete and expect replay complete | |
1621 | ASSERT_EQ(0, wait_for_notification(1)); | |
1622 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1623 | ASSERT_EQ(-EINVAL, mock_replayer.get_error_code()); | |
1624 | ||
1625 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1626 | mock_local_image_ctx, | |
1627 | mock_remote_image_ctx)); | |
1628 | } | |
1629 | ||
1630 | TEST_F(TestMockImageReplayerSnapshotReplayer, RequestSyncError) { | |
1631 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1632 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1633 | ||
1634 | MockThreads mock_threads(m_threads); | |
1635 | expect_work_queue_repeatedly(mock_threads); | |
1636 | ||
1637 | MockReplayerListener mock_replayer_listener; | |
1638 | expect_notification(mock_threads, mock_replayer_listener); | |
1639 | ||
1640 | InSequence seq; | |
1641 | ||
1642 | MockInstanceWatcher mock_instance_watcher; | |
1643 | MockImageMeta mock_image_meta; | |
1644 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1645 | mock_remote_image_ctx, | |
1646 | mock_image_meta); | |
1647 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1648 | "local mirror uuid", &m_pool_meta_cache, | |
1649 | &mock_state_builder, &mock_replayer_listener}; | |
1650 | m_pool_meta_cache.set_remote_pool_meta( | |
1651 | m_remote_io_ctx.get_id(), | |
1652 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1653 | ||
1654 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1655 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1656 | mock_local_image_ctx, | |
1657 | mock_remote_image_ctx, | |
1658 | mock_replayer_listener, | |
1659 | mock_image_meta, | |
1660 | &update_watch_ctx)); | |
1661 | ||
1662 | // inject snapshot | |
1663 | mock_remote_image_ctx.snap_info = { | |
1664 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
1665 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, "", | |
1911f103 | 1666 | CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
1667 | 0, {}, 0, 0, {}}}}; |
1668 | ||
1669 | // sync snap1 | |
1670 | expect_load_image_meta(mock_image_meta, false, 0); | |
1671 | expect_is_refresh_required(mock_local_image_ctx, false); | |
1672 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
1673 | MockSnapshotCopyRequest mock_snapshot_copy_request; | |
1674 | expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, | |
1675 | 0); | |
1676 | MockGetImageStateRequest mock_get_image_state_request; | |
1677 | expect_get_image_state(mock_get_image_state_request, 1, 0); | |
1678 | MockCreateNonPrimaryRequest mock_create_non_primary_request; | |
1679 | expect_create_non_primary_request(mock_create_non_primary_request, | |
1680 | false, "remote mirror uuid", 1, | |
1681 | {{1, CEPH_NOSNAP}}, 11, 0); | |
1682 | expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, | |
1683 | -ECANCELED); | |
1684 | ||
1685 | // wake-up replayer | |
1686 | update_watch_ctx->handle_notify(); | |
1687 | ||
1688 | // wait for sync to complete and expect replay complete | |
1689 | ASSERT_EQ(0, wait_for_notification(1)); | |
1690 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1691 | ASSERT_EQ(-ECANCELED, mock_replayer.get_error_code()); | |
1692 | ||
1693 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1694 | mock_local_image_ctx, | |
1695 | mock_remote_image_ctx)); | |
1696 | ||
1697 | } | |
1698 | ||
1699 | TEST_F(TestMockImageReplayerSnapshotReplayer, CopyImageError) { | |
1700 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1701 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1702 | ||
1703 | MockThreads mock_threads(m_threads); | |
1704 | expect_work_queue_repeatedly(mock_threads); | |
1705 | ||
1706 | MockReplayerListener mock_replayer_listener; | |
1707 | expect_notification(mock_threads, mock_replayer_listener); | |
1708 | ||
1709 | InSequence seq; | |
1710 | ||
1711 | MockInstanceWatcher mock_instance_watcher; | |
1712 | MockImageMeta mock_image_meta; | |
1713 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1714 | mock_remote_image_ctx, | |
1715 | mock_image_meta); | |
1716 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1717 | "local mirror uuid", &m_pool_meta_cache, | |
1718 | &mock_state_builder, &mock_replayer_listener}; | |
1719 | m_pool_meta_cache.set_remote_pool_meta( | |
1720 | m_remote_io_ctx.get_id(), | |
1721 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1722 | ||
1723 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1724 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1725 | mock_local_image_ctx, | |
1726 | mock_remote_image_ctx, | |
1727 | mock_replayer_listener, | |
1728 | mock_image_meta, | |
1729 | &update_watch_ctx)); | |
1730 | ||
1731 | // inject snapshot | |
1732 | mock_remote_image_ctx.snap_info = { | |
1733 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
1734 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, "", | |
1911f103 | 1735 | CEPH_NOSNAP,true, 0, {}}, |
9f95a23c TL |
1736 | 0, {}, 0, 0, {}}}}; |
1737 | ||
1738 | // sync snap1 | |
1739 | expect_load_image_meta(mock_image_meta, false, 0); | |
1740 | expect_is_refresh_required(mock_local_image_ctx, false); | |
1741 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
1742 | MockSnapshotCopyRequest mock_snapshot_copy_request; | |
1743 | expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, | |
1744 | 0); | |
1745 | MockGetImageStateRequest mock_get_image_state_request; | |
1746 | expect_get_image_state(mock_get_image_state_request, 1, 0); | |
1747 | MockCreateNonPrimaryRequest mock_create_non_primary_request; | |
1748 | expect_create_non_primary_request(mock_create_non_primary_request, | |
1749 | false, "remote mirror uuid", 1, | |
1750 | {{1, CEPH_NOSNAP}}, 11, 0); | |
1751 | expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); | |
1752 | MockImageCopyRequest mock_image_copy_request; | |
1753 | expect_image_copy(mock_image_copy_request, 0, 1, 0, {}, | |
1754 | {{1, CEPH_NOSNAP}}, -EINVAL); | |
1911f103 | 1755 | expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); |
9f95a23c TL |
1756 | |
1757 | // wake-up replayer | |
1758 | update_watch_ctx->handle_notify(); | |
1759 | ||
1760 | // wait for sync to complete and expect replay complete | |
1761 | ASSERT_EQ(0, wait_for_notification(1)); | |
1762 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1763 | ASSERT_EQ(-EINVAL, mock_replayer.get_error_code()); | |
1764 | ||
1765 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1766 | mock_local_image_ctx, | |
1767 | mock_remote_image_ctx)); | |
1768 | } | |
1769 | ||
1770 | TEST_F(TestMockImageReplayerSnapshotReplayer, UpdateNonPrimarySnapshotError) { | |
1771 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1772 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1773 | ||
1774 | MockThreads mock_threads(m_threads); | |
1775 | expect_work_queue_repeatedly(mock_threads); | |
1776 | ||
1777 | MockReplayerListener mock_replayer_listener; | |
1778 | expect_notification(mock_threads, mock_replayer_listener); | |
1779 | ||
1780 | InSequence seq; | |
1781 | ||
1782 | MockInstanceWatcher mock_instance_watcher; | |
1783 | MockImageMeta mock_image_meta; | |
1784 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1785 | mock_remote_image_ctx, | |
1786 | mock_image_meta); | |
1787 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1788 | "local mirror uuid", &m_pool_meta_cache, | |
1789 | &mock_state_builder, &mock_replayer_listener}; | |
1790 | m_pool_meta_cache.set_remote_pool_meta( | |
1791 | m_remote_io_ctx.get_id(), | |
1792 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1793 | ||
1794 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1795 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1796 | mock_local_image_ctx, | |
1797 | mock_remote_image_ctx, | |
1798 | mock_replayer_listener, | |
1799 | mock_image_meta, | |
1800 | &update_watch_ctx)); | |
1801 | ||
1802 | // inject snapshot | |
1803 | mock_remote_image_ctx.snap_info = { | |
1804 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
1805 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, "", | |
1911f103 | 1806 | CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
1807 | 0, {}, 0, 0, {}}}}; |
1808 | ||
1809 | // sync snap1 | |
1810 | expect_load_image_meta(mock_image_meta, false, 0); | |
1811 | expect_is_refresh_required(mock_local_image_ctx, false); | |
1812 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
1813 | MockSnapshotCopyRequest mock_snapshot_copy_request; | |
1814 | expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, | |
1815 | 0); | |
1816 | MockGetImageStateRequest mock_get_image_state_request; | |
1817 | expect_get_image_state(mock_get_image_state_request, 1, 0); | |
1818 | MockCreateNonPrimaryRequest mock_create_non_primary_request; | |
1819 | expect_create_non_primary_request(mock_create_non_primary_request, | |
1820 | false, "remote mirror uuid", 1, | |
1821 | {{1, CEPH_NOSNAP}}, 11, 0); | |
1822 | expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); | |
1823 | MockImageCopyRequest mock_image_copy_request; | |
1824 | expect_image_copy(mock_image_copy_request, 0, 1, 0, {}, | |
1825 | {{1, CEPH_NOSNAP}}, 0); | |
1826 | MockApplyImageStateRequest mock_apply_state_request; | |
1827 | expect_apply_image_state(mock_apply_state_request, 0); | |
1828 | expect_mirror_image_snapshot_set_copy_progress( | |
1829 | mock_local_image_ctx, 11, true, 0, -EINVAL); | |
1911f103 | 1830 | expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); |
9f95a23c TL |
1831 | |
1832 | // wake-up replayer | |
1833 | update_watch_ctx->handle_notify(); | |
1834 | ||
1835 | // wait for sync to complete and expect replay complete | |
1836 | ASSERT_EQ(0, wait_for_notification(1)); | |
1837 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1838 | ASSERT_EQ(-EINVAL, mock_replayer.get_error_code()); | |
1839 | ||
1840 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1841 | mock_local_image_ctx, | |
1842 | mock_remote_image_ctx)); | |
1843 | } | |
1844 | ||
1845 | TEST_F(TestMockImageReplayerSnapshotReplayer, UnlinkPeerError) { | |
1846 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1847 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1848 | ||
1849 | MockThreads mock_threads(m_threads); | |
1850 | expect_work_queue_repeatedly(mock_threads); | |
1851 | ||
1852 | MockReplayerListener mock_replayer_listener; | |
1853 | expect_notification(mock_threads, mock_replayer_listener); | |
1854 | ||
1855 | InSequence seq; | |
1856 | ||
1857 | MockInstanceWatcher mock_instance_watcher; | |
1858 | MockImageMeta mock_image_meta; | |
1859 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1860 | mock_remote_image_ctx, | |
1861 | mock_image_meta); | |
1862 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1863 | "local mirror uuid", &m_pool_meta_cache, | |
1864 | &mock_state_builder, &mock_replayer_listener}; | |
1865 | m_pool_meta_cache.set_remote_pool_meta( | |
1866 | m_remote_io_ctx.get_id(), | |
1867 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1868 | ||
1869 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1870 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1871 | mock_local_image_ctx, | |
1872 | mock_remote_image_ctx, | |
1873 | mock_replayer_listener, | |
1874 | mock_image_meta, | |
1875 | &update_watch_ctx)); | |
1876 | ||
1877 | // inject snapshot | |
1878 | mock_remote_image_ctx.snap_info = { | |
1879 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
1880 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, "", | |
1911f103 | 1881 | CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
1882 | 0, {}, 0, 0, {}}}, |
1883 | {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ | |
1884 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, | |
1911f103 | 1885 | "", CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
1886 | 0, {}, 0, 0, {}}}}; |
1887 | mock_local_image_ctx.snap_info = { | |
1888 | {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
1889 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", | |
1890 | 1, true, 0, {}}, | |
1891 | 0, {}, 0, 0, {}}}}; | |
1892 | ||
1893 | // sync snap2 | |
1894 | expect_load_image_meta(mock_image_meta, false, 0); | |
1895 | expect_is_refresh_required(mock_local_image_ctx, false); | |
1896 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
1897 | MockSnapshotCopyRequest mock_snapshot_copy_request; | |
1898 | expect_snapshot_copy(mock_snapshot_copy_request, 1, 2, 11, {{2, CEPH_NOSNAP}}, | |
1899 | 0); | |
1900 | MockGetImageStateRequest mock_get_image_state_request; | |
1901 | expect_get_image_state(mock_get_image_state_request, 2, 0); | |
1902 | MockCreateNonPrimaryRequest mock_create_non_primary_request; | |
1903 | expect_create_non_primary_request(mock_create_non_primary_request, | |
1904 | false, "remote mirror uuid", 2, | |
1905 | {{2, CEPH_NOSNAP}}, 12, 0); | |
1906 | expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); | |
1907 | MockImageCopyRequest mock_image_copy_request; | |
1908 | expect_image_copy(mock_image_copy_request, 1, 2, 11, {}, | |
1909 | {{2, CEPH_NOSNAP}}, 0); | |
1910 | MockApplyImageStateRequest mock_apply_state_request; | |
1911 | expect_apply_image_state(mock_apply_state_request, 0); | |
1912 | expect_mirror_image_snapshot_set_copy_progress( | |
1913 | mock_local_image_ctx, 12, true, 0, 0); | |
1914 | expect_notify_update(mock_local_image_ctx); | |
1915 | MockUnlinkPeerRequest mock_unlink_peer_request; | |
1916 | expect_unlink_peer(mock_unlink_peer_request, 1, "remote mirror peer uuid", | |
1917 | -EINVAL); | |
1918 | expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); | |
1919 | ||
1920 | // wake-up replayer | |
1921 | update_watch_ctx->handle_notify(); | |
1922 | ||
1923 | // wait for sync to complete and expect replay complete | |
1924 | ASSERT_EQ(0, wait_for_notification(1)); | |
1925 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1926 | ASSERT_EQ(-EINVAL, mock_replayer.get_error_code()); | |
1927 | ||
1928 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1929 | mock_local_image_ctx, | |
1930 | mock_remote_image_ctx)); | |
1931 | } | |
1932 | ||
1933 | TEST_F(TestMockImageReplayerSnapshotReplayer, SplitBrain) { | |
1934 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1935 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1936 | ||
1937 | MockThreads mock_threads(m_threads); | |
1938 | expect_work_queue_repeatedly(mock_threads); | |
1939 | ||
1940 | MockReplayerListener mock_replayer_listener; | |
1941 | expect_notification(mock_threads, mock_replayer_listener); | |
1942 | ||
1943 | InSequence seq; | |
1944 | ||
1945 | MockInstanceWatcher mock_instance_watcher; | |
1946 | MockImageMeta mock_image_meta; | |
1947 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
1948 | mock_remote_image_ctx, | |
1949 | mock_image_meta); | |
1950 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
1951 | "local mirror uuid", &m_pool_meta_cache, | |
1952 | &mock_state_builder, &mock_replayer_listener}; | |
1953 | m_pool_meta_cache.set_remote_pool_meta( | |
1954 | m_remote_io_ctx.get_id(), | |
1955 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
1956 | ||
1957 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
1958 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
1959 | mock_local_image_ctx, | |
1960 | mock_remote_image_ctx, | |
1961 | mock_replayer_listener, | |
1962 | mock_image_meta, | |
1963 | &update_watch_ctx)); | |
1964 | ||
1965 | // inject a primary demote to local image | |
1966 | mock_remote_image_ctx.snap_info = { | |
1967 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
1968 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, | |
1911f103 | 1969 | "", CEPH_NOSNAP, true, 0, {}}, |
9f95a23c TL |
1970 | 0, {}, 0, 0, {}}}}; |
1971 | mock_local_image_ctx.snap_info = { | |
1972 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
1911f103 TL |
1973 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, {}, "", CEPH_NOSNAP, |
1974 | true, 0, {}}, | |
9f95a23c TL |
1975 | 0, {}, 0, 0, {}}}}; |
1976 | ||
1977 | // detect split-brain | |
1978 | expect_load_image_meta(mock_image_meta, false, 0); | |
1979 | expect_is_refresh_required(mock_local_image_ctx, false); | |
1980 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
1981 | ||
1982 | // wake-up replayer | |
1983 | update_watch_ctx->handle_notify(); | |
1984 | ||
1985 | // wait for sync to complete and expect replay complete | |
1986 | ASSERT_EQ(0, wait_for_notification(1)); | |
1987 | ASSERT_FALSE(mock_replayer.is_replaying()); | |
1988 | ASSERT_EQ(-EEXIST, mock_replayer.get_error_code()); | |
1989 | ASSERT_EQ(std::string{"split-brain"}, mock_replayer.get_error_description()); | |
1990 | ||
1991 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
1992 | mock_local_image_ctx, | |
1993 | mock_remote_image_ctx)); | |
1994 | } | |
1995 | ||
1911f103 TL |
1996 | TEST_F(TestMockImageReplayerSnapshotReplayer, RemoteFailover) { |
1997 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
1998 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
1999 | ||
2000 | MockThreads mock_threads(m_threads); | |
2001 | expect_work_queue_repeatedly(mock_threads); | |
2002 | ||
2003 | MockReplayerListener mock_replayer_listener; | |
2004 | expect_notification(mock_threads, mock_replayer_listener); | |
2005 | ||
2006 | InSequence seq; | |
2007 | ||
2008 | MockInstanceWatcher mock_instance_watcher; | |
2009 | MockImageMeta mock_image_meta; | |
2010 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
2011 | mock_remote_image_ctx, | |
2012 | mock_image_meta); | |
2013 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
2014 | "local mirror uuid", &m_pool_meta_cache, | |
2015 | &mock_state_builder, &mock_replayer_listener}; | |
2016 | m_pool_meta_cache.set_remote_pool_meta( | |
2017 | m_remote_io_ctx.get_id(), | |
2018 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
2019 | ||
2020 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
2021 | ASSERT_EQ(0, init_entry_replayer(mock_replayer, mock_threads, | |
2022 | mock_local_image_ctx, | |
2023 | mock_remote_image_ctx, | |
2024 | mock_replayer_listener, | |
2025 | mock_image_meta, | |
2026 | &update_watch_ctx)); | |
2027 | ||
2028 | // inject a primary demote to local image | |
2029 | mock_remote_image_ctx.snap_info = { | |
2030 | {1U, librbd::SnapInfo{"snap1", cls::rbd::UserSnapshotNamespace{}, | |
2031 | 0, {}, 0, 0, {}}}, | |
2032 | {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ | |
2033 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED, | |
2034 | {"remote mirror peer uuid"}, "local mirror uuid", 12U, true, 0, {}}, | |
2035 | 0, {}, 0, 0, {}}}, | |
2036 | {3U, librbd::SnapInfo{"snap3", cls::rbd::MirrorSnapshotNamespace{ | |
2037 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, | |
2038 | "", CEPH_NOSNAP, true, 0, {}}, | |
2039 | 0, {}, 0, 0, {}}}}; | |
2040 | mock_local_image_ctx.snap_ids = { | |
2041 | {{cls::rbd::UserSnapshotNamespace{}, "snap1"}, 11}, | |
2042 | {{cls::rbd::MirrorSnapshotNamespace{}, "snap2"}, 12}}; | |
2043 | mock_local_image_ctx.snap_info = { | |
2044 | {11U, librbd::SnapInfo{"snap1", cls::rbd::UserSnapshotNamespace{}, | |
2045 | 0, {}, 0, 0, {}}}, | |
2046 | {12U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ | |
2047 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, {}, "", CEPH_NOSNAP, | |
2048 | true, 0, {}}, | |
2049 | 0, {}, 0, 0, {}}}}; | |
2050 | ||
2051 | // attach to promoted remote image | |
2052 | expect_load_image_meta(mock_image_meta, false, 0); | |
2053 | expect_is_refresh_required(mock_local_image_ctx, false); | |
2054 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
2055 | MockSnapshotCopyRequest mock_snapshot_copy_request; | |
2056 | expect_snapshot_copy(mock_snapshot_copy_request, 2, 3, 12, | |
2057 | {{2, 12}, {3, CEPH_NOSNAP}}, 0); | |
2058 | MockGetImageStateRequest mock_get_image_state_request; | |
2059 | expect_get_image_state(mock_get_image_state_request, 3, 0); | |
2060 | MockCreateNonPrimaryRequest mock_create_non_primary_request; | |
2061 | expect_create_non_primary_request(mock_create_non_primary_request, | |
2062 | false, "remote mirror uuid", 3, | |
2063 | {{1, 11}, {2, 12}, {3, CEPH_NOSNAP}}, 13, | |
2064 | 0); | |
2065 | expect_notify_sync_request(mock_instance_watcher, mock_local_image_ctx.id, 0); | |
2066 | MockImageCopyRequest mock_image_copy_request; | |
2067 | expect_image_copy(mock_image_copy_request, 2, 3, 12, {}, | |
2068 | {{1, 11}, {2, 12}, {3, CEPH_NOSNAP}}, 0); | |
2069 | MockApplyImageStateRequest mock_apply_state_request; | |
2070 | expect_apply_image_state(mock_apply_state_request, 0); | |
2071 | expect_mirror_image_snapshot_set_copy_progress( | |
2072 | mock_local_image_ctx, 13, true, 0, 0); | |
2073 | expect_notify_update(mock_local_image_ctx); | |
2074 | MockUnlinkPeerRequest mock_unlink_peer_request; | |
2075 | expect_unlink_peer(mock_unlink_peer_request, 2, "remote mirror peer uuid", 0); | |
2076 | expect_notify_sync_complete(mock_instance_watcher, mock_local_image_ctx.id); | |
2077 | ||
2078 | // idle | |
2079 | expect_load_image_meta(mock_image_meta, false, 0); | |
2080 | expect_is_refresh_required(mock_local_image_ctx, true); | |
2081 | expect_refresh( | |
2082 | mock_local_image_ctx, { | |
2083 | {11U, librbd::SnapInfo{"snap1", cls::rbd::UserSnapshotNamespace{}, | |
2084 | 0, {}, 0, 0, {}}}, | |
2085 | {12U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ | |
2086 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, {}, "", CEPH_NOSNAP, | |
2087 | true, 0, {}}, | |
2088 | 0, {}, 0, 0, {}}}, | |
2089 | {13U, librbd::SnapInfo{"snap3", cls::rbd::MirrorSnapshotNamespace{ | |
2090 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, | |
2091 | "remote mirror uuid", 3, true, 0, | |
2092 | {{1, 11}, {2, 12}, {3, CEPH_NOSNAP}}}, | |
2093 | 0, {}, 0, 0, {}}}, | |
2094 | }, 0); | |
2095 | expect_is_refresh_required(mock_remote_image_ctx, true); | |
2096 | expect_refresh( | |
2097 | mock_remote_image_ctx, { | |
2098 | {1U, librbd::SnapInfo{"snap1", cls::rbd::UserSnapshotNamespace{}, | |
2099 | 0, {}, 0, 0, {}}}, | |
2100 | {2U, librbd::SnapInfo{"snap2", cls::rbd::MirrorSnapshotNamespace{ | |
2101 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED, | |
2102 | {"remote mirror peer uuid"}, "local mirror uuid", 12U, true, 0, {}}, | |
2103 | 0, {}, 0, 0, {}}}, | |
2104 | {3U, librbd::SnapInfo{"snap3", cls::rbd::MirrorSnapshotNamespace{ | |
2105 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {}, "", CEPH_NOSNAP, true, 0, | |
2106 | {}}, | |
2107 | 0, {}, 0, 0, {}}} | |
2108 | }, 0); | |
2109 | ||
2110 | // wake-up replayer | |
2111 | update_watch_ctx->handle_notify(); | |
2112 | ||
2113 | // wait for sync to complete and expect replay complete | |
2114 | ASSERT_EQ(0, wait_for_notification(2)); | |
2115 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
2116 | mock_local_image_ctx, | |
2117 | mock_remote_image_ctx)); | |
2118 | } | |
2119 | ||
2120 | TEST_F(TestMockImageReplayerSnapshotReplayer, UnlinkRemoteSnapshot) { | |
2121 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
2122 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
2123 | ||
2124 | // it should attempt to unlink from remote snap1 since we don't need it | |
2125 | // anymore | |
2126 | mock_local_image_ctx.snap_info = { | |
2127 | {14U, librbd::SnapInfo{"snap4", cls::rbd::MirrorSnapshotNamespace{ | |
2128 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", | |
2129 | 4, true, 0, {}}, | |
2130 | 0, {}, 0, 0, {}}}}; | |
2131 | mock_remote_image_ctx.snap_info = { | |
2132 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
2133 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, | |
2134 | "", CEPH_NOSNAP, true, 0, {}}, | |
2135 | 0, {}, 0, 0, {}}}, | |
2136 | {4U, librbd::SnapInfo{"snap4", cls::rbd::MirrorSnapshotNamespace{ | |
2137 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, | |
2138 | "", CEPH_NOSNAP, true, 0, {}}, | |
2139 | 0, {}, 0, 0, {}}}}; | |
2140 | ||
2141 | MockThreads mock_threads(m_threads); | |
2142 | expect_work_queue_repeatedly(mock_threads); | |
2143 | ||
2144 | MockReplayerListener mock_replayer_listener; | |
2145 | expect_notification(mock_threads, mock_replayer_listener); | |
2146 | ||
2147 | InSequence seq; | |
2148 | ||
2149 | MockInstanceWatcher mock_instance_watcher; | |
2150 | MockImageMeta mock_image_meta; | |
2151 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
2152 | mock_remote_image_ctx, | |
2153 | mock_image_meta); | |
2154 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
2155 | "local mirror uuid", &m_pool_meta_cache, | |
2156 | &mock_state_builder, &mock_replayer_listener}; | |
2157 | m_pool_meta_cache.set_remote_pool_meta( | |
2158 | m_remote_io_ctx.get_id(), | |
2159 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
2160 | ||
2161 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
2162 | ||
2163 | // init | |
2164 | expect_register_update_watcher(mock_local_image_ctx, &update_watch_ctx, 123, | |
2165 | 0); | |
2166 | expect_register_update_watcher(mock_remote_image_ctx, &update_watch_ctx, 234, | |
2167 | 0); | |
2168 | ||
2169 | // unlink snap1 | |
2170 | expect_load_image_meta(mock_image_meta, false, 0); | |
2171 | expect_is_refresh_required(mock_local_image_ctx, false); | |
2172 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
2173 | MockUnlinkPeerRequest mock_unlink_peer_request; | |
2174 | expect_unlink_peer(mock_unlink_peer_request, 1, "remote mirror peer uuid", | |
2175 | 0); | |
2176 | ||
2177 | // idle | |
2178 | expect_load_image_meta(mock_image_meta, false, 0); | |
2179 | expect_is_refresh_required(mock_local_image_ctx, false); | |
2180 | expect_is_refresh_required(mock_remote_image_ctx, true); | |
2181 | expect_refresh( | |
2182 | mock_remote_image_ctx, { | |
2183 | {2U, librbd::SnapInfo{"snap2", cls::rbd::UserSnapshotNamespace{}, | |
2184 | 0, {}, 0, 0, {}}}, | |
2185 | {3U, librbd::SnapInfo{"snap3", cls::rbd::MirrorSnapshotNamespace{ | |
2186 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {""}, | |
2187 | "", CEPH_NOSNAP, true, 0, {}}, | |
2188 | 0, {}, 0, 0, {}}}, | |
2189 | {4U, librbd::SnapInfo{"snap4", cls::rbd::MirrorSnapshotNamespace{ | |
2190 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, | |
2191 | "", CEPH_NOSNAP, true, 0, {}}, | |
2192 | 0, {}, 0, 0, {}}} | |
2193 | }, 0); | |
2194 | ||
2195 | // fire init | |
2196 | C_SaferCond init_ctx; | |
2197 | mock_replayer.init(&init_ctx); | |
2198 | ASSERT_EQ(0, init_ctx.wait()); | |
2199 | ||
2200 | // wait for sync to complete | |
f6b5b4d7 | 2201 | ASSERT_EQ(0, wait_for_notification(3)); |
1911f103 TL |
2202 | |
2203 | // shut down | |
2204 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
2205 | mock_local_image_ctx, | |
2206 | mock_remote_image_ctx)); | |
2207 | } | |
2208 | ||
2209 | TEST_F(TestMockImageReplayerSnapshotReplayer, SkipImageSync) { | |
2210 | librbd::MockTestImageCtx mock_local_image_ctx{*m_local_image_ctx}; | |
2211 | librbd::MockTestImageCtx mock_remote_image_ctx{*m_remote_image_ctx}; | |
2212 | ||
2213 | mock_remote_image_ctx.snap_info = { | |
2214 | {1U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
2215 | cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"remote mirror peer uuid"}, | |
2216 | "", 0U, true, 0, {}}, | |
2217 | 0, {}, 0, 0, {}}}}; | |
2218 | ||
2219 | MockThreads mock_threads(m_threads); | |
2220 | expect_work_queue_repeatedly(mock_threads); | |
2221 | ||
2222 | MockReplayerListener mock_replayer_listener; | |
2223 | expect_notification(mock_threads, mock_replayer_listener); | |
2224 | ||
2225 | InSequence seq; | |
2226 | ||
2227 | MockInstanceWatcher mock_instance_watcher; | |
2228 | MockImageMeta mock_image_meta; | |
2229 | MockStateBuilder mock_state_builder(mock_local_image_ctx, | |
2230 | mock_remote_image_ctx, | |
2231 | mock_image_meta); | |
2232 | MockReplayer mock_replayer{&mock_threads, &mock_instance_watcher, | |
2233 | "local mirror uuid", &m_pool_meta_cache, | |
2234 | &mock_state_builder, &mock_replayer_listener}; | |
2235 | m_pool_meta_cache.set_remote_pool_meta( | |
2236 | m_remote_io_ctx.get_id(), | |
2237 | {"remote mirror uuid", "remote mirror peer uuid"}); | |
2238 | ||
2239 | librbd::UpdateWatchCtx* update_watch_ctx = nullptr; | |
2240 | ||
2241 | // init | |
2242 | expect_register_update_watcher(mock_local_image_ctx, &update_watch_ctx, 123, | |
2243 | 0); | |
2244 | expect_register_update_watcher(mock_remote_image_ctx, &update_watch_ctx, 234, | |
2245 | 0); | |
2246 | ||
2247 | // sync snap1 | |
2248 | expect_load_image_meta(mock_image_meta, false, 0); | |
2249 | expect_is_refresh_required(mock_local_image_ctx, false); | |
2250 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
2251 | MockSnapshotCopyRequest mock_snapshot_copy_request; | |
2252 | expect_snapshot_copy(mock_snapshot_copy_request, 0, 1, 0, {{1, CEPH_NOSNAP}}, | |
2253 | 0); | |
2254 | MockGetImageStateRequest mock_get_image_state_request; | |
2255 | expect_get_image_state(mock_get_image_state_request, 1, 0); | |
2256 | MockCreateNonPrimaryRequest mock_create_non_primary_request; | |
2257 | expect_create_non_primary_request(mock_create_non_primary_request, | |
2258 | false, "remote mirror uuid", 1, | |
2259 | {{1, CEPH_NOSNAP}}, 11, 0); | |
2260 | MockApplyImageStateRequest mock_apply_state_request; | |
2261 | expect_apply_image_state(mock_apply_state_request, 0); | |
2262 | expect_mirror_image_snapshot_set_copy_progress( | |
2263 | mock_local_image_ctx, 11, true, 0, 0); | |
2264 | expect_notify_update(mock_local_image_ctx); | |
2265 | ||
2266 | // idle | |
2267 | expect_load_image_meta(mock_image_meta, false, 0); | |
2268 | expect_is_refresh_required(mock_local_image_ctx, true); | |
2269 | expect_refresh( | |
2270 | mock_local_image_ctx, { | |
2271 | {11U, librbd::SnapInfo{"snap1", cls::rbd::MirrorSnapshotNamespace{ | |
2272 | cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "remote mirror uuid", | |
2273 | 1, true, 0, {{1, CEPH_NOSNAP}}}, | |
2274 | 0, {}, 0, 0, {}}}, | |
2275 | }, 0); | |
2276 | expect_is_refresh_required(mock_remote_image_ctx, false); | |
2277 | ||
2278 | // fire init | |
2279 | C_SaferCond init_ctx; | |
2280 | mock_replayer.init(&init_ctx); | |
2281 | ASSERT_EQ(0, init_ctx.wait()); | |
2282 | ||
2283 | // wait for sync to complete | |
2284 | ASSERT_EQ(0, wait_for_notification(3)); | |
2285 | ||
2286 | // shut down | |
2287 | ASSERT_EQ(0, shut_down_entry_replayer(mock_replayer, mock_threads, | |
2288 | mock_local_image_ctx, | |
2289 | mock_remote_image_ctx)); | |
2290 | } | |
2291 | ||
9f95a23c TL |
2292 | } // namespace snapshot |
2293 | } // namespace image_replayer | |
2294 | } // namespace mirror | |
2295 | } // namespace rbd |