]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2017 Red Hat, Inc. | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | */ | |
13 | ||
14 | #include "librados/librados_asio.h" | |
15 | #include <gtest/gtest.h> | |
16 | ||
17 | #include "common/ceph_argparse.h" | |
18 | #include "common/debug.h" | |
19 | #include "common/errno.h" | |
20 | #include "global/global_init.h" | |
21 | ||
22 | #ifdef HAVE_BOOST_CONTEXT | |
23 | #define BOOST_COROUTINES_NO_DEPRECATION_WARNING | |
24 | #include <boost/asio/spawn.hpp> | |
25 | #endif | |
26 | #include <boost/asio/use_future.hpp> | |
27 | ||
28 | #define dout_subsys ceph_subsys_rados | |
29 | #define dout_context g_ceph_context | |
30 | ||
31 | // test fixture for global setup/teardown | |
32 | class AsioRados : public ::testing::Test { | |
33 | static constexpr auto poolname = "ceph_test_rados_api_asio"; | |
34 | ||
35 | protected: | |
36 | static librados::Rados rados; | |
37 | static librados::IoCtx io; | |
38 | // writes to snapio fail immediately with -EROFS. this is used to test errors | |
39 | // that come from inside the initiating function, rather than passed to the | |
40 | // AioCompletion callback | |
41 | static librados::IoCtx snapio; | |
42 | ||
43 | public: | |
44 | static void SetUpTestCase() { | |
45 | ASSERT_EQ(0, rados.init_with_context(g_ceph_context)); | |
46 | ASSERT_EQ(0, rados.connect()); | |
47 | // open/create test pool | |
48 | int r = rados.ioctx_create(poolname, io); | |
49 | if (r == -ENOENT) { | |
50 | r = rados.pool_create(poolname); | |
51 | if (r == -EEXIST) { | |
52 | r = 0; | |
53 | } else if (r == 0) { | |
54 | r = rados.ioctx_create(poolname, io); | |
55 | } | |
56 | } | |
57 | ASSERT_EQ(0, r); | |
58 | ASSERT_EQ(0, rados.ioctx_create(poolname, snapio)); | |
59 | snapio.snap_set_read(1); | |
60 | // initialize the "exist" object | |
61 | bufferlist bl; | |
62 | bl.append("hello"); | |
63 | ASSERT_EQ(0, io.write_full("exist", bl)); | |
64 | } | |
65 | ||
66 | static void TearDownTestCase() { | |
67 | rados.shutdown(); | |
68 | } | |
69 | }; | |
70 | librados::Rados AsioRados::rados; | |
71 | librados::IoCtx AsioRados::io; | |
72 | librados::IoCtx AsioRados::snapio; | |
73 | ||
74 | TEST_F(AsioRados, AsyncReadCallback) | |
75 | { | |
76 | boost::asio::io_service service; | |
77 | ||
78 | auto success_cb = [&] (boost::system::error_code ec, bufferlist bl) { | |
79 | EXPECT_FALSE(ec); | |
80 | EXPECT_EQ("hello", bl.to_str()); | |
81 | }; | |
82 | librados::async_read(service, io, "exist", 256, 0, success_cb); | |
83 | ||
84 | auto failure_cb = [&] (boost::system::error_code ec, bufferlist bl) { | |
85 | EXPECT_EQ(boost::system::errc::no_such_file_or_directory, ec); | |
86 | }; | |
87 | librados::async_read(service, io, "noexist", 256, 0, failure_cb); | |
88 | ||
89 | service.run(); | |
90 | } | |
91 | ||
92 | TEST_F(AsioRados, AsyncReadFuture) | |
93 | { | |
94 | boost::asio::io_service service; | |
95 | ||
96 | std::future<bufferlist> f1 = librados::async_read(service, io, "exist", 256, | |
97 | 0, boost::asio::use_future); | |
98 | std::future<bufferlist> f2 = librados::async_read(service, io, "noexist", 256, | |
99 | 0, boost::asio::use_future); | |
100 | ||
101 | service.run(); | |
102 | ||
103 | EXPECT_NO_THROW({ | |
104 | auto bl = f1.get(); | |
105 | EXPECT_EQ("hello", bl.to_str()); | |
106 | }); | |
107 | EXPECT_THROW(f2.get(), boost::system::system_error); | |
108 | } | |
109 | ||
110 | #ifdef HAVE_BOOST_CONTEXT | |
111 | TEST_F(AsioRados, AsyncReadYield) | |
112 | { | |
113 | boost::asio::io_service service; | |
114 | ||
115 | auto success_cr = [&] (boost::asio::yield_context yield) { | |
116 | boost::system::error_code ec; | |
117 | auto bl = librados::async_read(service, io, "exist", 256, 0, yield[ec]); | |
118 | EXPECT_FALSE(ec); | |
119 | EXPECT_EQ("hello", bl.to_str()); | |
120 | }; | |
121 | boost::asio::spawn(service, success_cr); | |
122 | ||
123 | auto failure_cr = [&] (boost::asio::yield_context yield) { | |
124 | boost::system::error_code ec; | |
125 | auto bl = librados::async_read(service, io, "noexist", 256, 0, yield[ec]); | |
126 | EXPECT_EQ(boost::system::errc::no_such_file_or_directory, ec); | |
127 | }; | |
128 | boost::asio::spawn(service, failure_cr); | |
129 | ||
130 | service.run(); | |
131 | } | |
132 | #endif | |
133 | ||
134 | TEST_F(AsioRados, AsyncWriteCallback) | |
135 | { | |
136 | boost::asio::io_service service; | |
137 | ||
138 | bufferlist bl; | |
139 | bl.append("hello"); | |
140 | ||
141 | auto success_cb = [&] (boost::system::error_code ec) { | |
142 | EXPECT_FALSE(ec); | |
143 | }; | |
144 | librados::async_write(service, io, "exist", bl, bl.length(), 0, | |
145 | success_cb); | |
146 | ||
147 | auto failure_cb = [&] (boost::system::error_code ec) { | |
148 | EXPECT_EQ(boost::system::errc::read_only_file_system, ec); | |
149 | }; | |
150 | librados::async_write(service, snapio, "exist", bl, bl.length(), 0, | |
151 | failure_cb); | |
152 | ||
153 | service.run(); | |
154 | } | |
155 | ||
156 | TEST_F(AsioRados, AsyncWriteFuture) | |
157 | { | |
158 | boost::asio::io_service service; | |
159 | ||
160 | bufferlist bl; | |
161 | bl.append("hello"); | |
162 | ||
163 | auto f1 = librados::async_write(service, io, "exist", bl, bl.length(), 0, | |
164 | boost::asio::use_future); | |
165 | auto f2 = librados::async_write(service, snapio, "exist", bl, bl.length(), 0, | |
166 | boost::asio::use_future); | |
167 | ||
168 | service.run(); | |
169 | ||
170 | EXPECT_NO_THROW(f1.get()); | |
171 | EXPECT_THROW(f2.get(), boost::system::system_error); | |
172 | } | |
173 | ||
174 | #ifdef HAVE_BOOST_CONTEXT | |
175 | TEST_F(AsioRados, AsyncWriteYield) | |
176 | { | |
177 | boost::asio::io_service service; | |
178 | ||
179 | bufferlist bl; | |
180 | bl.append("hello"); | |
181 | ||
182 | auto success_cr = [&] (boost::asio::yield_context yield) { | |
183 | boost::system::error_code ec; | |
184 | librados::async_write(service, io, "exist", bl, bl.length(), 0, | |
185 | yield[ec]); | |
186 | EXPECT_FALSE(ec); | |
187 | EXPECT_EQ("hello", bl.to_str()); | |
188 | }; | |
189 | boost::asio::spawn(service, success_cr); | |
190 | ||
191 | auto failure_cr = [&] (boost::asio::yield_context yield) { | |
192 | boost::system::error_code ec; | |
193 | librados::async_write(service, snapio, "exist", bl, bl.length(), 0, | |
194 | yield[ec]); | |
195 | EXPECT_EQ(boost::system::errc::read_only_file_system, ec); | |
196 | }; | |
197 | boost::asio::spawn(service, failure_cr); | |
198 | ||
199 | service.run(); | |
200 | } | |
201 | #endif | |
202 | ||
203 | TEST_F(AsioRados, AsyncReadOperationCallback) | |
204 | { | |
205 | boost::asio::io_service service; | |
206 | { | |
207 | librados::ObjectReadOperation op; | |
208 | op.read(0, 0, nullptr, nullptr); | |
209 | auto success_cb = [&] (boost::system::error_code ec, bufferlist bl) { | |
210 | EXPECT_FALSE(ec); | |
211 | EXPECT_EQ("hello", bl.to_str()); | |
212 | }; | |
213 | librados::async_operate(service, io, "exist", &op, 0, success_cb); | |
214 | } | |
215 | { | |
216 | librados::ObjectReadOperation op; | |
217 | op.read(0, 0, nullptr, nullptr); | |
218 | auto failure_cb = [&] (boost::system::error_code ec, bufferlist bl) { | |
219 | EXPECT_EQ(boost::system::errc::no_such_file_or_directory, ec); | |
220 | }; | |
221 | librados::async_operate(service, io, "noexist", &op, 0, failure_cb); | |
222 | } | |
223 | service.run(); | |
224 | } | |
225 | ||
226 | TEST_F(AsioRados, AsyncReadOperationFuture) | |
227 | { | |
228 | boost::asio::io_service service; | |
229 | std::future<bufferlist> f1; | |
230 | { | |
231 | librados::ObjectReadOperation op; | |
232 | op.read(0, 0, nullptr, nullptr); | |
233 | f1 = librados::async_operate(service, io, "exist", &op, 0, | |
234 | boost::asio::use_future); | |
235 | } | |
236 | std::future<bufferlist> f2; | |
237 | { | |
238 | librados::ObjectReadOperation op; | |
239 | op.read(0, 0, nullptr, nullptr); | |
240 | f2 = librados::async_operate(service, io, "noexist", &op, 0, | |
241 | boost::asio::use_future); | |
242 | } | |
243 | service.run(); | |
244 | ||
245 | EXPECT_NO_THROW({ | |
246 | auto bl = f1.get(); | |
247 | EXPECT_EQ("hello", bl.to_str()); | |
248 | }); | |
249 | EXPECT_THROW(f2.get(), boost::system::system_error); | |
250 | } | |
251 | ||
252 | #ifdef HAVE_BOOST_CONTEXT | |
253 | TEST_F(AsioRados, AsyncReadOperationYield) | |
254 | { | |
255 | boost::asio::io_service service; | |
256 | ||
257 | auto success_cr = [&] (boost::asio::yield_context yield) { | |
258 | librados::ObjectReadOperation op; | |
259 | op.read(0, 0, nullptr, nullptr); | |
260 | boost::system::error_code ec; | |
261 | auto bl = librados::async_operate(service, io, "exist", &op, 0, | |
262 | yield[ec]); | |
263 | EXPECT_FALSE(ec); | |
264 | EXPECT_EQ("hello", bl.to_str()); | |
265 | }; | |
266 | boost::asio::spawn(service, success_cr); | |
267 | ||
268 | auto failure_cr = [&] (boost::asio::yield_context yield) { | |
269 | librados::ObjectReadOperation op; | |
270 | op.read(0, 0, nullptr, nullptr); | |
271 | boost::system::error_code ec; | |
272 | auto bl = librados::async_operate(service, io, "noexist", &op, 0, | |
273 | yield[ec]); | |
274 | EXPECT_EQ(boost::system::errc::no_such_file_or_directory, ec); | |
275 | }; | |
276 | boost::asio::spawn(service, failure_cr); | |
277 | ||
278 | service.run(); | |
279 | } | |
280 | #endif | |
281 | ||
282 | TEST_F(AsioRados, AsyncWriteOperationCallback) | |
283 | { | |
284 | boost::asio::io_service service; | |
285 | ||
286 | bufferlist bl; | |
287 | bl.append("hello"); | |
288 | ||
289 | { | |
290 | librados::ObjectWriteOperation op; | |
291 | op.write_full(bl); | |
292 | auto success_cb = [&] (boost::system::error_code ec) { | |
293 | EXPECT_FALSE(ec); | |
294 | }; | |
295 | librados::async_operate(service, io, "exist", &op, 0, success_cb); | |
296 | } | |
297 | { | |
298 | librados::ObjectWriteOperation op; | |
299 | op.write_full(bl); | |
300 | auto failure_cb = [&] (boost::system::error_code ec) { | |
301 | EXPECT_EQ(boost::system::errc::read_only_file_system, ec); | |
302 | }; | |
303 | librados::async_operate(service, snapio, "exist", &op, 0, failure_cb); | |
304 | } | |
305 | service.run(); | |
306 | } | |
307 | ||
308 | TEST_F(AsioRados, AsyncWriteOperationFuture) | |
309 | { | |
310 | boost::asio::io_service service; | |
311 | ||
312 | bufferlist bl; | |
313 | bl.append("hello"); | |
314 | ||
315 | std::future<void> f1; | |
316 | { | |
317 | librados::ObjectWriteOperation op; | |
318 | op.write_full(bl); | |
319 | f1 = librados::async_operate(service, io, "exist", &op, 0, | |
320 | boost::asio::use_future); | |
321 | } | |
322 | std::future<void> f2; | |
323 | { | |
324 | librados::ObjectWriteOperation op; | |
325 | op.write_full(bl); | |
326 | f2 = librados::async_operate(service, snapio, "exist", &op, 0, | |
327 | boost::asio::use_future); | |
328 | } | |
329 | service.run(); | |
330 | ||
331 | EXPECT_NO_THROW(f1.get()); | |
332 | EXPECT_THROW(f2.get(), boost::system::system_error); | |
333 | } | |
334 | ||
335 | #ifdef HAVE_BOOST_CONTEXT | |
336 | TEST_F(AsioRados, AsyncWriteOperationYield) | |
337 | { | |
338 | boost::asio::io_service service; | |
339 | ||
340 | bufferlist bl; | |
341 | bl.append("hello"); | |
342 | ||
343 | auto success_cr = [&] (boost::asio::yield_context yield) { | |
344 | librados::ObjectWriteOperation op; | |
345 | op.write_full(bl); | |
346 | boost::system::error_code ec; | |
347 | librados::async_operate(service, io, "exist", &op, 0, yield[ec]); | |
348 | EXPECT_FALSE(ec); | |
349 | }; | |
350 | boost::asio::spawn(service, success_cr); | |
351 | ||
352 | auto failure_cr = [&] (boost::asio::yield_context yield) { | |
353 | librados::ObjectWriteOperation op; | |
354 | op.write_full(bl); | |
355 | boost::system::error_code ec; | |
356 | librados::async_operate(service, snapio, "exist", &op, 0, yield[ec]); | |
357 | EXPECT_EQ(boost::system::errc::read_only_file_system, ec); | |
358 | }; | |
359 | boost::asio::spawn(service, failure_cr); | |
360 | ||
361 | service.run(); | |
362 | } | |
363 | #endif | |
364 | ||
365 | int main(int argc, char **argv) | |
366 | { | |
367 | vector<const char*> args; | |
368 | argv_to_vec(argc, (const char **)argv, args); | |
369 | env_to_vec(args); | |
370 | ||
371 | auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, | |
372 | CODE_ENVIRONMENT_UTILITY, 0); | |
373 | common_init_finish(cct.get()); | |
374 | ||
375 | ::testing::InitGoogleTest(&argc, argv); | |
376 | return RUN_ALL_TESTS(); | |
377 | } |