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