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