1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
14 struct MockTestImageCtx : public MockImageCtx {
15 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
19 } // anonymous namespace
24 struct ImageRequest<librbd::MockTestImageCtx> {
25 static ImageRequest* s_instance;
26 AioCompletion *aio_comp;
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;
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) {
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));
57 inline ImageCtx *get_image_ctx(MockTestImageCtx *image_ctx) {
58 return image_ctx->image_ctx;
66 struct ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>> {
67 typedef librbd::io::ImageRequest<librbd::MockTestImageCtx> ImageRequest;
68 static PointerWQ* s_instance;
72 PointerWQ(const std::string &name, time_t, int, ThreadPool *)
76 virtual ~PointerWQ() {
79 MOCK_METHOD0(drain, void());
80 MOCK_METHOD0(empty, bool());
81 MOCK_METHOD0(signal, void());
82 MOCK_METHOD0(process_finish, void());
84 MOCK_METHOD0(front, ImageRequest*());
85 MOCK_METHOD1(requeue, void(ImageRequest*));
87 MOCK_METHOD0(dequeue, void*());
88 MOCK_METHOD1(queue, void(ImageRequest*));
90 void register_work_queue() {
93 Mutex &get_pool_lock() {
97 void* invoke_dequeue() {
98 Mutex::Locker locker(m_lock);
99 return _void_dequeue();
101 void invoke_process(ImageRequest *image_request) {
102 process(image_request);
105 virtual void *_void_dequeue() {
108 virtual void process(ImageRequest *req) = 0;
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;
117 #include "librbd/io/ImageRequestWQ.cc"
123 using ::testing::InSequence;
124 using ::testing::Invoke;
125 using ::testing::Return;
126 using ::testing::WithArg;
128 struct TestMockIoImageRequestWQ : public TestMockFixture {
129 typedef ImageRequestWQ<librbd::MockTestImageCtx> MockImageRequestWQ;
130 typedef ImageRequest<librbd::MockTestImageCtx> MockImageRequest;
132 void expect_is_write_op(MockImageRequest &image_request, bool write_op) {
133 EXPECT_CALL(image_request, is_write_op()).WillOnce(Return(write_op));
136 void expect_signal(MockImageRequestWQ &image_request_wq) {
137 EXPECT_CALL(image_request_wq, signal());
140 void expect_queue(MockImageRequestWQ &image_request_wq) {
141 EXPECT_CALL(image_request_wq, queue(_));
144 void expect_front(MockImageRequestWQ &image_request_wq,
145 MockImageRequest *image_request) {
146 EXPECT_CALL(image_request_wq, front()).WillOnce(Return(image_request));
149 void expect_is_refresh_request(MockTestImageCtx &mock_image_ctx,
151 EXPECT_CALL(*mock_image_ctx.state, is_refresh_required()).WillOnce(
155 void expect_dequeue(MockImageRequestWQ &image_request_wq,
156 MockImageRequest *image_request) {
157 EXPECT_CALL(image_request_wq, dequeue()).WillOnce(Return(image_request));
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));
166 void expect_may_auto_request_lock(librbd::exclusive_lock::MockPolicy &policy,
168 EXPECT_CALL(policy, may_auto_request_lock()).WillOnce(Return(value));
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) {
179 void expect_process_finish(MockImageRequestWQ &mock_image_request_wq) {
180 EXPECT_CALL(mock_image_request_wq, process_finish()).Times(1);
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);
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) {
199 TEST_F(TestMockIoImageRequestWQ, AcquireLockError) {
200 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
202 librbd::ImageCtx *ictx;
203 ASSERT_EQ(0, open_image(m_image_name, &ictx));
205 MockTestImageCtx mock_image_ctx(*ictx);
206 MockExclusiveLock mock_exclusive_lock;
207 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
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);
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);
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);
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);
238 ASSERT_EQ(0, aio_comp->wait_for_complete());
239 ASSERT_EQ(-EPERM, aio_comp->get_return_value());
243 TEST_F(TestMockIoImageRequestWQ, RefreshError) {
244 librbd::ImageCtx *ictx;
245 ASSERT_EQ(0, open_image(m_image_name, &ictx));
247 MockTestImageCtx mock_image_ctx(*ictx);
250 MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
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);
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);
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);
273 ASSERT_EQ(0, aio_comp->wait_for_complete());
274 ASSERT_EQ(-EPERM, aio_comp->get_return_value());
279 } // namespace librbd