]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/io/test_mock_ImageRequestWQ.cc
update sources to v12.1.1
[ceph.git] / ceph / src / test / librbd / io / test_mock_ImageRequestWQ.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/exclusive_lock/MockPolicy.h"
8 #include "librbd/io/ImageRequestWQ.h"
9 #include "librbd/io/ImageRequest.h"
10
11 namespace librbd {
12 namespace {
13
14 struct MockTestImageCtx : public MockImageCtx {
15 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
16 }
17 };
18
19 } // anonymous namespace
20
21 namespace io {
22
23 template <>
24 struct ImageRequest<librbd::MockTestImageCtx> {
25 static ImageRequest* s_instance;
26 AioCompletion *aio_comp;
27
28 static ImageRequest* create_write_request(librbd::MockTestImageCtx &image_ctx,
29 AioCompletion *aio_comp,
30 Extents &&image_extents,
31 bufferlist &&bl, int op_flags,
32 const ZTracer::Trace &parent_trace) {
33 assert(s_instance != nullptr);
34 s_instance->aio_comp = aio_comp;
35 return s_instance;
36 }
37 static void aio_write(librbd::MockTestImageCtx *ictx, AioCompletion *c,
38 Extents &&image_extents, bufferlist &&bl, int op_flags,
39 const ZTracer::Trace &parent_trace) {
40 }
41
42
43 MOCK_CONST_METHOD0(is_write_op, bool());
44 MOCK_CONST_METHOD0(start_op, void());
45 MOCK_CONST_METHOD0(send, void());
46 MOCK_CONST_METHOD1(fail, void(int));
47
48 ImageRequest() {
49 s_instance = this;
50 }
51 };
52
53 } // namespace io
54
55 namespace util {
56
57 inline ImageCtx *get_image_ctx(MockTestImageCtx *image_ctx) {
58 return image_ctx->image_ctx;
59 }
60
61 } // namespace util
62
63 } // namespace librbd
64
65 template <>
66 struct ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>> {
67 typedef librbd::io::ImageRequest<librbd::MockTestImageCtx> ImageRequest;
68 static PointerWQ* s_instance;
69
70 Mutex m_lock;
71
72 PointerWQ(const std::string &name, time_t, int, ThreadPool *)
73 : m_lock(name) {
74 s_instance = this;
75 }
76 virtual ~PointerWQ() {
77 }
78
79 MOCK_METHOD0(drain, void());
80 MOCK_METHOD0(empty, bool());
81 MOCK_METHOD0(signal, void());
82 MOCK_METHOD0(process_finish, void());
83
84 MOCK_METHOD0(front, ImageRequest*());
85 MOCK_METHOD1(requeue, void(ImageRequest*));
86
87 MOCK_METHOD0(dequeue, void*());
88 MOCK_METHOD1(queue, void(ImageRequest*));
89
90 void register_work_queue() {
91 // no-op
92 }
93 Mutex &get_pool_lock() {
94 return m_lock;
95 }
96
97 void* invoke_dequeue() {
98 Mutex::Locker locker(m_lock);
99 return _void_dequeue();
100 }
101 void invoke_process(ImageRequest *image_request) {
102 process(image_request);
103 }
104
105 virtual void *_void_dequeue() {
106 return dequeue();
107 }
108 virtual void process(ImageRequest *req) = 0;
109
110 };
111
112 ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>>*
113 ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>>::s_instance = nullptr;
114 librbd::io::ImageRequest<librbd::MockTestImageCtx>*
115 librbd::io::ImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
116
117 #include "librbd/io/ImageRequestWQ.cc"
118
119 namespace librbd {
120 namespace io {
121
122 using ::testing::_;
123 using ::testing::InSequence;
124 using ::testing::Invoke;
125 using ::testing::Return;
126 using ::testing::WithArg;
127
128 struct TestMockIoImageRequestWQ : public TestMockFixture {
129 typedef ImageRequestWQ<librbd::MockTestImageCtx> MockImageRequestWQ;
130 typedef ImageRequest<librbd::MockTestImageCtx> MockImageRequest;
131
132 void expect_is_write_op(MockImageRequest &image_request, bool write_op) {
133 EXPECT_CALL(image_request, is_write_op()).WillOnce(Return(write_op));
134 }
135
136 void expect_signal(MockImageRequestWQ &image_request_wq) {
137 EXPECT_CALL(image_request_wq, signal());
138 }
139
140 void expect_queue(MockImageRequestWQ &image_request_wq) {
141 EXPECT_CALL(image_request_wq, queue(_));
142 }
143
144 void expect_front(MockImageRequestWQ &image_request_wq,
145 MockImageRequest *image_request) {
146 EXPECT_CALL(image_request_wq, front()).WillOnce(Return(image_request));
147 }
148
149 void expect_is_refresh_request(MockTestImageCtx &mock_image_ctx,
150 bool required) {
151 EXPECT_CALL(*mock_image_ctx.state, is_refresh_required()).WillOnce(
152 Return(required));
153 }
154
155 void expect_dequeue(MockImageRequestWQ &image_request_wq,
156 MockImageRequest *image_request) {
157 EXPECT_CALL(image_request_wq, dequeue()).WillOnce(Return(image_request));
158 }
159
160 void expect_get_exclusive_lock_policy(MockTestImageCtx &mock_image_ctx,
161 librbd::exclusive_lock::MockPolicy &policy) {
162 EXPECT_CALL(mock_image_ctx,
163 get_exclusive_lock_policy()).WillOnce(Return(&policy));
164 }
165
166 void expect_may_auto_request_lock(librbd::exclusive_lock::MockPolicy &policy,
167 bool value) {
168 EXPECT_CALL(policy, may_auto_request_lock()).WillOnce(Return(value));
169 }
170
171 void expect_acquire_lock(MockExclusiveLock &mock_exclusive_lock,
172 Context **on_finish) {
173 EXPECT_CALL(mock_exclusive_lock, acquire_lock(_))
174 .WillOnce(Invoke([on_finish](Context *ctx) {
175 *on_finish = ctx;
176 }));
177 }
178
179 void expect_process_finish(MockImageRequestWQ &mock_image_request_wq) {
180 EXPECT_CALL(mock_image_request_wq, process_finish()).Times(1);
181 }
182
183 void expect_fail(MockImageRequest &mock_image_request, int r) {
184 EXPECT_CALL(mock_image_request, fail(r))
185 .WillOnce(Invoke([&mock_image_request](int r) {
186 mock_image_request.aio_comp->get();
187 mock_image_request.aio_comp->fail(r);
188 }));
189 }
190
191 void expect_refresh(MockTestImageCtx &mock_image_ctx, Context **on_finish) {
192 EXPECT_CALL(*mock_image_ctx.state, refresh(_))
193 .WillOnce(Invoke([on_finish](Context *ctx) {
194 *on_finish = ctx;
195 }));
196 }
197 };
198
199 TEST_F(TestMockIoImageRequestWQ, AcquireLockError) {
200 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
201
202 librbd::ImageCtx *ictx;
203 ASSERT_EQ(0, open_image(m_image_name, &ictx));
204
205 MockTestImageCtx mock_image_ctx(*ictx);
206 MockExclusiveLock mock_exclusive_lock;
207 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
208
209 InSequence seq;
210 MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
211 expect_signal(mock_image_request_wq);
212 mock_image_request_wq.set_require_lock(DIRECTION_WRITE, true);
213
214 auto mock_image_request = new MockImageRequest();
215 expect_is_write_op(*mock_image_request, true);
216 expect_queue(mock_image_request_wq);
217 auto *aio_comp = new librbd::io::AioCompletion();
218 mock_image_request_wq.aio_write(aio_comp, 0, 0, {}, 0);
219
220 librbd::exclusive_lock::MockPolicy mock_exclusive_lock_policy;
221 expect_front(mock_image_request_wq, mock_image_request);
222 expect_is_refresh_request(mock_image_ctx, false);
223 expect_is_write_op(*mock_image_request, true);
224 expect_dequeue(mock_image_request_wq, mock_image_request);
225 expect_get_exclusive_lock_policy(mock_image_ctx, mock_exclusive_lock_policy);
226 expect_may_auto_request_lock(mock_exclusive_lock_policy, true);
227 Context *on_acquire = nullptr;
228 expect_acquire_lock(mock_exclusive_lock, &on_acquire);
229 ASSERT_TRUE(mock_image_request_wq.invoke_dequeue() == nullptr);
230 ASSERT_TRUE(on_acquire != nullptr);
231
232 expect_process_finish(mock_image_request_wq);
233 expect_fail(*mock_image_request, -EPERM);
234 expect_is_write_op(*mock_image_request, true);
235 expect_signal(mock_image_request_wq);
236 on_acquire->complete(-EPERM);
237
238 ASSERT_EQ(0, aio_comp->wait_for_complete());
239 ASSERT_EQ(-EPERM, aio_comp->get_return_value());
240 aio_comp->release();
241 }
242
243 TEST_F(TestMockIoImageRequestWQ, RefreshError) {
244 librbd::ImageCtx *ictx;
245 ASSERT_EQ(0, open_image(m_image_name, &ictx));
246
247 MockTestImageCtx mock_image_ctx(*ictx);
248
249 InSequence seq;
250 MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
251
252 auto mock_image_request = new MockImageRequest();
253 expect_is_write_op(*mock_image_request, true);
254 expect_queue(mock_image_request_wq);
255 auto *aio_comp = new librbd::io::AioCompletion();
256 mock_image_request_wq.aio_write(aio_comp, 0, 0, {}, 0);
257
258 expect_front(mock_image_request_wq, mock_image_request);
259 expect_is_refresh_request(mock_image_ctx, true);
260 expect_is_write_op(*mock_image_request, true);
261 expect_dequeue(mock_image_request_wq, mock_image_request);
262 Context *on_refresh = nullptr;
263 expect_refresh(mock_image_ctx, &on_refresh);
264 ASSERT_TRUE(mock_image_request_wq.invoke_dequeue() == nullptr);
265 ASSERT_TRUE(on_refresh != nullptr);
266
267 expect_process_finish(mock_image_request_wq);
268 expect_fail(*mock_image_request, -EPERM);
269 expect_is_write_op(*mock_image_request, true);
270 expect_signal(mock_image_request_wq);
271 on_refresh->complete(-EPERM);
272
273 ASSERT_EQ(0, aio_comp->wait_for_complete());
274 ASSERT_EQ(-EPERM, aio_comp->get_return_value());
275 aio_comp->release();
276 }
277
278 } // namespace io
279 } // namespace librbd