]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/mirror/snapshot/test_mock_CreateNonPrimaryRequest.cc
a92be03304ff5e943bd8b54281bfabdd86fdd1e4
[ceph.git] / ceph / src / test / librbd / mirror / snapshot / test_mock_CreateNonPrimaryRequest.cc
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/librbd/test_mock_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "test/librbd/mock/MockImageCtx.h"
7 #include "test/librbd/mock/MockOperations.h"
8 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
9 #include "test/librados_test_stub/MockTestMemRadosClient.h"
10 #include "librbd/mirror/snapshot/CreateNonPrimaryRequest.h"
11 #include "librbd/mirror/snapshot/Utils.h"
12 #include "librbd/mirror/snapshot/WriteImageStateRequest.h"
13
14 namespace librbd {
15
16 namespace {
17
18 struct MockTestImageCtx : public MockImageCtx {
19 explicit MockTestImageCtx(librbd::ImageCtx& image_ctx) : MockImageCtx(image_ctx) {
20 }
21 };
22
23 } // anonymous namespace
24
25 namespace mirror {
26 namespace snapshot {
27 namespace util {
28
29 namespace {
30
31 struct Mock {
32 static Mock* s_instance;
33
34 Mock() {
35 s_instance = this;
36 }
37
38 MOCK_METHOD1(can_create_non_primary_snapshot,
39 bool(librbd::MockTestImageCtx *));
40 };
41
42 Mock *Mock::s_instance = nullptr;
43
44 } // anonymous namespace
45
46 template<> bool can_create_non_primary_snapshot(
47 librbd::MockTestImageCtx *image_ctx) {
48 return Mock::s_instance->can_create_non_primary_snapshot(image_ctx);
49 }
50
51 } // namespace util
52
53 template <>
54 struct WriteImageStateRequest<MockTestImageCtx> {
55 uint64_t snap_id = CEPH_NOSNAP;
56 ImageState image_state;
57 Context* on_finish = nullptr;
58 static WriteImageStateRequest* s_instance;
59 static WriteImageStateRequest *create(MockTestImageCtx *image_ctx,
60 uint64_t snap_id,
61 const ImageState &image_state,
62 Context *on_finish) {
63 ceph_assert(s_instance != nullptr);
64 s_instance->snap_id = snap_id;
65 s_instance->image_state = image_state;
66 s_instance->on_finish = on_finish;
67 return s_instance;
68 }
69
70 MOCK_METHOD0(send, void());
71
72 WriteImageStateRequest() {
73 s_instance = this;
74 }
75 };
76
77 WriteImageStateRequest<MockTestImageCtx>* WriteImageStateRequest<MockTestImageCtx>::s_instance = nullptr;
78
79 } // namespace snapshot
80 } // namespace mirror
81 } // namespace librbd
82
83 // template definitions
84 #include "librbd/mirror/snapshot/CreateNonPrimaryRequest.cc"
85 template class librbd::mirror::snapshot::CreateNonPrimaryRequest<librbd::MockTestImageCtx>;
86
87 namespace librbd {
88 namespace mirror {
89 namespace snapshot {
90
91 using ::testing::_;
92 using ::testing::DoAll;
93 using ::testing::InSequence;
94 using ::testing::Invoke;
95 using ::testing::Return;
96 using ::testing::StrEq;
97 using ::testing::WithArg;
98
99 class TestMockMirrorSnapshotCreateNonPrimaryRequest : public TestMockFixture {
100 public:
101 typedef CreateNonPrimaryRequest<MockTestImageCtx> MockCreateNonPrimaryRequest;
102 typedef WriteImageStateRequest<MockTestImageCtx> MockWriteImageStateRequest;
103 typedef util::Mock MockUtils;
104
105 void expect_clone_md_ctx(MockTestImageCtx &mock_image_ctx) {
106 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), clone())
107 .WillOnce(Invoke([&mock_image_ctx]() {
108 get_mock_io_ctx(mock_image_ctx.md_ctx).get();
109 return &get_mock_io_ctx(mock_image_ctx.md_ctx);
110 }));
111 }
112
113 void expect_refresh_image(MockTestImageCtx &mock_image_ctx,
114 bool refresh_required, int r) {
115 EXPECT_CALL(*mock_image_ctx.state, is_refresh_required())
116 .WillOnce(Return(refresh_required));
117 if (refresh_required) {
118 EXPECT_CALL(*mock_image_ctx.state, refresh(_))
119 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
120 }
121 }
122
123 void expect_get_mirror_image(MockTestImageCtx &mock_image_ctx,
124 const cls::rbd::MirrorImage &mirror_image,
125 int r) {
126 using ceph::encode;
127 bufferlist bl;
128 encode(mirror_image, bl);
129
130 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
131 exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_image_get"),
132 _, _, _))
133 .WillOnce(DoAll(WithArg<5>(CopyInBufferlist(bl)),
134 Return(r)));
135 }
136
137 void expect_can_create_non_primary_snapshot(MockUtils &mock_utils,
138 bool result) {
139 EXPECT_CALL(mock_utils, can_create_non_primary_snapshot(_))
140 .WillOnce(Return(result));
141 }
142
143 void expect_get_mirror_peers(MockTestImageCtx &mock_image_ctx,
144 const std::vector<cls::rbd::MirrorPeer> &peers,
145 int r) {
146 using ceph::encode;
147 bufferlist bl;
148 encode(peers, bl);
149
150 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
151 exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_peer_list"),
152 _, _, _))
153 .WillOnce(DoAll(WithArg<5>(CopyInBufferlist(bl)),
154 Return(r)));
155 }
156
157 void expect_create_snapshot(MockTestImageCtx &mock_image_ctx, int r) {
158 EXPECT_CALL(*mock_image_ctx.operations, snap_create(_, _, _))
159 .WillOnce(WithArg<2>(CompleteContext(
160 r, mock_image_ctx.image_ctx->op_work_queue)));
161 }
162
163 void expect_write_image_state(
164 MockTestImageCtx &mock_image_ctx,
165 MockWriteImageStateRequest &mock_write_image_state_request, int r) {
166 EXPECT_CALL(mock_image_ctx, get_snap_id(_, _))
167 .WillOnce(Return(123));
168 EXPECT_CALL(mock_write_image_state_request, send())
169 .WillOnce(Invoke([&mock_image_ctx, &mock_write_image_state_request, r]() {
170 mock_image_ctx.image_ctx->op_work_queue->queue(
171 mock_write_image_state_request.on_finish, r);
172 }));
173 }
174 };
175
176 TEST_F(TestMockMirrorSnapshotCreateNonPrimaryRequest, Success) {
177 REQUIRE_FORMAT_V2();
178
179 librbd::ImageCtx *ictx;
180 ASSERT_EQ(0, open_image(m_image_name, &ictx));
181
182 MockTestImageCtx mock_image_ctx(*ictx);
183
184 InSequence seq;
185
186 expect_refresh_image(mock_image_ctx, true, 0);
187 expect_get_mirror_image(
188 mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, "gid",
189 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0);
190 MockUtils mock_utils;
191 expect_can_create_non_primary_snapshot(mock_utils, true);
192 expect_create_snapshot(mock_image_ctx, 0);
193 MockWriteImageStateRequest mock_write_image_state_request;
194 expect_write_image_state(mock_image_ctx, mock_write_image_state_request, 0);
195
196 C_SaferCond ctx;
197 auto req = new MockCreateNonPrimaryRequest(&mock_image_ctx, false,
198 "mirror_uuid", 123, {{1, 2}}, {},
199 nullptr, &ctx);
200 req->send();
201 ASSERT_EQ(0, ctx.wait());
202 }
203
204 TEST_F(TestMockMirrorSnapshotCreateNonPrimaryRequest, SuccessDemoted) {
205 REQUIRE_FORMAT_V2();
206
207 librbd::ImageCtx *ictx;
208 ASSERT_EQ(0, open_image(m_image_name, &ictx));
209
210 MockTestImageCtx mock_image_ctx(*ictx);
211
212 InSequence seq;
213
214 expect_clone_md_ctx(mock_image_ctx);
215 expect_refresh_image(mock_image_ctx, true, 0);
216 expect_get_mirror_image(
217 mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, "gid",
218 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0);
219 MockUtils mock_utils;
220 expect_can_create_non_primary_snapshot(mock_utils, true);
221 expect_get_mirror_peers(mock_image_ctx,
222 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
223 "mirror", "mirror uuid"}}, 0);
224 expect_create_snapshot(mock_image_ctx, 0);
225 MockWriteImageStateRequest mock_write_image_state_request;
226 expect_write_image_state(mock_image_ctx, mock_write_image_state_request, 0);
227
228 C_SaferCond ctx;
229 auto req = new MockCreateNonPrimaryRequest(&mock_image_ctx, true,
230 "mirror_uuid", 123, {{1, 2}}, {},
231 nullptr, &ctx);
232 req->send();
233 ASSERT_EQ(0, ctx.wait());
234 }
235
236 TEST_F(TestMockMirrorSnapshotCreateNonPrimaryRequest, RefreshError) {
237 REQUIRE_FORMAT_V2();
238
239 librbd::ImageCtx *ictx;
240 ASSERT_EQ(0, open_image(m_image_name, &ictx));
241
242 MockTestImageCtx mock_image_ctx(*ictx);
243
244 InSequence seq;
245
246 expect_refresh_image(mock_image_ctx, true, -EINVAL);
247
248 C_SaferCond ctx;
249 auto req = new MockCreateNonPrimaryRequest(&mock_image_ctx, false,
250 "mirror_uuid", 123, {{1, 2}}, {},
251 nullptr, &ctx);
252 req->send();
253 ASSERT_EQ(-EINVAL, ctx.wait());
254 }
255
256 TEST_F(TestMockMirrorSnapshotCreateNonPrimaryRequest, GetMirrorImageError) {
257 REQUIRE_FORMAT_V2();
258
259 librbd::ImageCtx *ictx;
260 ASSERT_EQ(0, open_image(m_image_name, &ictx));
261
262 MockTestImageCtx mock_image_ctx(*ictx);
263
264 InSequence seq;
265
266 expect_refresh_image(mock_image_ctx, false, 0);
267 expect_get_mirror_image(
268 mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, "gid",
269 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, -EINVAL);
270
271 C_SaferCond ctx;
272 auto req = new MockCreateNonPrimaryRequest(&mock_image_ctx, false,
273 "mirror_uuid", 123, {{1, 2}}, {},
274 nullptr, &ctx);
275 req->send();
276 ASSERT_EQ(-EINVAL, ctx.wait());
277 }
278
279 TEST_F(TestMockMirrorSnapshotCreateNonPrimaryRequest, CanNotError) {
280 REQUIRE_FORMAT_V2();
281
282 librbd::ImageCtx *ictx;
283 ASSERT_EQ(0, open_image(m_image_name, &ictx));
284
285 MockTestImageCtx mock_image_ctx(*ictx);
286
287 InSequence seq;
288
289 expect_refresh_image(mock_image_ctx, false, 0);
290 expect_get_mirror_image(
291 mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, "gid",
292 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0);
293 MockUtils mock_utils;
294 expect_can_create_non_primary_snapshot(mock_utils, false);
295
296 C_SaferCond ctx;
297 auto req = new MockCreateNonPrimaryRequest(&mock_image_ctx, false,
298 "mirror_uuid", 123, {{1, 2}}, {},
299 nullptr, &ctx);
300 req->send();
301 ASSERT_EQ(-EINVAL, ctx.wait());
302 }
303
304 TEST_F(TestMockMirrorSnapshotCreateNonPrimaryRequest, GetMirrorPeersError) {
305 REQUIRE_FORMAT_V2();
306
307 librbd::ImageCtx *ictx;
308 ASSERT_EQ(0, open_image(m_image_name, &ictx));
309
310 MockTestImageCtx mock_image_ctx(*ictx);
311
312 InSequence seq;
313
314 expect_clone_md_ctx(mock_image_ctx);
315 expect_refresh_image(mock_image_ctx, true, 0);
316 expect_get_mirror_image(
317 mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, "gid",
318 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0);
319 MockUtils mock_utils;
320 expect_can_create_non_primary_snapshot(mock_utils, true);
321 expect_get_mirror_peers(mock_image_ctx, {}, -EPERM);
322
323 C_SaferCond ctx;
324 auto req = new MockCreateNonPrimaryRequest(&mock_image_ctx, true,
325 "mirror_uuid", 123, {{1, 2}}, {},
326 nullptr, &ctx);
327 req->send();
328 ASSERT_EQ(-EPERM, ctx.wait());
329 }
330
331 TEST_F(TestMockMirrorSnapshotCreateNonPrimaryRequest, CreateSnapshotError) {
332 REQUIRE_FORMAT_V2();
333
334 librbd::ImageCtx *ictx;
335 ASSERT_EQ(0, open_image(m_image_name, &ictx));
336
337 MockTestImageCtx mock_image_ctx(*ictx);
338
339 InSequence seq;
340
341 expect_refresh_image(mock_image_ctx, true, 0);
342 expect_get_mirror_image(
343 mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, "gid",
344 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0);
345 MockUtils mock_utils;
346 expect_can_create_non_primary_snapshot(mock_utils, true);
347 expect_create_snapshot(mock_image_ctx, -EINVAL);
348
349 C_SaferCond ctx;
350 auto req = new MockCreateNonPrimaryRequest(&mock_image_ctx, false,
351 "mirror_uuid", 123, {{1, 2}}, {},
352 nullptr, &ctx);
353 req->send();
354 ASSERT_EQ(-EINVAL, ctx.wait());
355 }
356
357 TEST_F(TestMockMirrorSnapshotCreateNonPrimaryRequest, WriteImageStateError) {
358 REQUIRE_FORMAT_V2();
359
360 librbd::ImageCtx *ictx;
361 ASSERT_EQ(0, open_image(m_image_name, &ictx));
362
363 MockTestImageCtx mock_image_ctx(*ictx);
364
365 InSequence seq;
366
367 expect_refresh_image(mock_image_ctx, true, 0);
368 expect_get_mirror_image(
369 mock_image_ctx, {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, "gid",
370 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, 0);
371 MockUtils mock_utils;
372 expect_can_create_non_primary_snapshot(mock_utils, true);
373 expect_create_snapshot(mock_image_ctx, 0);
374 MockWriteImageStateRequest mock_write_image_state_request;
375 expect_write_image_state(mock_image_ctx, mock_write_image_state_request,
376 -EINVAL);
377
378 C_SaferCond ctx;
379 auto req = new MockCreateNonPrimaryRequest(&mock_image_ctx, false,
380 "mirror_uuid", 123, {{1, 2}}, {},
381 nullptr, &ctx);
382 req->send();
383 ASSERT_EQ(-EINVAL, ctx.wait());
384 }
385
386 } // namespace snapshot
387 } // namespace mirror
388 } // namespace librbd