]>
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 "include/rbd/librbd.hpp" | |
6 | #include "librbd/ImageCtx.h" | |
7 | #include "librbd/ImageState.h" | |
8 | #include "librbd/Operations.h" | |
9 | #include "librbd/journal/TypeTraits.h" | |
10 | #include "test/journal/mock/MockJournaler.h" | |
11 | #include "test/librados_test_stub/MockTestMemIoCtxImpl.h" | |
12 | #include "test/librbd/mock/MockImageCtx.h" | |
13 | #include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.h" | |
14 | #include "tools/rbd_mirror/image_sync/SnapshotCreateRequest.h" | |
15 | #include "tools/rbd_mirror/Threads.h" | |
16 | ||
17 | namespace librbd { | |
18 | ||
19 | namespace { | |
20 | ||
21 | struct MockTestImageCtx : public librbd::MockImageCtx { | |
22 | MockTestImageCtx(librbd::ImageCtx &image_ctx) | |
23 | : librbd::MockImageCtx(image_ctx) { | |
24 | } | |
25 | }; | |
26 | ||
27 | } // anonymous namespace | |
28 | ||
29 | namespace journal { | |
30 | ||
31 | template <> | |
32 | struct TypeTraits<librbd::MockTestImageCtx> { | |
33 | typedef ::journal::MockJournaler Journaler; | |
34 | }; | |
35 | ||
36 | } // namespace journal | |
37 | } // namespace librbd | |
38 | ||
39 | namespace rbd { | |
40 | namespace mirror { | |
41 | namespace image_sync { | |
42 | ||
43 | template <> | |
44 | struct SnapshotCreateRequest<librbd::MockTestImageCtx> { | |
45 | static SnapshotCreateRequest* s_instance; | |
46 | static SnapshotCreateRequest* create(librbd::MockTestImageCtx* image_ctx, | |
47 | const std::string &snap_name, | |
48 | const cls::rbd::SnapshotNamespace &snap_namespace, | |
49 | uint64_t size, | |
50 | const librbd::ParentSpec &parent_spec, | |
51 | uint64_t parent_overlap, | |
52 | Context *on_finish) { | |
53 | assert(s_instance != nullptr); | |
54 | s_instance->on_finish = on_finish; | |
55 | return s_instance; | |
56 | } | |
57 | ||
58 | Context *on_finish = nullptr; | |
59 | ||
60 | SnapshotCreateRequest() { | |
61 | s_instance = this; | |
62 | } | |
63 | ||
64 | MOCK_METHOD0(send, void()); | |
65 | }; | |
66 | ||
67 | SnapshotCreateRequest<librbd::MockTestImageCtx>* SnapshotCreateRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
68 | ||
69 | } // namespace image_sync | |
70 | } // namespace mirror | |
71 | } // namespace rbd | |
72 | ||
73 | // template definitions | |
74 | #include "tools/rbd_mirror/image_sync/SnapshotCopyRequest.cc" | |
75 | template class rbd::mirror::image_sync::SnapshotCopyRequest<librbd::MockTestImageCtx>; | |
76 | ||
77 | namespace rbd { | |
78 | namespace mirror { | |
79 | namespace image_sync { | |
80 | ||
81 | using ::testing::_; | |
82 | using ::testing::DoAll; | |
83 | using ::testing::DoDefault; | |
84 | using ::testing::InSequence; | |
85 | using ::testing::Invoke; | |
86 | using ::testing::InvokeWithoutArgs; | |
87 | using ::testing::Return; | |
31f18b77 | 88 | using ::testing::ReturnNew; |
7c673cae FG |
89 | using ::testing::SetArgPointee; |
90 | using ::testing::StrEq; | |
91 | using ::testing::WithArg; | |
92 | ||
93 | class TestMockImageSyncSnapshotCopyRequest : public TestMockFixture { | |
94 | public: | |
95 | typedef SnapshotCopyRequest<librbd::MockTestImageCtx> MockSnapshotCopyRequest; | |
96 | typedef SnapshotCreateRequest<librbd::MockTestImageCtx> MockSnapshotCreateRequest; | |
97 | ||
98 | void SetUp() override { | |
99 | TestMockFixture::SetUp(); | |
100 | ||
101 | librbd::RBD rbd; | |
102 | ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size)); | |
103 | ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx)); | |
104 | ||
105 | ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size)); | |
106 | ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx)); | |
107 | } | |
108 | ||
31f18b77 FG |
109 | void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) { |
110 | EXPECT_CALL(mock_exclusive_lock, start_op()).WillOnce( | |
111 | ReturnNew<FunctionContext>([](int) {})); | |
112 | } | |
113 | ||
7c673cae FG |
114 | void expect_get_snap_namespace(librbd::MockTestImageCtx &mock_image_ctx, |
115 | uint64_t snap_id) { | |
116 | EXPECT_CALL(mock_image_ctx, get_snap_namespace(snap_id, _)) | |
117 | .WillOnce(DoAll(SetArgPointee<1>(cls::rbd::UserSnapshotNamespace()), | |
118 | Return(0))); | |
119 | } | |
120 | ||
121 | void expect_snap_create(librbd::MockTestImageCtx &mock_image_ctx, | |
122 | MockSnapshotCreateRequest &mock_snapshot_create_request, | |
123 | const std::string &snap_name, uint64_t snap_id, int r) { | |
124 | EXPECT_CALL(mock_snapshot_create_request, send()) | |
125 | .WillOnce(DoAll(Invoke([&mock_image_ctx, snap_id, snap_name]() { | |
126 | inject_snap(mock_image_ctx, snap_id, snap_name); | |
127 | }), | |
128 | Invoke([this, &mock_snapshot_create_request, r]() { | |
129 | m_threads->work_queue->queue(mock_snapshot_create_request.on_finish, r); | |
130 | }))); | |
131 | } | |
132 | ||
133 | void expect_snap_remove(librbd::MockTestImageCtx &mock_image_ctx, | |
134 | const std::string &snap_name, int r) { | |
135 | EXPECT_CALL(*mock_image_ctx.operations, execute_snap_remove(_, StrEq(snap_name), _)) | |
136 | .WillOnce(WithArg<2>(Invoke([this, r](Context *ctx) { | |
137 | m_threads->work_queue->queue(ctx, r); | |
138 | }))); | |
139 | } | |
140 | ||
141 | void expect_snap_protect(librbd::MockTestImageCtx &mock_image_ctx, | |
142 | const std::string &snap_name, int r) { | |
143 | EXPECT_CALL(*mock_image_ctx.operations, execute_snap_protect(_, StrEq(snap_name), _)) | |
144 | .WillOnce(WithArg<2>(Invoke([this, r](Context *ctx) { | |
145 | m_threads->work_queue->queue(ctx, r); | |
146 | }))); | |
147 | } | |
148 | ||
149 | void expect_snap_unprotect(librbd::MockTestImageCtx &mock_image_ctx, | |
150 | const std::string &snap_name, int r) { | |
151 | EXPECT_CALL(*mock_image_ctx.operations, execute_snap_unprotect(_, StrEq(snap_name), _)) | |
152 | .WillOnce(WithArg<2>(Invoke([this, r](Context *ctx) { | |
153 | m_threads->work_queue->queue(ctx, r); | |
154 | }))); | |
155 | } | |
156 | ||
157 | void expect_snap_is_protected(librbd::MockTestImageCtx &mock_image_ctx, | |
158 | uint64_t snap_id, bool is_protected, int r) { | |
159 | EXPECT_CALL(mock_image_ctx, is_snap_protected(snap_id, _)) | |
160 | .WillOnce(DoAll(SetArgPointee<1>(is_protected), | |
161 | Return(r))); | |
162 | } | |
163 | ||
164 | void expect_snap_is_unprotected(librbd::MockTestImageCtx &mock_image_ctx, | |
165 | uint64_t snap_id, bool is_unprotected, int r) { | |
166 | EXPECT_CALL(mock_image_ctx, is_snap_unprotected(snap_id, _)) | |
167 | .WillOnce(DoAll(SetArgPointee<1>(is_unprotected), | |
168 | Return(r))); | |
169 | } | |
170 | ||
171 | void expect_update_client(journal::MockJournaler &mock_journaler, int r) { | |
172 | EXPECT_CALL(mock_journaler, update_client(_, _)) | |
173 | .WillOnce(WithArg<1>(CompleteContext(r))); | |
174 | } | |
175 | ||
176 | static void inject_snap(librbd::MockTestImageCtx &mock_image_ctx, | |
177 | uint64_t snap_id, const std::string &snap_name) { | |
178 | mock_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(), | |
179 | snap_name}] = snap_id; | |
180 | } | |
181 | ||
182 | MockSnapshotCopyRequest *create_request(librbd::MockTestImageCtx &mock_remote_image_ctx, | |
183 | librbd::MockTestImageCtx &mock_local_image_ctx, | |
184 | journal::MockJournaler &mock_journaler, | |
185 | Context *on_finish) { | |
186 | return new MockSnapshotCopyRequest(&mock_local_image_ctx, | |
187 | &mock_remote_image_ctx, &m_snap_map, | |
188 | &mock_journaler, &m_client_meta, | |
189 | m_threads->work_queue, on_finish); | |
190 | } | |
191 | ||
192 | int create_snap(librbd::ImageCtx *image_ctx, const std::string &snap_name, | |
193 | bool protect = false) { | |
194 | int r = image_ctx->operations->snap_create(cls::rbd::UserSnapshotNamespace(), | |
195 | snap_name.c_str()); | |
196 | if (r < 0) { | |
197 | return r; | |
198 | } | |
199 | ||
200 | if (protect) { | |
201 | r = image_ctx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(), | |
202 | snap_name.c_str()); | |
203 | if (r < 0) { | |
204 | return r; | |
205 | } | |
206 | } | |
207 | ||
208 | r = image_ctx->state->refresh(); | |
209 | if (r < 0) { | |
210 | return r; | |
211 | } | |
212 | return 0; | |
213 | } | |
214 | ||
215 | void validate_snap_seqs(const librbd::journal::MirrorPeerClientMeta::SnapSeqs &snap_seqs) { | |
216 | ASSERT_EQ(snap_seqs, m_client_meta.snap_seqs); | |
217 | } | |
218 | ||
219 | void validate_snap_map(const MockSnapshotCopyRequest::SnapMap &snap_map) { | |
220 | ASSERT_EQ(snap_map, m_snap_map); | |
221 | } | |
222 | ||
223 | librbd::ImageCtx *m_remote_image_ctx; | |
224 | librbd::ImageCtx *m_local_image_ctx; | |
225 | ||
226 | MockSnapshotCopyRequest::SnapMap m_snap_map; | |
227 | librbd::journal::MirrorPeerClientMeta m_client_meta; | |
228 | }; | |
229 | ||
230 | TEST_F(TestMockImageSyncSnapshotCopyRequest, Empty) { | |
231 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
232 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
233 | journal::MockJournaler mock_journaler; | |
234 | ||
31f18b77 FG |
235 | librbd::MockExclusiveLock mock_exclusive_lock; |
236 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
237 | ||
7c673cae FG |
238 | InSequence seq; |
239 | expect_update_client(mock_journaler, 0); | |
240 | ||
241 | C_SaferCond ctx; | |
242 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
243 | mock_local_image_ctx, | |
244 | mock_journaler, &ctx); | |
245 | request->send(); | |
246 | ASSERT_EQ(0, ctx.wait()); | |
247 | ||
248 | validate_snap_map({}); | |
249 | validate_snap_seqs({}); | |
250 | } | |
251 | ||
252 | TEST_F(TestMockImageSyncSnapshotCopyRequest, UpdateClientError) { | |
253 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
254 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
255 | journal::MockJournaler mock_journaler; | |
256 | ||
31f18b77 FG |
257 | librbd::MockExclusiveLock mock_exclusive_lock; |
258 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
259 | ||
7c673cae FG |
260 | InSequence seq; |
261 | expect_update_client(mock_journaler, -EINVAL); | |
262 | ||
263 | C_SaferCond ctx; | |
264 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
265 | mock_local_image_ctx, | |
266 | mock_journaler, &ctx); | |
267 | request->send(); | |
268 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
269 | } | |
270 | ||
271 | TEST_F(TestMockImageSyncSnapshotCopyRequest, UpdateClientCancel) { | |
272 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
273 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
274 | journal::MockJournaler mock_journaler; | |
275 | ||
31f18b77 FG |
276 | librbd::MockExclusiveLock mock_exclusive_lock; |
277 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
278 | ||
7c673cae FG |
279 | C_SaferCond ctx; |
280 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
281 | mock_local_image_ctx, | |
282 | mock_journaler, &ctx); | |
283 | InSequence seq; | |
284 | EXPECT_CALL(mock_journaler, update_client(_, _)) | |
285 | .WillOnce(DoAll(InvokeWithoutArgs([request]() { | |
286 | request->cancel(); | |
287 | }), | |
288 | WithArg<1>(CompleteContext(0)))); | |
289 | ||
290 | request->send(); | |
291 | ASSERT_EQ(-ECANCELED, ctx.wait()); | |
292 | } | |
293 | ||
294 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapCreate) { | |
295 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1")); | |
296 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap2")); | |
297 | ||
31f18b77 FG |
298 | uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ |
299 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
300 | uint64_t remote_snap_id2 = m_remote_image_ctx->snap_ids[ | |
301 | {cls::rbd::UserSnapshotNamespace(), "snap2"}]; | |
7c673cae FG |
302 | |
303 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
304 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
305 | MockSnapshotCreateRequest mock_snapshot_create_request; | |
306 | journal::MockJournaler mock_journaler; | |
307 | ||
31f18b77 FG |
308 | librbd::MockExclusiveLock mock_exclusive_lock; |
309 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
310 | ||
7c673cae FG |
311 | InSequence seq; |
312 | expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); | |
31f18b77 | 313 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
314 | expect_snap_create(mock_local_image_ctx, mock_snapshot_create_request, "snap1", 12, 0); |
315 | expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id2); | |
31f18b77 | 316 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
317 | expect_snap_create(mock_local_image_ctx, mock_snapshot_create_request, "snap2", 14, 0); |
318 | expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, false, 0); | |
319 | expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id2, false, 0); | |
320 | expect_update_client(mock_journaler, 0); | |
321 | ||
322 | C_SaferCond ctx; | |
323 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
324 | mock_local_image_ctx, | |
325 | mock_journaler, &ctx); | |
326 | request->send(); | |
327 | ASSERT_EQ(0, ctx.wait()); | |
328 | ||
329 | validate_snap_map({{remote_snap_id1, {12}}, {remote_snap_id2, {14, 12}}}); | |
330 | validate_snap_seqs({{remote_snap_id1, 12}, {remote_snap_id2, 14}}); | |
331 | } | |
332 | ||
333 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapCreateError) { | |
334 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1")); | |
335 | ||
336 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
337 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
338 | MockSnapshotCreateRequest mock_snapshot_create_request; | |
339 | journal::MockJournaler mock_journaler; | |
340 | ||
31f18b77 FG |
341 | librbd::MockExclusiveLock mock_exclusive_lock; |
342 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
343 | ||
344 | uint64_t remote_snap_id1 = mock_remote_image_ctx.snap_ids[ | |
345 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
7c673cae FG |
346 | InSequence seq; |
347 | expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); | |
31f18b77 | 348 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
349 | expect_snap_create(mock_local_image_ctx, mock_snapshot_create_request, "snap1", 12, -EINVAL); |
350 | ||
351 | C_SaferCond ctx; | |
352 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
353 | mock_local_image_ctx, | |
354 | mock_journaler, &ctx); | |
355 | request->send(); | |
356 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
357 | } | |
358 | ||
359 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapCreateCancel) { | |
360 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1")); | |
361 | ||
362 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
363 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
364 | MockSnapshotCreateRequest mock_snapshot_create_request; | |
365 | journal::MockJournaler mock_journaler; | |
366 | ||
31f18b77 FG |
367 | librbd::MockExclusiveLock mock_exclusive_lock; |
368 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
369 | ||
370 | uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ | |
371 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
7c673cae FG |
372 | expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); |
373 | ||
374 | C_SaferCond ctx; | |
375 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
376 | mock_local_image_ctx, | |
377 | mock_journaler, &ctx); | |
378 | InSequence seq; | |
31f18b77 | 379 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
380 | EXPECT_CALL(mock_snapshot_create_request, send()) |
381 | .WillOnce(DoAll(InvokeWithoutArgs([request]() { | |
382 | request->cancel(); | |
383 | }), | |
384 | Invoke([this, &mock_snapshot_create_request]() { | |
385 | m_threads->work_queue->queue(mock_snapshot_create_request.on_finish, 0); | |
386 | }))); | |
387 | ||
388 | request->send(); | |
389 | ASSERT_EQ(-ECANCELED, ctx.wait()); | |
390 | } | |
391 | ||
392 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapRemoveAndCreate) { | |
393 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1")); | |
394 | ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1")); | |
395 | ||
31f18b77 FG |
396 | uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ |
397 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
398 | uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ | |
399 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
7c673cae FG |
400 | |
401 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
402 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
403 | MockSnapshotCreateRequest mock_snapshot_create_request; | |
404 | journal::MockJournaler mock_journaler; | |
405 | ||
31f18b77 FG |
406 | librbd::MockExclusiveLock mock_exclusive_lock; |
407 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
408 | ||
7c673cae FG |
409 | InSequence seq; |
410 | expect_snap_is_unprotected(mock_local_image_ctx, | |
31f18b77 FG |
411 | m_local_image_ctx->snap_ids[ |
412 | {cls::rbd::UserSnapshotNamespace(), "snap1"}], | |
413 | true, 0); | |
7c673cae | 414 | expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); |
31f18b77 | 415 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
416 | expect_snap_remove(mock_local_image_ctx, "snap1", 0); |
417 | expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); | |
31f18b77 | 418 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
419 | expect_snap_create(mock_local_image_ctx, mock_snapshot_create_request, "snap1", 12, 0); |
420 | expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, false, 0); | |
421 | expect_update_client(mock_journaler, 0); | |
422 | ||
423 | C_SaferCond ctx; | |
424 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
425 | mock_local_image_ctx, | |
426 | mock_journaler, &ctx); | |
427 | request->send(); | |
428 | ASSERT_EQ(0, ctx.wait()); | |
429 | ||
430 | validate_snap_map({{remote_snap_id1, {12}}}); | |
431 | validate_snap_seqs({{remote_snap_id1, 12}}); | |
432 | } | |
433 | ||
434 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapRemoveError) { | |
435 | ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1")); | |
436 | ||
437 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
438 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
439 | journal::MockJournaler mock_journaler; | |
440 | ||
31f18b77 FG |
441 | librbd::MockExclusiveLock mock_exclusive_lock; |
442 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
443 | ||
444 | uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ | |
445 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
7c673cae FG |
446 | InSequence seq; |
447 | expect_snap_is_unprotected(mock_local_image_ctx, | |
31f18b77 FG |
448 | m_local_image_ctx->snap_ids[ |
449 | {cls::rbd::UserSnapshotNamespace(), "snap1"}], | |
450 | true, 0); | |
7c673cae | 451 | expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); |
31f18b77 | 452 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
453 | expect_snap_remove(mock_local_image_ctx, "snap1", -EINVAL); |
454 | ||
455 | C_SaferCond ctx; | |
456 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
457 | mock_local_image_ctx, | |
458 | mock_journaler, &ctx); | |
459 | request->send(); | |
460 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
461 | } | |
462 | ||
463 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapUnprotect) { | |
464 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); | |
465 | ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); | |
466 | ||
31f18b77 FG |
467 | uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ |
468 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
469 | uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ | |
470 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
7c673cae FG |
471 | m_client_meta.snap_seqs[remote_snap_id1] = local_snap_id1; |
472 | ||
473 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
474 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
475 | journal::MockJournaler mock_journaler; | |
476 | ||
31f18b77 FG |
477 | librbd::MockExclusiveLock mock_exclusive_lock; |
478 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
479 | ||
7c673cae FG |
480 | InSequence seq; |
481 | expect_snap_is_unprotected(mock_local_image_ctx, local_snap_id1, false, 0); | |
482 | expect_snap_is_unprotected(mock_remote_image_ctx, remote_snap_id1, true, 0); | |
31f18b77 | 483 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
484 | expect_snap_unprotect(mock_local_image_ctx, "snap1", 0); |
485 | expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); | |
486 | expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); | |
487 | expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, false, 0); | |
488 | expect_update_client(mock_journaler, 0); | |
489 | ||
490 | C_SaferCond ctx; | |
491 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
492 | mock_local_image_ctx, | |
493 | mock_journaler, &ctx); | |
494 | request->send(); | |
495 | ASSERT_EQ(0, ctx.wait()); | |
496 | ||
497 | validate_snap_map({{remote_snap_id1, {local_snap_id1}}}); | |
498 | validate_snap_seqs({{remote_snap_id1, local_snap_id1}}); | |
499 | } | |
500 | ||
501 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapUnprotectError) { | |
502 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); | |
503 | ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); | |
504 | ||
31f18b77 FG |
505 | uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ |
506 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
507 | uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ | |
508 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
7c673cae FG |
509 | m_client_meta.snap_seqs[remote_snap_id1] = local_snap_id1; |
510 | ||
511 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
512 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
513 | journal::MockJournaler mock_journaler; | |
514 | ||
31f18b77 FG |
515 | librbd::MockExclusiveLock mock_exclusive_lock; |
516 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
517 | ||
7c673cae FG |
518 | InSequence seq; |
519 | expect_snap_is_unprotected(mock_local_image_ctx, local_snap_id1, false, 0); | |
520 | expect_snap_is_unprotected(mock_remote_image_ctx, remote_snap_id1, true, 0); | |
31f18b77 | 521 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
522 | expect_snap_unprotect(mock_local_image_ctx, "snap1", -EBUSY); |
523 | ||
524 | C_SaferCond ctx; | |
525 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
526 | mock_local_image_ctx, | |
527 | mock_journaler, &ctx); | |
528 | request->send(); | |
529 | ASSERT_EQ(-EBUSY, ctx.wait()); | |
530 | } | |
531 | ||
532 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapUnprotectCancel) { | |
533 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); | |
534 | ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); | |
535 | ||
31f18b77 FG |
536 | uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ |
537 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
538 | uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ | |
539 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
7c673cae FG |
540 | m_client_meta.snap_seqs[remote_snap_id1] = local_snap_id1; |
541 | ||
542 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
543 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
544 | journal::MockJournaler mock_journaler; | |
545 | ||
31f18b77 FG |
546 | librbd::MockExclusiveLock mock_exclusive_lock; |
547 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
548 | ||
7c673cae FG |
549 | C_SaferCond ctx; |
550 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
551 | mock_local_image_ctx, | |
552 | mock_journaler, &ctx); | |
553 | InSequence seq; | |
554 | expect_snap_is_unprotected(mock_local_image_ctx, local_snap_id1, false, 0); | |
555 | expect_snap_is_unprotected(mock_remote_image_ctx, remote_snap_id1, true, 0); | |
31f18b77 | 556 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
557 | EXPECT_CALL(*mock_local_image_ctx.operations, |
558 | execute_snap_unprotect(_, StrEq("snap1"), _)) | |
559 | .WillOnce(DoAll(InvokeWithoutArgs([request]() { | |
560 | request->cancel(); | |
561 | }), | |
562 | WithArg<2>(Invoke([this](Context *ctx) { | |
563 | m_threads->work_queue->queue(ctx, 0); | |
564 | })))); | |
565 | ||
566 | request->send(); | |
567 | ASSERT_EQ(-ECANCELED, ctx.wait()); | |
568 | } | |
569 | ||
570 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapUnprotectRemove) { | |
571 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); | |
572 | ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); | |
573 | ||
31f18b77 FG |
574 | uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ |
575 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
576 | uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ | |
577 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
7c673cae FG |
578 | |
579 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
580 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
581 | MockSnapshotCreateRequest mock_snapshot_create_request; | |
582 | journal::MockJournaler mock_journaler; | |
583 | ||
31f18b77 FG |
584 | librbd::MockExclusiveLock mock_exclusive_lock; |
585 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
586 | ||
7c673cae FG |
587 | InSequence seq; |
588 | expect_snap_is_unprotected(mock_local_image_ctx, | |
31f18b77 FG |
589 | m_local_image_ctx->snap_ids[ |
590 | {cls::rbd::UserSnapshotNamespace(), "snap1"}], | |
591 | false, 0); | |
592 | expect_start_op(mock_exclusive_lock); | |
7c673cae FG |
593 | expect_snap_unprotect(mock_local_image_ctx, "snap1", 0); |
594 | expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); | |
31f18b77 | 595 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
596 | expect_snap_remove(mock_local_image_ctx, "snap1", 0); |
597 | expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); | |
31f18b77 | 598 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
599 | expect_snap_create(mock_local_image_ctx, mock_snapshot_create_request, "snap1", 12, 0); |
600 | expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, false, 0); | |
601 | expect_update_client(mock_journaler, 0); | |
602 | ||
603 | C_SaferCond ctx; | |
604 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
605 | mock_local_image_ctx, | |
606 | mock_journaler, &ctx); | |
607 | request->send(); | |
608 | ASSERT_EQ(0, ctx.wait()); | |
609 | ||
610 | validate_snap_map({{remote_snap_id1, {12}}}); | |
611 | validate_snap_seqs({{remote_snap_id1, 12}}); | |
612 | } | |
613 | ||
614 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapCreateProtect) { | |
615 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); | |
616 | ||
31f18b77 FG |
617 | uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ |
618 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
7c673cae FG |
619 | |
620 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
621 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
622 | MockSnapshotCreateRequest mock_snapshot_create_request; | |
623 | journal::MockJournaler mock_journaler; | |
624 | ||
31f18b77 FG |
625 | librbd::MockExclusiveLock mock_exclusive_lock; |
626 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
627 | ||
7c673cae FG |
628 | InSequence seq; |
629 | expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); | |
31f18b77 | 630 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
631 | expect_snap_create(mock_local_image_ctx, mock_snapshot_create_request, "snap1", 12, 0); |
632 | expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, true, 0); | |
633 | expect_snap_is_protected(mock_local_image_ctx, 12, false, 0); | |
31f18b77 | 634 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
635 | expect_snap_protect(mock_local_image_ctx, "snap1", 0); |
636 | expect_update_client(mock_journaler, 0); | |
637 | ||
638 | C_SaferCond ctx; | |
639 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
640 | mock_local_image_ctx, | |
641 | mock_journaler, &ctx); | |
642 | request->send(); | |
643 | ASSERT_EQ(0, ctx.wait()); | |
644 | ||
645 | validate_snap_map({{remote_snap_id1, {12}}}); | |
646 | validate_snap_seqs({{remote_snap_id1, 12}}); | |
647 | } | |
648 | ||
649 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapProtect) { | |
650 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); | |
651 | ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); | |
652 | ||
31f18b77 FG |
653 | uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ |
654 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
655 | uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ | |
656 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
7c673cae FG |
657 | m_client_meta.snap_seqs[remote_snap_id1] = local_snap_id1; |
658 | ||
659 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
660 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
661 | journal::MockJournaler mock_journaler; | |
662 | ||
31f18b77 FG |
663 | librbd::MockExclusiveLock mock_exclusive_lock; |
664 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
665 | ||
7c673cae FG |
666 | InSequence seq; |
667 | expect_snap_is_unprotected(mock_local_image_ctx, local_snap_id1, true, 0); | |
668 | expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); | |
669 | expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); | |
670 | expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, true, 0); | |
671 | expect_snap_is_protected(mock_local_image_ctx, local_snap_id1, false, 0); | |
31f18b77 | 672 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
673 | expect_snap_protect(mock_local_image_ctx, "snap1", 0); |
674 | expect_update_client(mock_journaler, 0); | |
675 | ||
676 | C_SaferCond ctx; | |
677 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
678 | mock_local_image_ctx, | |
679 | mock_journaler, &ctx); | |
680 | request->send(); | |
681 | ASSERT_EQ(0, ctx.wait()); | |
682 | ||
683 | validate_snap_map({{remote_snap_id1, {local_snap_id1}}}); | |
684 | validate_snap_seqs({{remote_snap_id1, local_snap_id1}}); | |
685 | } | |
686 | ||
687 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapProtectError) { | |
688 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); | |
689 | ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); | |
690 | ||
31f18b77 FG |
691 | uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ |
692 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
693 | uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ | |
694 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
7c673cae FG |
695 | m_client_meta.snap_seqs[remote_snap_id1] = local_snap_id1; |
696 | ||
697 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
698 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
699 | journal::MockJournaler mock_journaler; | |
700 | ||
31f18b77 FG |
701 | librbd::MockExclusiveLock mock_exclusive_lock; |
702 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
703 | ||
7c673cae FG |
704 | InSequence seq; |
705 | expect_snap_is_unprotected(mock_local_image_ctx, local_snap_id1, true, 0); | |
706 | expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); | |
707 | expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); | |
708 | expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, true, 0); | |
709 | expect_snap_is_protected(mock_local_image_ctx, local_snap_id1, false, 0); | |
31f18b77 | 710 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
711 | expect_snap_protect(mock_local_image_ctx, "snap1", -EINVAL); |
712 | ||
713 | C_SaferCond ctx; | |
714 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
715 | mock_local_image_ctx, | |
716 | mock_journaler, &ctx); | |
717 | request->send(); | |
718 | ASSERT_EQ(-EINVAL, ctx.wait()); | |
719 | } | |
720 | ||
721 | TEST_F(TestMockImageSyncSnapshotCopyRequest, SnapProtectCancel) { | |
722 | ASSERT_EQ(0, create_snap(m_remote_image_ctx, "snap1", true)); | |
723 | ASSERT_EQ(0, create_snap(m_local_image_ctx, "snap1", true)); | |
724 | ||
31f18b77 FG |
725 | uint64_t remote_snap_id1 = m_remote_image_ctx->snap_ids[ |
726 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
727 | uint64_t local_snap_id1 = m_local_image_ctx->snap_ids[ | |
728 | {cls::rbd::UserSnapshotNamespace(), "snap1"}]; | |
7c673cae FG |
729 | m_client_meta.snap_seqs[remote_snap_id1] = local_snap_id1; |
730 | ||
731 | librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx); | |
732 | librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx); | |
733 | journal::MockJournaler mock_journaler; | |
734 | ||
31f18b77 FG |
735 | librbd::MockExclusiveLock mock_exclusive_lock; |
736 | mock_local_image_ctx.exclusive_lock = &mock_exclusive_lock; | |
737 | ||
7c673cae FG |
738 | C_SaferCond ctx; |
739 | MockSnapshotCopyRequest *request = create_request(mock_remote_image_ctx, | |
740 | mock_local_image_ctx, | |
741 | mock_journaler, &ctx); | |
742 | InSequence seq; | |
743 | expect_snap_is_unprotected(mock_local_image_ctx, local_snap_id1, true, 0); | |
744 | expect_get_snap_namespace(mock_local_image_ctx, local_snap_id1); | |
745 | expect_get_snap_namespace(mock_remote_image_ctx, remote_snap_id1); | |
746 | expect_snap_is_protected(mock_remote_image_ctx, remote_snap_id1, true, 0); | |
747 | expect_snap_is_protected(mock_local_image_ctx, local_snap_id1, false, 0); | |
31f18b77 | 748 | expect_start_op(mock_exclusive_lock); |
7c673cae FG |
749 | EXPECT_CALL(*mock_local_image_ctx.operations, |
750 | execute_snap_protect(_, StrEq("snap1"), _)) | |
751 | .WillOnce(DoAll(InvokeWithoutArgs([request]() { | |
752 | request->cancel(); | |
753 | }), | |
754 | WithArg<2>(Invoke([this](Context *ctx) { | |
755 | m_threads->work_queue->queue(ctx, 0); | |
756 | })))); | |
757 | ||
758 | request->send(); | |
759 | ASSERT_EQ(-ECANCELED, ctx.wait()); | |
760 | } | |
761 | ||
762 | } // namespace image_sync | |
763 | } // namespace mirror | |
764 | } // namespace rbd |