]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "test/rbd_mirror/test_mock_fixture.h" | |
5 | #include "librbd/journal/TypeTraits.h" | |
31f18b77 | 6 | #include "tools/rbd_mirror/InstanceWatcher.h" |
7c673cae FG |
7 | #include "tools/rbd_mirror/Threads.h" |
8 | #include "tools/rbd_mirror/image_replayer/BootstrapRequest.h" | |
9 | #include "tools/rbd_mirror/image_replayer/CloseImageRequest.h" | |
10 | #include "tools/rbd_mirror/image_replayer/CreateImageRequest.h" | |
11 | #include "tools/rbd_mirror/image_replayer/IsPrimaryRequest.h" | |
12 | #include "tools/rbd_mirror/image_replayer/OpenImageRequest.h" | |
13 | #include "tools/rbd_mirror/image_replayer/OpenLocalImageRequest.h" | |
14 | #include "test/journal/mock/MockJournaler.h" | |
15 | #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" | |
16 | #include "test/librbd/mock/MockImageCtx.h" | |
17 | #include "test/librbd/mock/MockJournal.h" | |
18 | ||
19 | namespace librbd { | |
20 | ||
21 | namespace { | |
22 | ||
23 | struct MockTestImageCtx : public librbd::MockImageCtx { | |
24 | MockTestImageCtx(librbd::ImageCtx &image_ctx) | |
25 | : librbd::MockImageCtx(image_ctx) { | |
26 | } | |
27 | }; | |
28 | ||
29 | } // anonymous namespace | |
30 | ||
31 | namespace journal { | |
32 | ||
33 | template <> | |
34 | struct TypeTraits<librbd::MockTestImageCtx> { | |
35 | typedef ::journal::MockJournaler Journaler; | |
36 | }; | |
37 | ||
38 | } // namespace journal | |
d2e6a577 FG |
39 | |
40 | namespace util { | |
41 | ||
42 | static std::string s_image_id; | |
43 | ||
44 | template <> | |
45 | std::string generate_image_id<MockTestImageCtx>(librados::IoCtx&) { | |
11fdf7f2 | 46 | ceph_assert(!s_image_id.empty()); |
d2e6a577 FG |
47 | return s_image_id; |
48 | } | |
49 | ||
50 | } // namespace util | |
7c673cae FG |
51 | } // namespace librbd |
52 | ||
53 | namespace rbd { | |
54 | namespace mirror { | |
55 | ||
56 | class ProgressContext; | |
57 | ||
11fdf7f2 TL |
58 | template <> |
59 | struct Threads<librbd::MockTestImageCtx> { | |
60 | Mutex &timer_lock; | |
61 | SafeTimer *timer; | |
62 | ContextWQ *work_queue; | |
63 | ||
64 | Threads(Threads<librbd::ImageCtx> *threads) | |
65 | : timer_lock(threads->timer_lock), timer(threads->timer), | |
66 | work_queue(threads->work_queue) { | |
67 | } | |
68 | }; | |
69 | ||
7c673cae | 70 | template<> |
31f18b77 FG |
71 | struct ImageSync<librbd::MockTestImageCtx> { |
72 | static ImageSync* s_instance; | |
73 | Context *on_finish = nullptr; | |
74 | ||
75 | static ImageSync* create( | |
76 | librbd::MockTestImageCtx *local_image_ctx, | |
77 | librbd::MockTestImageCtx *remote_image_ctx, | |
11fdf7f2 TL |
78 | SafeTimer *timer, Mutex *timer_lock, |
79 | const std::string &mirror_uuid, ::journal::MockJournaler *journaler, | |
31f18b77 FG |
80 | librbd::journal::MirrorPeerClientMeta *client_meta, ContextWQ *work_queue, |
81 | InstanceWatcher<librbd::MockTestImageCtx> *instance_watcher, | |
82 | Context *on_finish, ProgressContext *progress_ctx) { | |
11fdf7f2 | 83 | ceph_assert(s_instance != nullptr); |
31f18b77 FG |
84 | s_instance->on_finish = on_finish; |
85 | return s_instance; | |
86 | } | |
87 | ||
88 | ImageSync() { | |
11fdf7f2 | 89 | ceph_assert(s_instance == nullptr); |
31f18b77 FG |
90 | s_instance = this; |
91 | } | |
92 | ~ImageSync() { | |
93 | s_instance = nullptr; | |
94 | } | |
95 | ||
96 | MOCK_METHOD0(get, void()); | |
97 | MOCK_METHOD0(put, void()); | |
98 | MOCK_METHOD0(send, void()); | |
99 | MOCK_METHOD0(cancel, void()); | |
100 | }; | |
101 | ||
102 | ImageSync<librbd::MockTestImageCtx>* | |
103 | ImageSync<librbd::MockTestImageCtx>::s_instance = nullptr; | |
104 | ||
105 | template<> | |
106 | struct InstanceWatcher<librbd::MockTestImageCtx> { | |
7c673cae FG |
107 | }; |
108 | ||
109 | namespace image_replayer { | |
110 | ||
111 | template<> | |
112 | struct CloseImageRequest<librbd::MockTestImageCtx> { | |
113 | static CloseImageRequest* s_instance; | |
114 | librbd::MockTestImageCtx **image_ctx = nullptr; | |
115 | Context *on_finish = nullptr; | |
116 | ||
117 | static CloseImageRequest* create(librbd::MockTestImageCtx **image_ctx, | |
118 | Context *on_finish) { | |
11fdf7f2 | 119 | ceph_assert(s_instance != nullptr); |
7c673cae FG |
120 | s_instance->image_ctx = image_ctx; |
121 | s_instance->on_finish = on_finish; | |
122 | s_instance->construct(*image_ctx); | |
123 | return s_instance; | |
124 | } | |
125 | ||
126 | CloseImageRequest() { | |
11fdf7f2 | 127 | ceph_assert(s_instance == nullptr); |
7c673cae FG |
128 | s_instance = this; |
129 | } | |
130 | ~CloseImageRequest() { | |
131 | s_instance = nullptr; | |
132 | } | |
133 | ||
134 | MOCK_METHOD1(construct, void(librbd::MockTestImageCtx *image_ctx)); | |
135 | MOCK_METHOD0(send, void()); | |
136 | }; | |
137 | ||
138 | template<> | |
139 | struct CreateImageRequest<librbd::MockTestImageCtx> { | |
140 | static CreateImageRequest* s_instance; | |
7c673cae FG |
141 | Context *on_finish = nullptr; |
142 | ||
11fdf7f2 TL |
143 | static CreateImageRequest* create(Threads<librbd::MockTestImageCtx>* threads, |
144 | librados::IoCtx &local_io_ctx, | |
7c673cae FG |
145 | const std::string &global_image_id, |
146 | const std::string &remote_mirror_uuid, | |
147 | const std::string &local_image_name, | |
d2e6a577 | 148 | const std::string &local_image_id, |
7c673cae | 149 | librbd::MockTestImageCtx *remote_image_ctx, |
7c673cae | 150 | Context *on_finish) { |
11fdf7f2 | 151 | ceph_assert(s_instance != nullptr); |
7c673cae | 152 | s_instance->on_finish = on_finish; |
d2e6a577 | 153 | s_instance->construct(local_image_id); |
7c673cae FG |
154 | return s_instance; |
155 | } | |
156 | ||
157 | CreateImageRequest() { | |
11fdf7f2 | 158 | ceph_assert(s_instance == nullptr); |
7c673cae FG |
159 | s_instance = this; |
160 | } | |
161 | ~CreateImageRequest() { | |
162 | s_instance = nullptr; | |
163 | } | |
164 | ||
d2e6a577 | 165 | MOCK_METHOD1(construct, void(const std::string&)); |
7c673cae FG |
166 | MOCK_METHOD0(send, void()); |
167 | }; | |
168 | ||
169 | template<> | |
170 | struct IsPrimaryRequest<librbd::MockTestImageCtx> { | |
171 | static IsPrimaryRequest* s_instance; | |
172 | bool *primary = nullptr; | |
173 | Context *on_finish = nullptr; | |
174 | ||
175 | static IsPrimaryRequest* create(librbd::MockTestImageCtx *image_ctx, | |
176 | bool *primary, Context *on_finish) { | |
11fdf7f2 | 177 | ceph_assert(s_instance != nullptr); |
7c673cae FG |
178 | s_instance->primary = primary; |
179 | s_instance->on_finish = on_finish; | |
180 | return s_instance; | |
181 | } | |
182 | ||
183 | IsPrimaryRequest() { | |
11fdf7f2 | 184 | ceph_assert(s_instance == nullptr); |
7c673cae FG |
185 | s_instance = this; |
186 | } | |
187 | ~IsPrimaryRequest() { | |
188 | s_instance = nullptr; | |
189 | } | |
190 | ||
191 | MOCK_METHOD0(send, void()); | |
192 | }; | |
193 | ||
194 | template<> | |
195 | struct OpenImageRequest<librbd::MockTestImageCtx> { | |
196 | static OpenImageRequest* s_instance; | |
197 | librbd::MockTestImageCtx **image_ctx = nullptr; | |
198 | Context *on_finish = nullptr; | |
199 | ||
200 | static OpenImageRequest* create(librados::IoCtx &io_ctx, | |
201 | librbd::MockTestImageCtx **image_ctx, | |
202 | const std::string &image_id, | |
203 | bool read_only, Context *on_finish) { | |
11fdf7f2 | 204 | ceph_assert(s_instance != nullptr); |
7c673cae FG |
205 | s_instance->image_ctx = image_ctx; |
206 | s_instance->on_finish = on_finish; | |
207 | s_instance->construct(io_ctx, image_id); | |
208 | return s_instance; | |
209 | } | |
210 | ||
211 | OpenImageRequest() { | |
11fdf7f2 | 212 | ceph_assert(s_instance == nullptr); |
7c673cae FG |
213 | s_instance = this; |
214 | } | |
215 | ~OpenImageRequest() { | |
216 | s_instance = nullptr; | |
217 | } | |
218 | ||
219 | MOCK_METHOD2(construct, void(librados::IoCtx &io_ctx, | |
220 | const std::string &image_id)); | |
221 | MOCK_METHOD0(send, void()); | |
222 | }; | |
223 | ||
224 | template<> | |
225 | struct OpenLocalImageRequest<librbd::MockTestImageCtx> { | |
226 | static OpenLocalImageRequest* s_instance; | |
227 | librbd::MockTestImageCtx **image_ctx = nullptr; | |
228 | Context *on_finish = nullptr; | |
229 | ||
230 | static OpenLocalImageRequest* create(librados::IoCtx &local_io_ctx, | |
231 | librbd::MockTestImageCtx **local_image_ctx, | |
232 | const std::string &local_image_id, | |
233 | ContextWQ *work_queue, | |
234 | Context *on_finish) { | |
11fdf7f2 | 235 | ceph_assert(s_instance != nullptr); |
7c673cae FG |
236 | s_instance->image_ctx = local_image_ctx; |
237 | s_instance->on_finish = on_finish; | |
238 | s_instance->construct(local_io_ctx, local_image_id); | |
239 | return s_instance; | |
240 | } | |
241 | ||
242 | OpenLocalImageRequest() { | |
11fdf7f2 | 243 | ceph_assert(s_instance == nullptr); |
7c673cae FG |
244 | s_instance = this; |
245 | } | |
246 | ~OpenLocalImageRequest() { | |
247 | s_instance = nullptr; | |
248 | } | |
249 | ||
250 | MOCK_METHOD2(construct, void(librados::IoCtx &io_ctx, | |
251 | const std::string &image_id)); | |
252 | MOCK_METHOD0(send, void()); | |
253 | }; | |
254 | ||
255 | CloseImageRequest<librbd::MockTestImageCtx>* | |
256 | CloseImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
257 | CreateImageRequest<librbd::MockTestImageCtx>* | |
258 | CreateImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
259 | IsPrimaryRequest<librbd::MockTestImageCtx>* | |
260 | IsPrimaryRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
261 | OpenImageRequest<librbd::MockTestImageCtx>* | |
262 | OpenImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
263 | OpenLocalImageRequest<librbd::MockTestImageCtx>* | |
264 | OpenLocalImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
265 | ||
266 | } // namespace image_replayer | |
267 | } // namespace mirror | |
268 | } // namespace rbd | |
269 | ||
270 | // template definitions | |
271 | #include "tools/rbd_mirror/image_replayer/BootstrapRequest.cc" | |
7c673cae FG |
272 | |
273 | namespace rbd { | |
274 | namespace mirror { | |
275 | namespace image_replayer { | |
276 | ||
277 | using ::testing::_; | |
278 | using ::testing::DoAll; | |
279 | using ::testing::InSequence; | |
280 | using ::testing::Invoke; | |
281 | using ::testing::Return; | |
282 | using ::testing::SetArgPointee; | |
283 | using ::testing::StrEq; | |
284 | using ::testing::WithArg; | |
285 | ||
286 | MATCHER_P(IsSameIoCtx, io_ctx, "") { | |
287 | return &get_mock_io_ctx(arg) == &get_mock_io_ctx(*io_ctx); | |
288 | } | |
289 | ||
290 | class TestMockImageReplayerBootstrapRequest : public TestMockFixture { | |
291 | public: | |
11fdf7f2 | 292 | typedef Threads<librbd::MockTestImageCtx> MockThreads; |
7c673cae FG |
293 | typedef BootstrapRequest<librbd::MockTestImageCtx> MockBootstrapRequest; |
294 | typedef CloseImageRequest<librbd::MockTestImageCtx> MockCloseImageRequest; | |
295 | typedef CreateImageRequest<librbd::MockTestImageCtx> MockCreateImageRequest; | |
31f18b77 FG |
296 | typedef ImageSync<librbd::MockTestImageCtx> MockImageSync; |
297 | typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher; | |
7c673cae FG |
298 | typedef IsPrimaryRequest<librbd::MockTestImageCtx> MockIsPrimaryRequest; |
299 | typedef OpenImageRequest<librbd::MockTestImageCtx> MockOpenImageRequest; | |
300 | typedef OpenLocalImageRequest<librbd::MockTestImageCtx> MockOpenLocalImageRequest; | |
301 | typedef std::list<cls::journal::Tag> Tags; | |
302 | ||
303 | void SetUp() override { | |
304 | TestMockFixture::SetUp(); | |
305 | ||
306 | librbd::RBD rbd; | |
307 | ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size)); | |
308 | ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx)); | |
309 | } | |
310 | ||
311 | void create_local_image() { | |
312 | librbd::RBD rbd; | |
313 | ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size)); | |
314 | ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx)); | |
315 | } | |
316 | ||
317 | void expect_journaler_get_client(::journal::MockJournaler &mock_journaler, | |
318 | const std::string &client_id, | |
319 | cls::journal::Client &client, int r) { | |
320 | EXPECT_CALL(mock_journaler, get_client(StrEq(client_id), _, _)) | |
321 | .WillOnce(DoAll(WithArg<1>(Invoke([client](cls::journal::Client *out_client) { | |
322 | *out_client = client; | |
323 | })), | |
324 | WithArg<2>(Invoke([this, r](Context *on_finish) { | |
325 | m_threads->work_queue->queue(on_finish, r); | |
326 | })))); | |
327 | } | |
328 | ||
329 | void expect_journaler_get_tags(::journal::MockJournaler &mock_journaler, | |
330 | uint64_t tag_class, const Tags& tags, | |
331 | int r) { | |
332 | EXPECT_CALL(mock_journaler, get_tags(tag_class, _, _)) | |
333 | .WillOnce(DoAll(WithArg<1>(Invoke([tags](Tags *out_tags) { | |
334 | *out_tags = tags; | |
335 | })), | |
336 | WithArg<2>(Invoke([this, r](Context *on_finish) { | |
337 | m_threads->work_queue->queue(on_finish, r); | |
338 | })))); | |
339 | } | |
340 | ||
341 | void expect_journaler_register_client(::journal::MockJournaler &mock_journaler, | |
342 | const librbd::journal::ClientData &client_data, | |
343 | int r) { | |
344 | bufferlist bl; | |
11fdf7f2 | 345 | encode(client_data, bl); |
7c673cae FG |
346 | |
347 | EXPECT_CALL(mock_journaler, register_client(ContentsEqual(bl), _)) | |
348 | .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) { | |
349 | m_threads->work_queue->queue(on_finish, r); | |
350 | }))); | |
351 | } | |
352 | ||
d2e6a577 FG |
353 | void expect_journaler_unregister_client(::journal::MockJournaler &mock_journaler, |
354 | int r) { | |
355 | EXPECT_CALL(mock_journaler, unregister_client(_)) | |
356 | .WillOnce(Invoke([this, r](Context *on_finish) { | |
357 | m_threads->work_queue->queue(on_finish, r); | |
358 | })); | |
359 | } | |
360 | ||
7c673cae FG |
361 | void expect_journaler_update_client(::journal::MockJournaler &mock_journaler, |
362 | const librbd::journal::ClientData &client_data, | |
363 | int r) { | |
364 | bufferlist bl; | |
11fdf7f2 | 365 | encode(client_data, bl); |
7c673cae FG |
366 | |
367 | EXPECT_CALL(mock_journaler, update_client(ContentsEqual(bl), _)) | |
368 | .WillOnce(WithArg<1>(Invoke([this, r](Context *on_finish) { | |
369 | m_threads->work_queue->queue(on_finish, r); | |
370 | }))); | |
371 | } | |
372 | ||
373 | void expect_open_image(MockOpenImageRequest &mock_open_image_request, | |
374 | librados::IoCtx &io_ctx, const std::string &image_id, | |
375 | librbd::MockTestImageCtx &mock_image_ctx, int r) { | |
376 | EXPECT_CALL(mock_open_image_request, construct(IsSameIoCtx(&io_ctx), image_id)); | |
377 | EXPECT_CALL(mock_open_image_request, send()) | |
378 | .WillOnce(Invoke([this, &mock_open_image_request, &mock_image_ctx, r]() { | |
379 | *mock_open_image_request.image_ctx = &mock_image_ctx; | |
380 | m_threads->work_queue->queue(mock_open_image_request.on_finish, r); | |
381 | })); | |
382 | } | |
383 | ||
384 | void expect_open_local_image(MockOpenLocalImageRequest &mock_open_local_image_request, | |
385 | librados::IoCtx &io_ctx, const std::string &image_id, | |
386 | librbd::MockTestImageCtx *mock_image_ctx, int r) { | |
387 | EXPECT_CALL(mock_open_local_image_request, | |
388 | construct(IsSameIoCtx(&io_ctx), image_id)); | |
389 | EXPECT_CALL(mock_open_local_image_request, send()) | |
390 | .WillOnce(Invoke([this, &mock_open_local_image_request, mock_image_ctx, r]() { | |
391 | *mock_open_local_image_request.image_ctx = mock_image_ctx; | |
392 | m_threads->work_queue->queue(mock_open_local_image_request.on_finish, | |
393 | r); | |
394 | })); | |
395 | } | |
396 | ||
397 | void expect_close_image(MockCloseImageRequest &mock_close_image_request, | |
398 | librbd::MockTestImageCtx &mock_image_ctx, int r) { | |
399 | EXPECT_CALL(mock_close_image_request, construct(&mock_image_ctx)); | |
400 | EXPECT_CALL(mock_close_image_request, send()) | |
401 | .WillOnce(Invoke([this, &mock_close_image_request, r]() { | |
402 | *mock_close_image_request.image_ctx = nullptr; | |
403 | m_threads->work_queue->queue(mock_close_image_request.on_finish, r); | |
404 | })); | |
405 | } | |
406 | ||
407 | void expect_is_primary(MockIsPrimaryRequest &mock_is_primary_request, | |
408 | bool primary, int r) { | |
409 | EXPECT_CALL(mock_is_primary_request, send()) | |
410 | .WillOnce(Invoke([this, &mock_is_primary_request, primary, r]() { | |
411 | *mock_is_primary_request.primary = primary; | |
412 | m_threads->work_queue->queue(mock_is_primary_request.on_finish, r); | |
413 | })); | |
414 | } | |
415 | ||
416 | void expect_journal_get_tag_tid(librbd::MockJournal &mock_journal, | |
417 | uint64_t tag_tid) { | |
418 | EXPECT_CALL(mock_journal, get_tag_tid()).WillOnce(Return(tag_tid)); | |
419 | } | |
420 | ||
421 | void expect_journal_get_tag_data(librbd::MockJournal &mock_journal, | |
422 | const librbd::journal::TagData &tag_data) { | |
423 | EXPECT_CALL(mock_journal, get_tag_data()).WillOnce(Return(tag_data)); | |
424 | } | |
425 | ||
426 | void expect_is_resync_requested(librbd::MockJournal &mock_journal, | |
427 | bool do_resync, int r) { | |
428 | EXPECT_CALL(mock_journal, is_resync_requested(_)) | |
429 | .WillOnce(DoAll(SetArgPointee<0>(do_resync), | |
430 | Return(r))); | |
431 | } | |
432 | ||
433 | void expect_create_image(MockCreateImageRequest &mock_create_image_request, | |
434 | const std::string &image_id, int r) { | |
d2e6a577 | 435 | EXPECT_CALL(mock_create_image_request, construct(image_id)); |
7c673cae | 436 | EXPECT_CALL(mock_create_image_request, send()) |
d2e6a577 | 437 | .WillOnce(Invoke([this, &mock_create_image_request, r]() { |
7c673cae FG |
438 | m_threads->work_queue->queue(mock_create_image_request.on_finish, r); |
439 | })); | |
440 | } | |
441 | ||
31f18b77 FG |
442 | void expect_image_sync(MockImageSync &mock_image_sync, int r) { |
443 | EXPECT_CALL(mock_image_sync, get()); | |
444 | EXPECT_CALL(mock_image_sync, send()) | |
445 | .WillOnce(Invoke([this, &mock_image_sync, r]() { | |
446 | m_threads->work_queue->queue(mock_image_sync.on_finish, r); | |
447 | })); | |
448 | EXPECT_CALL(mock_image_sync, put()); | |
7c673cae FG |
449 | } |
450 | ||
451 | bufferlist encode_tag_data(const librbd::journal::TagData &tag_data) { | |
452 | bufferlist bl; | |
11fdf7f2 | 453 | encode(tag_data, bl); |
7c673cae FG |
454 | return bl; |
455 | } | |
456 | ||
11fdf7f2 TL |
457 | MockBootstrapRequest *create_request(MockThreads* mock_threads, |
458 | MockInstanceWatcher *mock_instance_watcher, | |
7c673cae FG |
459 | ::journal::MockJournaler &mock_journaler, |
460 | const std::string &local_image_id, | |
461 | const std::string &remote_image_id, | |
462 | const std::string &global_image_id, | |
463 | const std::string &local_mirror_uuid, | |
464 | const std::string &remote_mirror_uuid, | |
b32b8144 FG |
465 | cls::journal::ClientState *client_state, |
466 | librbd::journal::MirrorPeerClientMeta *mirror_peer_client_meta, | |
7c673cae | 467 | Context *on_finish) { |
11fdf7f2 | 468 | return new MockBootstrapRequest(mock_threads, m_local_io_ctx, |
7c673cae | 469 | m_remote_io_ctx, |
31f18b77 | 470 | mock_instance_watcher, |
7c673cae FG |
471 | &m_local_test_image_ctx, |
472 | local_image_id, | |
473 | remote_image_id, | |
474 | global_image_id, | |
7c673cae FG |
475 | local_mirror_uuid, |
476 | remote_mirror_uuid, | |
477 | &mock_journaler, | |
b32b8144 | 478 | client_state, mirror_peer_client_meta, |
7c673cae FG |
479 | on_finish, &m_do_resync); |
480 | } | |
481 | ||
482 | librbd::ImageCtx *m_remote_image_ctx; | |
483 | librbd::ImageCtx *m_local_image_ctx = nullptr; | |
484 | librbd::MockTestImageCtx *m_local_test_image_ctx = nullptr; | |
7c673cae FG |
485 | bool m_do_resync; |
486 | }; | |
487 | ||
488 | TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteSyncingState) { | |
489 | create_local_image(); | |
490 | ||
491 | InSequence seq; | |
492 | ||
493 | // lookup remote image tag class | |
494 | cls::journal::Client client; | |
495 | librbd::journal::ClientData client_data{ | |
496 | librbd::journal::ImageClientMeta{123}}; | |
11fdf7f2 | 497 | encode(client_data, client.data); |
7c673cae FG |
498 | ::journal::MockJournaler mock_journaler; |
499 | expect_journaler_get_client(mock_journaler, | |
500 | librbd::Journal<>::IMAGE_CLIENT_ID, | |
501 | client, 0); | |
502 | ||
d2e6a577 FG |
503 | // open the remote image |
504 | librbd::MockJournal mock_journal; | |
505 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
506 | MockOpenImageRequest mock_open_image_request; | |
507 | expect_open_image(mock_open_image_request, m_remote_io_ctx, | |
508 | mock_remote_image_ctx.id, mock_remote_image_ctx, 0); | |
509 | ||
d2e6a577 | 510 | // test if remote image is primary |
7c673cae FG |
511 | MockIsPrimaryRequest mock_is_primary_request; |
512 | expect_is_primary(mock_is_primary_request, false, 0); | |
513 | ||
514 | // switch the state to replaying | |
b32b8144 FG |
515 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); |
516 | librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{ | |
517 | mock_local_image_ctx.id}; | |
7c673cae FG |
518 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; |
519 | client_data.client_meta = mirror_peer_client_meta; | |
520 | expect_journaler_update_client(mock_journaler, client_data, 0); | |
521 | ||
522 | MockCloseImageRequest mock_close_image_request; | |
523 | expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0); | |
524 | ||
525 | C_SaferCond ctx; | |
11fdf7f2 | 526 | MockThreads mock_threads(m_threads); |
31f18b77 | 527 | MockInstanceWatcher mock_instance_watcher; |
b32b8144 FG |
528 | cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED; |
529 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING; | |
7c673cae | 530 | MockBootstrapRequest *request = create_request( |
11fdf7f2 TL |
531 | &mock_threads, &mock_instance_watcher, mock_journaler, |
532 | mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id", | |
533 | "local mirror uuid", "remote mirror uuid", &client_state, | |
534 | &mirror_peer_client_meta, &ctx); | |
7c673cae FG |
535 | request->send(); |
536 | ASSERT_EQ(-EREMOTEIO, ctx.wait()); | |
537 | } | |
538 | ||
28e407b8 AA |
539 | TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteNotTagOwner) { |
540 | create_local_image(); | |
541 | ||
542 | InSequence seq; | |
543 | ||
544 | // lookup remote image tag class | |
545 | cls::journal::Client client; | |
546 | librbd::journal::ClientData client_data{ | |
547 | librbd::journal::ImageClientMeta{123}}; | |
548 | encode(client_data, client.data); | |
549 | ::journal::MockJournaler mock_journaler; | |
550 | expect_journaler_get_client(mock_journaler, | |
551 | librbd::Journal<>::IMAGE_CLIENT_ID, | |
552 | client, 0); | |
553 | ||
554 | // open the remote image | |
555 | librbd::MockJournal mock_journal; | |
556 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
557 | MockOpenImageRequest mock_open_image_request; | |
558 | expect_open_image(mock_open_image_request, m_remote_io_ctx, | |
559 | mock_remote_image_ctx.id, mock_remote_image_ctx, 0); | |
560 | ||
561 | // test if remote image is primary | |
562 | MockIsPrimaryRequest mock_is_primary_request; | |
563 | expect_is_primary(mock_is_primary_request, false, 0); | |
564 | ||
565 | // open the local image | |
566 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
567 | mock_local_image_ctx.journal = &mock_journal; | |
568 | MockOpenLocalImageRequest mock_open_local_image_request; | |
569 | expect_open_local_image(mock_open_local_image_request, m_local_io_ctx, | |
570 | mock_local_image_ctx.id, &mock_local_image_ctx, 0); | |
571 | expect_is_resync_requested(mock_journal, false, 0); | |
572 | ||
573 | expect_journal_get_tag_tid(mock_journal, 345); | |
574 | expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::LOCAL_MIRROR_UUID, | |
575 | librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
576 | true, 344, 0}); | |
577 | ||
578 | MockCloseImageRequest mock_close_image_request; | |
579 | expect_close_image(mock_close_image_request, mock_local_image_ctx, 0); | |
580 | expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0); | |
581 | ||
582 | C_SaferCond ctx; | |
11fdf7f2 | 583 | MockThreads mock_threads(m_threads); |
28e407b8 AA |
584 | MockInstanceWatcher mock_instance_watcher; |
585 | cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED; | |
586 | librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{ | |
587 | mock_local_image_ctx.id}; | |
588 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; | |
589 | MockBootstrapRequest *request = create_request( | |
11fdf7f2 TL |
590 | &mock_threads, &mock_instance_watcher, mock_journaler, |
591 | mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id", | |
592 | "local mirror uuid", "remote mirror uuid", &client_state, | |
593 | &mirror_peer_client_meta, &ctx); | |
28e407b8 AA |
594 | request->send(); |
595 | ASSERT_EQ(-EREMOTEIO, ctx.wait()); | |
596 | } | |
597 | ||
7c673cae FG |
598 | TEST_F(TestMockImageReplayerBootstrapRequest, RemoteDemotePromote) { |
599 | create_local_image(); | |
600 | ||
601 | InSequence seq; | |
602 | ||
603 | // lookup remote image tag class | |
604 | cls::journal::Client client; | |
605 | librbd::journal::ClientData client_data{ | |
606 | librbd::journal::ImageClientMeta{123}}; | |
11fdf7f2 | 607 | encode(client_data, client.data); |
7c673cae FG |
608 | ::journal::MockJournaler mock_journaler; |
609 | expect_journaler_get_client(mock_journaler, | |
610 | librbd::Journal<>::IMAGE_CLIENT_ID, | |
611 | client, 0); | |
612 | ||
d2e6a577 FG |
613 | // open the remote image |
614 | librbd::MockJournal mock_journal; | |
615 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
616 | MockOpenImageRequest mock_open_image_request; | |
617 | expect_open_image(mock_open_image_request, m_remote_io_ctx, | |
618 | mock_remote_image_ctx.id, mock_remote_image_ctx, 0); | |
619 | ||
d2e6a577 | 620 | // test if remote image is primary |
7c673cae | 621 | MockIsPrimaryRequest mock_is_primary_request; |
28e407b8 | 622 | expect_is_primary(mock_is_primary_request, false, 0); |
7c673cae FG |
623 | |
624 | // open the local image | |
b32b8144 | 625 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); |
7c673cae FG |
626 | mock_local_image_ctx.journal = &mock_journal; |
627 | MockOpenLocalImageRequest mock_open_local_image_request; | |
628 | expect_open_local_image(mock_open_local_image_request, m_local_io_ctx, | |
629 | mock_local_image_ctx.id, &mock_local_image_ctx, 0); | |
630 | expect_is_resync_requested(mock_journal, false, 0); | |
631 | ||
28e407b8 AA |
632 | expect_journal_get_tag_tid(mock_journal, 345); |
633 | expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"}); | |
634 | ||
7c673cae FG |
635 | // remote demotion / promotion event |
636 | Tags tags = { | |
637 | {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID, | |
638 | librbd::Journal<>::LOCAL_MIRROR_UUID, | |
639 | true, 1, 99})}, | |
640 | {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
641 | librbd::Journal<>::LOCAL_MIRROR_UUID, | |
642 | true, 2, 1})}, | |
643 | {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID, | |
644 | librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
645 | true, 2, 1})}, | |
646 | {5, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID, | |
647 | librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
648 | true, 4, 369})} | |
649 | }; | |
650 | expect_journaler_get_tags(mock_journaler, 123, tags, 0); | |
7c673cae FG |
651 | |
652 | MockCloseImageRequest mock_close_image_request; | |
653 | expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0); | |
654 | ||
655 | C_SaferCond ctx; | |
11fdf7f2 | 656 | MockThreads mock_threads(m_threads); |
31f18b77 | 657 | MockInstanceWatcher mock_instance_watcher; |
b32b8144 FG |
658 | cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED; |
659 | librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{ | |
660 | mock_local_image_ctx.id}; | |
661 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; | |
7c673cae | 662 | MockBootstrapRequest *request = create_request( |
11fdf7f2 TL |
663 | &mock_threads, &mock_instance_watcher, mock_journaler, |
664 | mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id", | |
665 | "local mirror uuid", "remote mirror uuid", &client_state, | |
666 | &mirror_peer_client_meta, &ctx); | |
7c673cae FG |
667 | request->send(); |
668 | ASSERT_EQ(0, ctx.wait()); | |
669 | } | |
670 | ||
671 | TEST_F(TestMockImageReplayerBootstrapRequest, MultipleRemoteDemotePromotes) { | |
672 | create_local_image(); | |
673 | ||
674 | InSequence seq; | |
675 | ||
676 | // lookup remote image tag class | |
677 | cls::journal::Client client; | |
678 | librbd::journal::ClientData client_data{ | |
679 | librbd::journal::ImageClientMeta{123}}; | |
11fdf7f2 | 680 | encode(client_data, client.data); |
7c673cae FG |
681 | ::journal::MockJournaler mock_journaler; |
682 | expect_journaler_get_client(mock_journaler, | |
683 | librbd::Journal<>::IMAGE_CLIENT_ID, | |
684 | client, 0); | |
685 | ||
d2e6a577 FG |
686 | // open the remote image |
687 | librbd::MockJournal mock_journal; | |
688 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
689 | MockOpenImageRequest mock_open_image_request; | |
690 | expect_open_image(mock_open_image_request, m_remote_io_ctx, | |
691 | mock_remote_image_ctx.id, mock_remote_image_ctx, 0); | |
692 | ||
d2e6a577 | 693 | // test if remote image is primary |
7c673cae FG |
694 | MockIsPrimaryRequest mock_is_primary_request; |
695 | expect_is_primary(mock_is_primary_request, true, 0); | |
696 | ||
697 | // open the local image | |
b32b8144 | 698 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); |
7c673cae FG |
699 | mock_local_image_ctx.journal = &mock_journal; |
700 | MockOpenLocalImageRequest mock_open_local_image_request; | |
701 | expect_open_local_image(mock_open_local_image_request, m_local_io_ctx, | |
702 | mock_local_image_ctx.id, &mock_local_image_ctx, 0); | |
703 | expect_is_resync_requested(mock_journal, false, 0); | |
704 | ||
28e407b8 AA |
705 | expect_journal_get_tag_tid(mock_journal, 345); |
706 | expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
707 | "remote mirror uuid", true, 4, 1}); | |
708 | ||
7c673cae FG |
709 | // remote demotion / promotion event |
710 | Tags tags = { | |
711 | {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID, | |
712 | librbd::Journal<>::LOCAL_MIRROR_UUID, | |
713 | true, 1, 99})}, | |
714 | {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
715 | librbd::Journal<>::LOCAL_MIRROR_UUID, | |
716 | true, 2, 1})}, | |
717 | {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID, | |
718 | librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
719 | true, 3, 1})}, | |
720 | {5, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
721 | librbd::Journal<>::LOCAL_MIRROR_UUID, | |
722 | true, 4, 1})}, | |
723 | {6, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID, | |
724 | librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
725 | true, 5, 1})}, | |
726 | {7, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
727 | librbd::Journal<>::LOCAL_MIRROR_UUID, | |
728 | true, 6, 1})}, | |
729 | {8, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID, | |
730 | librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
731 | true, 7, 1})} | |
732 | }; | |
733 | expect_journaler_get_tags(mock_journaler, 123, tags, 0); | |
7c673cae FG |
734 | |
735 | MockCloseImageRequest mock_close_image_request; | |
736 | expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0); | |
737 | ||
738 | C_SaferCond ctx; | |
11fdf7f2 | 739 | MockThreads mock_threads(m_threads); |
31f18b77 | 740 | MockInstanceWatcher mock_instance_watcher; |
b32b8144 FG |
741 | cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED; |
742 | librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{ | |
743 | mock_local_image_ctx.id}; | |
744 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; | |
7c673cae | 745 | MockBootstrapRequest *request = create_request( |
11fdf7f2 TL |
746 | &mock_threads, &mock_instance_watcher, mock_journaler, |
747 | mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id", | |
748 | "local mirror uuid", "remote mirror uuid", &client_state, | |
749 | &mirror_peer_client_meta, &ctx); | |
7c673cae FG |
750 | request->send(); |
751 | ASSERT_EQ(0, ctx.wait()); | |
752 | } | |
753 | ||
754 | TEST_F(TestMockImageReplayerBootstrapRequest, LocalDemoteRemotePromote) { | |
755 | create_local_image(); | |
756 | ||
757 | InSequence seq; | |
758 | ||
759 | // lookup remote image tag class | |
760 | cls::journal::Client client; | |
761 | librbd::journal::ClientData client_data{ | |
762 | librbd::journal::ImageClientMeta{123}}; | |
11fdf7f2 | 763 | encode(client_data, client.data); |
7c673cae FG |
764 | ::journal::MockJournaler mock_journaler; |
765 | expect_journaler_get_client(mock_journaler, | |
766 | librbd::Journal<>::IMAGE_CLIENT_ID, | |
767 | client, 0); | |
768 | ||
d2e6a577 FG |
769 | // open the remote image |
770 | librbd::MockJournal mock_journal; | |
771 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
772 | MockOpenImageRequest mock_open_image_request; | |
773 | expect_open_image(mock_open_image_request, m_remote_io_ctx, | |
774 | mock_remote_image_ctx.id, mock_remote_image_ctx, 0); | |
775 | ||
d2e6a577 | 776 | // test if remote image is primary |
7c673cae FG |
777 | MockIsPrimaryRequest mock_is_primary_request; |
778 | expect_is_primary(mock_is_primary_request, true, 0); | |
779 | ||
780 | // open the local image | |
b32b8144 | 781 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); |
7c673cae FG |
782 | mock_local_image_ctx.journal = &mock_journal; |
783 | MockOpenLocalImageRequest mock_open_local_image_request; | |
784 | expect_open_local_image(mock_open_local_image_request, m_local_io_ctx, | |
785 | mock_local_image_ctx.id, &mock_local_image_ctx, 0); | |
786 | expect_is_resync_requested(mock_journal, false, 0); | |
787 | ||
28e407b8 AA |
788 | expect_journal_get_tag_tid(mock_journal, 346); |
789 | expect_journal_get_tag_data(mock_journal, | |
790 | {librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
791 | librbd::Journal<>::LOCAL_MIRROR_UUID, | |
792 | true, 345, 1}); | |
793 | ||
7c673cae FG |
794 | // remote demotion / promotion event |
795 | Tags tags = { | |
796 | {2, 123, encode_tag_data({"local mirror uuid", "local mirror uuid", | |
797 | true, 344, 99})}, | |
798 | {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
799 | "local mirror uuid", true, 345, 1})}, | |
800 | {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID, | |
801 | librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
802 | true, 3, 1})} | |
803 | }; | |
804 | expect_journaler_get_tags(mock_journaler, 123, tags, 0); | |
7c673cae FG |
805 | |
806 | MockCloseImageRequest mock_close_image_request; | |
807 | expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0); | |
808 | ||
809 | C_SaferCond ctx; | |
11fdf7f2 | 810 | MockThreads mock_threads(m_threads); |
31f18b77 | 811 | MockInstanceWatcher mock_instance_watcher; |
b32b8144 FG |
812 | cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED; |
813 | librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{ | |
814 | mock_local_image_ctx.id}; | |
815 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; | |
7c673cae | 816 | MockBootstrapRequest *request = create_request( |
11fdf7f2 TL |
817 | &mock_threads, &mock_instance_watcher, mock_journaler, |
818 | mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id", | |
819 | "local mirror uuid", "remote mirror uuid", &client_state, | |
820 | &mirror_peer_client_meta, &ctx); | |
7c673cae FG |
821 | request->send(); |
822 | ASSERT_EQ(0, ctx.wait()); | |
823 | } | |
824 | ||
825 | TEST_F(TestMockImageReplayerBootstrapRequest, SplitBrainForcePromote) { | |
826 | create_local_image(); | |
827 | ||
828 | InSequence seq; | |
829 | ||
830 | // lookup remote image tag class | |
831 | cls::journal::Client client; | |
832 | librbd::journal::ClientData client_data{ | |
833 | librbd::journal::ImageClientMeta{123}}; | |
11fdf7f2 | 834 | encode(client_data, client.data); |
7c673cae FG |
835 | ::journal::MockJournaler mock_journaler; |
836 | expect_journaler_get_client(mock_journaler, | |
837 | librbd::Journal<>::IMAGE_CLIENT_ID, | |
838 | client, 0); | |
839 | ||
d2e6a577 FG |
840 | // open the remote image |
841 | librbd::MockJournal mock_journal; | |
842 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
843 | MockOpenImageRequest mock_open_image_request; | |
844 | expect_open_image(mock_open_image_request, m_remote_io_ctx, | |
845 | mock_remote_image_ctx.id, mock_remote_image_ctx, 0); | |
846 | ||
d2e6a577 | 847 | // test if remote image is primary |
7c673cae FG |
848 | MockIsPrimaryRequest mock_is_primary_request; |
849 | expect_is_primary(mock_is_primary_request, true, 0); | |
850 | ||
851 | // open the local image | |
b32b8144 | 852 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); |
7c673cae FG |
853 | mock_local_image_ctx.journal = &mock_journal; |
854 | MockOpenLocalImageRequest mock_open_local_image_request; | |
855 | expect_open_local_image(mock_open_local_image_request, m_local_io_ctx, | |
856 | mock_local_image_ctx.id, &mock_local_image_ctx, 0); | |
857 | expect_is_resync_requested(mock_journal, false, 0); | |
858 | ||
28e407b8 AA |
859 | expect_journal_get_tag_tid(mock_journal, 345); |
860 | expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::LOCAL_MIRROR_UUID, | |
861 | librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
862 | true, 344, 0}); | |
863 | ||
7c673cae FG |
864 | // remote demotion / promotion event |
865 | Tags tags = { | |
866 | {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID, | |
867 | librbd::Journal<>::LOCAL_MIRROR_UUID, | |
868 | true, 1, 99})}, | |
869 | {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID, | |
870 | librbd::Journal<>::LOCAL_MIRROR_UUID, | |
871 | true, 2, 1})} | |
872 | }; | |
873 | expect_journaler_get_tags(mock_journaler, 123, tags, 0); | |
7c673cae FG |
874 | |
875 | MockCloseImageRequest mock_close_image_request; | |
876 | expect_close_image(mock_close_image_request, mock_local_image_ctx, 0); | |
877 | expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0); | |
878 | ||
879 | C_SaferCond ctx; | |
11fdf7f2 | 880 | MockThreads mock_threads(m_threads); |
31f18b77 | 881 | MockInstanceWatcher mock_instance_watcher; |
b32b8144 FG |
882 | cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED; |
883 | librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{ | |
884 | mock_local_image_ctx.id}; | |
885 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; | |
7c673cae | 886 | MockBootstrapRequest *request = create_request( |
11fdf7f2 TL |
887 | &mock_threads, &mock_instance_watcher, mock_journaler, |
888 | mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id", | |
889 | "local mirror uuid", "remote mirror uuid", &client_state, | |
890 | &mirror_peer_client_meta, &ctx); | |
7c673cae FG |
891 | request->send(); |
892 | ASSERT_EQ(-EEXIST, ctx.wait()); | |
893 | ASSERT_EQ(NULL, m_local_test_image_ctx); | |
894 | } | |
895 | ||
896 | TEST_F(TestMockImageReplayerBootstrapRequest, ResyncRequested) { | |
897 | create_local_image(); | |
898 | ||
899 | InSequence seq; | |
900 | ||
901 | // lookup remote image tag class | |
902 | cls::journal::Client client; | |
903 | librbd::journal::ClientData client_data{ | |
904 | librbd::journal::ImageClientMeta{123}}; | |
11fdf7f2 | 905 | encode(client_data, client.data); |
7c673cae FG |
906 | ::journal::MockJournaler mock_journaler; |
907 | expect_journaler_get_client(mock_journaler, | |
908 | librbd::Journal<>::IMAGE_CLIENT_ID, | |
909 | client, 0); | |
910 | ||
d2e6a577 FG |
911 | // open the remote image |
912 | librbd::MockJournal mock_journal; | |
913 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
914 | MockOpenImageRequest mock_open_image_request; | |
915 | expect_open_image(mock_open_image_request, m_remote_io_ctx, | |
916 | mock_remote_image_ctx.id, mock_remote_image_ctx, 0); | |
917 | ||
d2e6a577 | 918 | // test if remote image is primary |
7c673cae FG |
919 | MockIsPrimaryRequest mock_is_primary_request; |
920 | expect_is_primary(mock_is_primary_request, true, 0); | |
921 | ||
922 | // open the local image | |
b32b8144 | 923 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); |
7c673cae FG |
924 | mock_local_image_ctx.journal = &mock_journal; |
925 | MockOpenLocalImageRequest mock_open_local_image_request; | |
926 | expect_open_local_image(mock_open_local_image_request, m_local_io_ctx, | |
927 | mock_local_image_ctx.id, &mock_local_image_ctx, 0); | |
928 | ||
929 | // resync is requested | |
930 | expect_is_resync_requested(mock_journal, true, 0); | |
931 | ||
28e407b8 AA |
932 | expect_journal_get_tag_tid(mock_journal, 345); |
933 | expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"}); | |
7c673cae FG |
934 | |
935 | MockCloseImageRequest mock_close_image_request; | |
936 | expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0); | |
937 | ||
938 | C_SaferCond ctx; | |
11fdf7f2 | 939 | MockThreads mock_threads(m_threads); |
31f18b77 | 940 | MockInstanceWatcher mock_instance_watcher; |
b32b8144 FG |
941 | cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED; |
942 | librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{ | |
943 | mock_local_image_ctx.id}; | |
944 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; | |
7c673cae | 945 | MockBootstrapRequest *request = create_request( |
11fdf7f2 TL |
946 | &mock_threads, &mock_instance_watcher, mock_journaler, |
947 | mock_local_image_ctx.id, mock_remote_image_ctx.id, "global image id", | |
948 | "local mirror uuid", "remote mirror uuid", &client_state, | |
949 | &mirror_peer_client_meta, &ctx); | |
7c673cae FG |
950 | m_do_resync = false; |
951 | request->send(); | |
952 | ASSERT_EQ(0, ctx.wait()); | |
953 | ASSERT_TRUE(m_do_resync); | |
954 | } | |
955 | ||
956 | TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemote) { | |
957 | create_local_image(); | |
958 | ||
959 | InSequence seq; | |
960 | ||
961 | // lookup remote image tag class | |
962 | cls::journal::Client client; | |
963 | librbd::journal::ClientData client_data{ | |
964 | librbd::journal::ImageClientMeta{123}}; | |
11fdf7f2 | 965 | encode(client_data, client.data); |
7c673cae FG |
966 | ::journal::MockJournaler mock_journaler; |
967 | expect_journaler_get_client(mock_journaler, | |
968 | librbd::Journal<>::IMAGE_CLIENT_ID, | |
969 | client, 0); | |
970 | ||
d2e6a577 FG |
971 | // open the remote image |
972 | librbd::MockJournal mock_journal; | |
973 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
974 | MockOpenImageRequest mock_open_image_request; | |
975 | expect_open_image(mock_open_image_request, m_remote_io_ctx, | |
976 | mock_remote_image_ctx.id, mock_remote_image_ctx, 0); | |
977 | ||
d2e6a577 | 978 | // test if remote image is primary |
7c673cae FG |
979 | MockIsPrimaryRequest mock_is_primary_request; |
980 | expect_is_primary(mock_is_primary_request, true, 0); | |
981 | ||
d2e6a577 | 982 | // update client state back to syncing |
7c673cae FG |
983 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); |
984 | mock_local_image_ctx.journal = &mock_journal; | |
985 | ||
d2e6a577 | 986 | librbd::util::s_image_id = mock_local_image_ctx.id; |
b32b8144 FG |
987 | librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta; |
988 | mirror_peer_client_meta.image_id = mock_local_image_ctx.id; | |
d2e6a577 FG |
989 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING; |
990 | client_data.client_meta = mirror_peer_client_meta; | |
991 | client.data.clear(); | |
11fdf7f2 | 992 | encode(client_data, client.data); |
d2e6a577 FG |
993 | expect_journaler_update_client(mock_journaler, client_data, 0); |
994 | ||
995 | // create the local image | |
7c673cae FG |
996 | MockCreateImageRequest mock_create_image_request; |
997 | expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0); | |
998 | ||
999 | // open the local image | |
1000 | MockOpenLocalImageRequest mock_open_local_image_request; | |
1001 | expect_open_local_image(mock_open_local_image_request, m_local_io_ctx, | |
1002 | mock_local_image_ctx.id, &mock_local_image_ctx, 0); | |
1003 | expect_is_resync_requested(mock_journal, false, 0); | |
1004 | ||
28e407b8 AA |
1005 | expect_journal_get_tag_tid(mock_journal, 345); |
1006 | expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"}); | |
1007 | ||
7c673cae | 1008 | // sync the remote image to the local image |
31f18b77 FG |
1009 | MockImageSync mock_image_sync; |
1010 | expect_image_sync(mock_image_sync, 0); | |
7c673cae FG |
1011 | |
1012 | MockCloseImageRequest mock_close_image_request; | |
1013 | expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0); | |
1014 | ||
1015 | C_SaferCond ctx; | |
11fdf7f2 | 1016 | MockThreads mock_threads(m_threads); |
31f18b77 | 1017 | MockInstanceWatcher mock_instance_watcher; |
b32b8144 FG |
1018 | cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED; |
1019 | mirror_peer_client_meta.image_id = ""; | |
1020 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; | |
7c673cae | 1021 | MockBootstrapRequest *request = create_request( |
11fdf7f2 | 1022 | &mock_threads, &mock_instance_watcher, mock_journaler, "", |
7c673cae | 1023 | mock_remote_image_ctx.id, "global image id", "local mirror uuid", |
b32b8144 | 1024 | "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx); |
7c673cae FG |
1025 | request->send(); |
1026 | ASSERT_EQ(0, ctx.wait()); | |
1027 | } | |
1028 | ||
1029 | TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) { | |
1030 | create_local_image(); | |
1031 | ||
1032 | InSequence seq; | |
1033 | ||
1034 | // lookup remote image tag class | |
1035 | cls::journal::Client client; | |
1036 | librbd::journal::ClientData client_data{ | |
1037 | librbd::journal::ImageClientMeta{123}}; | |
11fdf7f2 | 1038 | encode(client_data, client.data); |
7c673cae FG |
1039 | ::journal::MockJournaler mock_journaler; |
1040 | expect_journaler_get_client(mock_journaler, | |
1041 | librbd::Journal<>::IMAGE_CLIENT_ID, | |
1042 | client, 0); | |
1043 | ||
d2e6a577 FG |
1044 | // open the remote image |
1045 | librbd::MockJournal mock_journal; | |
1046 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
1047 | MockOpenImageRequest mock_open_image_request; | |
1048 | expect_open_image(mock_open_image_request, m_remote_io_ctx, | |
1049 | mock_remote_image_ctx.id, mock_remote_image_ctx, 0); | |
1050 | ||
d2e6a577 | 1051 | // test if remote image is primary |
7c673cae FG |
1052 | MockIsPrimaryRequest mock_is_primary_request; |
1053 | expect_is_primary(mock_is_primary_request, true, 0); | |
1054 | ||
1055 | // open the missing local image | |
1056 | MockOpenLocalImageRequest mock_open_local_image_request; | |
1057 | expect_open_local_image(mock_open_local_image_request, m_local_io_ctx, | |
1058 | "missing image id", nullptr, -ENOENT); | |
1059 | ||
d2e6a577 FG |
1060 | // re-register the client |
1061 | expect_journaler_unregister_client(mock_journaler, 0); | |
b32b8144 FG |
1062 | librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta; |
1063 | mirror_peer_client_meta.image_id = ""; | |
3efd9988 | 1064 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; |
d2e6a577 FG |
1065 | client_data.client_meta = mirror_peer_client_meta; |
1066 | expect_journaler_register_client(mock_journaler, client_data, 0); | |
1067 | ||
1068 | // test if remote image is primary | |
1069 | expect_is_primary(mock_is_primary_request, true, 0); | |
1070 | ||
1071 | // update client state back to syncing | |
7c673cae FG |
1072 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); |
1073 | mock_local_image_ctx.journal = &mock_journal; | |
1074 | ||
d2e6a577 | 1075 | librbd::util::s_image_id = mock_local_image_ctx.id; |
b32b8144 | 1076 | mirror_peer_client_meta.image_id = mock_local_image_ctx.id; |
d2e6a577 FG |
1077 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING; |
1078 | client_data.client_meta = mirror_peer_client_meta; | |
1079 | client.data.clear(); | |
11fdf7f2 | 1080 | encode(client_data, client.data); |
d2e6a577 FG |
1081 | expect_journaler_update_client(mock_journaler, client_data, 0); |
1082 | ||
1083 | // create the missing local image | |
7c673cae FG |
1084 | MockCreateImageRequest mock_create_image_request; |
1085 | expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0); | |
1086 | ||
1087 | // open the local image | |
1088 | expect_open_local_image(mock_open_local_image_request, m_local_io_ctx, | |
1089 | mock_local_image_ctx.id, &mock_local_image_ctx, 0); | |
1090 | expect_is_resync_requested(mock_journal, false, 0); | |
1091 | ||
28e407b8 AA |
1092 | expect_journal_get_tag_tid(mock_journal, 345); |
1093 | expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"}); | |
1094 | ||
7c673cae | 1095 | // sync the remote image to the local image |
31f18b77 FG |
1096 | MockImageSync mock_image_sync; |
1097 | expect_image_sync(mock_image_sync, 0); | |
7c673cae FG |
1098 | |
1099 | MockCloseImageRequest mock_close_image_request; | |
1100 | expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0); | |
1101 | ||
1102 | C_SaferCond ctx; | |
11fdf7f2 | 1103 | MockThreads mock_threads(m_threads); |
31f18b77 | 1104 | MockInstanceWatcher mock_instance_watcher; |
b32b8144 FG |
1105 | cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED; |
1106 | mirror_peer_client_meta.image_id = "missing image id"; | |
1107 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; | |
7c673cae | 1108 | MockBootstrapRequest *request = create_request( |
11fdf7f2 TL |
1109 | &mock_threads, &mock_instance_watcher, mock_journaler, "missing image id", |
1110 | mock_remote_image_ctx.id, "global image id", "local mirror uuid", | |
1111 | "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx); | |
1112 | request->send(); | |
1113 | ASSERT_EQ(0, ctx.wait()); | |
1114 | } | |
1115 | ||
1116 | TEST_F(TestMockImageReplayerBootstrapRequest, LocalImageIdCollision) { | |
1117 | create_local_image(); | |
1118 | ||
1119 | InSequence seq; | |
1120 | ||
1121 | // lookup remote image tag class | |
1122 | cls::journal::Client client; | |
1123 | librbd::journal::ClientData client_data{ | |
1124 | librbd::journal::ImageClientMeta{123}}; | |
1125 | encode(client_data, client.data); | |
1126 | ::journal::MockJournaler mock_journaler; | |
1127 | expect_journaler_get_client(mock_journaler, | |
1128 | librbd::Journal<>::IMAGE_CLIENT_ID, | |
1129 | client, 0); | |
1130 | ||
1131 | // open the remote image | |
1132 | librbd::MockJournal mock_journal; | |
1133 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
1134 | MockOpenImageRequest mock_open_image_request; | |
1135 | expect_open_image(mock_open_image_request, m_remote_io_ctx, | |
1136 | mock_remote_image_ctx.id, mock_remote_image_ctx, 0); | |
1137 | ||
1138 | // test if remote image is primary | |
1139 | MockIsPrimaryRequest mock_is_primary_request; | |
1140 | expect_is_primary(mock_is_primary_request, true, 0); | |
1141 | ||
1142 | // update client state back to syncing | |
1143 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
1144 | mock_local_image_ctx.journal = &mock_journal; | |
1145 | ||
1146 | librbd::util::s_image_id = mock_local_image_ctx.id; | |
1147 | librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta; | |
1148 | mirror_peer_client_meta.image_id = mock_local_image_ctx.id; | |
1149 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING; | |
1150 | client_data.client_meta = mirror_peer_client_meta; | |
1151 | client.data.clear(); | |
1152 | encode(client_data, client.data); | |
1153 | expect_journaler_update_client(mock_journaler, client_data, 0); | |
1154 | ||
1155 | // create the local image | |
1156 | MockCreateImageRequest mock_create_image_request; | |
1157 | expect_create_image(mock_create_image_request, mock_local_image_ctx.id, | |
1158 | -EBADF); | |
1159 | ||
1160 | expect_journaler_update_client(mock_journaler, client_data, 0); | |
1161 | expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0); | |
1162 | ||
1163 | // open the local image | |
1164 | MockOpenLocalImageRequest mock_open_local_image_request; | |
1165 | expect_open_local_image(mock_open_local_image_request, m_local_io_ctx, | |
1166 | mock_local_image_ctx.id, &mock_local_image_ctx, 0); | |
1167 | expect_is_resync_requested(mock_journal, false, 0); | |
1168 | ||
1169 | expect_journal_get_tag_tid(mock_journal, 345); | |
1170 | expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"}); | |
1171 | ||
1172 | // sync the remote image to the local image | |
1173 | MockImageSync mock_image_sync; | |
1174 | expect_image_sync(mock_image_sync, 0); | |
1175 | ||
1176 | MockCloseImageRequest mock_close_image_request; | |
1177 | expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0); | |
1178 | ||
1179 | C_SaferCond ctx; | |
1180 | MockThreads mock_threads(m_threads); | |
1181 | MockInstanceWatcher mock_instance_watcher; | |
1182 | cls::journal::ClientState client_state = cls::journal::CLIENT_STATE_CONNECTED; | |
1183 | mirror_peer_client_meta.image_id = ""; | |
1184 | mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING; | |
1185 | MockBootstrapRequest *request = create_request( | |
1186 | &mock_threads, &mock_instance_watcher, mock_journaler, "", | |
7c673cae | 1187 | mock_remote_image_ctx.id, "global image id", "local mirror uuid", |
b32b8144 | 1188 | "remote mirror uuid", &client_state, &mirror_peer_client_meta, &ctx); |
7c673cae FG |
1189 | request->send(); |
1190 | ASSERT_EQ(0, ctx.wait()); | |
1191 | } | |
1192 | ||
1193 | } // namespace image_replayer | |
1194 | } // namespace mirror | |
1195 | } // namespace rbd |