]>
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 | ||
11fdf7f2 | 22 | #define BOOST_COROUTINES_NO_DEPRECATION_WARNING |
92f5a8d4 TL |
23 | #include <boost/range/begin.hpp> |
24 | #include <boost/range/end.hpp> | |
11fdf7f2 | 25 | #include <boost/asio/spawn.hpp> |
11fdf7f2 TL |
26 | #include <boost/asio/use_future.hpp> |
27 | ||
28 | #define dout_subsys ceph_subsys_rados | |
29 | #define dout_context g_ceph_context | |
30 | ||
20effc67 TL |
31 | using namespace std; |
32 | ||
11fdf7f2 TL |
33 | // test fixture for global setup/teardown |
34 | class AsioRados : public ::testing::Test { | |
35 | static constexpr auto poolname = "ceph_test_rados_api_asio"; | |
36 | ||
37 | protected: | |
38 | static librados::Rados rados; | |
39 | static librados::IoCtx io; | |
40 | // writes to snapio fail immediately with -EROFS. this is used to test errors | |
41 | // that come from inside the initiating function, rather than passed to the | |
42 | // AioCompletion callback | |
43 | static librados::IoCtx snapio; | |
44 | ||
45 | public: | |
46 | static void SetUpTestCase() { | |
47 | ASSERT_EQ(0, rados.init_with_context(g_ceph_context)); | |
48 | ASSERT_EQ(0, rados.connect()); | |
49 | // open/create test pool | |
50 | int r = rados.ioctx_create(poolname, io); | |
51 | if (r == -ENOENT) { | |
52 | r = rados.pool_create(poolname); | |
53 | if (r == -EEXIST) { | |
54 | r = 0; | |
55 | } else if (r == 0) { | |
56 | r = rados.ioctx_create(poolname, io); | |
57 | } | |
58 | } | |
59 | ASSERT_EQ(0, r); | |
60 | ASSERT_EQ(0, rados.ioctx_create(poolname, snapio)); | |
61 | snapio.snap_set_read(1); | |
62 | // initialize the "exist" object | |
63 | bufferlist bl; | |
64 | bl.append("hello"); | |
65 | ASSERT_EQ(0, io.write_full("exist", bl)); | |
66 | } | |
67 | ||
68 | static void TearDownTestCase() { | |
69 | rados.shutdown(); | |
70 | } | |
71 | }; | |
72 | librados::Rados AsioRados::rados; | |
73 | librados::IoCtx AsioRados::io; | |
74 | librados::IoCtx AsioRados::snapio; | |
75 | ||
76 | TEST_F(AsioRados, AsyncReadCallback) | |
77 | { | |
78 | boost::asio::io_service service; | |
79 | ||
80 | auto success_cb = [&] (boost::system::error_code ec, bufferlist bl) { | |
81 | EXPECT_FALSE(ec); | |
82 | EXPECT_EQ("hello", bl.to_str()); | |
83 | }; | |
84 | librados::async_read(service, io, "exist", 256, 0, success_cb); | |
85 | ||
86 | auto failure_cb = [&] (boost::system::error_code ec, bufferlist bl) { | |
87 | EXPECT_EQ(boost::system::errc::no_such_file_or_directory, ec); | |
88 | }; | |
89 | librados::async_read(service, io, "noexist", 256, 0, failure_cb); | |
90 | ||
91 | service.run(); | |
92 | } | |
93 | ||
94 | TEST_F(AsioRados, AsyncReadFuture) | |
95 | { | |
96 | boost::asio::io_service service; | |
97 | ||
98 | std::future<bufferlist> f1 = librados::async_read(service, io, "exist", 256, | |
99 | 0, boost::asio::use_future); | |
100 | std::future<bufferlist> f2 = librados::async_read(service, io, "noexist", 256, | |
101 | 0, boost::asio::use_future); | |
102 | ||
103 | service.run(); | |
104 | ||
105 | EXPECT_NO_THROW({ | |
106 | auto bl = f1.get(); | |
107 | EXPECT_EQ("hello", bl.to_str()); | |
108 | }); | |
109 | EXPECT_THROW(f2.get(), boost::system::system_error); | |
110 | } | |
111 | ||
11fdf7f2 TL |
112 | TEST_F(AsioRados, AsyncReadYield) |
113 | { | |
114 | boost::asio::io_service service; | |
115 | ||
116 | auto success_cr = [&] (boost::asio::yield_context yield) { | |
117 | boost::system::error_code ec; | |
118 | auto bl = librados::async_read(service, io, "exist", 256, 0, yield[ec]); | |
119 | EXPECT_FALSE(ec); | |
120 | EXPECT_EQ("hello", bl.to_str()); | |
121 | }; | |
122 | boost::asio::spawn(service, success_cr); | |
123 | ||
124 | auto failure_cr = [&] (boost::asio::yield_context yield) { | |
125 | boost::system::error_code ec; | |
126 | auto bl = librados::async_read(service, io, "noexist", 256, 0, yield[ec]); | |
127 | EXPECT_EQ(boost::system::errc::no_such_file_or_directory, ec); | |
128 | }; | |
129 | boost::asio::spawn(service, failure_cr); | |
130 | ||
131 | service.run(); | |
132 | } | |
11fdf7f2 TL |
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 | ||
11fdf7f2 TL |
174 | TEST_F(AsioRados, AsyncWriteYield) |
175 | { | |
176 | boost::asio::io_service service; | |
177 | ||
178 | bufferlist bl; | |
179 | bl.append("hello"); | |
180 | ||
181 | auto success_cr = [&] (boost::asio::yield_context yield) { | |
182 | boost::system::error_code ec; | |
183 | librados::async_write(service, io, "exist", bl, bl.length(), 0, | |
184 | yield[ec]); | |
185 | EXPECT_FALSE(ec); | |
186 | EXPECT_EQ("hello", bl.to_str()); | |
187 | }; | |
188 | boost::asio::spawn(service, success_cr); | |
189 | ||
190 | auto failure_cr = [&] (boost::asio::yield_context yield) { | |
191 | boost::system::error_code ec; | |
192 | librados::async_write(service, snapio, "exist", bl, bl.length(), 0, | |
193 | yield[ec]); | |
194 | EXPECT_EQ(boost::system::errc::read_only_file_system, ec); | |
195 | }; | |
196 | boost::asio::spawn(service, failure_cr); | |
197 | ||
198 | service.run(); | |
199 | } | |
11fdf7f2 TL |
200 | |
201 | TEST_F(AsioRados, AsyncReadOperationCallback) | |
202 | { | |
203 | boost::asio::io_service service; | |
204 | { | |
205 | librados::ObjectReadOperation op; | |
206 | op.read(0, 0, nullptr, nullptr); | |
207 | auto success_cb = [&] (boost::system::error_code ec, bufferlist bl) { | |
208 | EXPECT_FALSE(ec); | |
209 | EXPECT_EQ("hello", bl.to_str()); | |
210 | }; | |
211 | librados::async_operate(service, io, "exist", &op, 0, success_cb); | |
212 | } | |
213 | { | |
214 | librados::ObjectReadOperation op; | |
215 | op.read(0, 0, nullptr, nullptr); | |
216 | auto failure_cb = [&] (boost::system::error_code ec, bufferlist bl) { | |
217 | EXPECT_EQ(boost::system::errc::no_such_file_or_directory, ec); | |
218 | }; | |
219 | librados::async_operate(service, io, "noexist", &op, 0, failure_cb); | |
220 | } | |
221 | service.run(); | |
222 | } | |
223 | ||
224 | TEST_F(AsioRados, AsyncReadOperationFuture) | |
225 | { | |
226 | boost::asio::io_service service; | |
227 | std::future<bufferlist> f1; | |
228 | { | |
229 | librados::ObjectReadOperation op; | |
230 | op.read(0, 0, nullptr, nullptr); | |
231 | f1 = librados::async_operate(service, io, "exist", &op, 0, | |
232 | boost::asio::use_future); | |
233 | } | |
234 | std::future<bufferlist> f2; | |
235 | { | |
236 | librados::ObjectReadOperation op; | |
237 | op.read(0, 0, nullptr, nullptr); | |
238 | f2 = librados::async_operate(service, io, "noexist", &op, 0, | |
239 | boost::asio::use_future); | |
240 | } | |
241 | service.run(); | |
242 | ||
243 | EXPECT_NO_THROW({ | |
244 | auto bl = f1.get(); | |
245 | EXPECT_EQ("hello", bl.to_str()); | |
246 | }); | |
247 | EXPECT_THROW(f2.get(), boost::system::system_error); | |
248 | } | |
249 | ||
11fdf7f2 TL |
250 | TEST_F(AsioRados, AsyncReadOperationYield) |
251 | { | |
252 | boost::asio::io_service service; | |
253 | ||
254 | auto success_cr = [&] (boost::asio::yield_context yield) { | |
255 | librados::ObjectReadOperation op; | |
256 | op.read(0, 0, nullptr, nullptr); | |
257 | boost::system::error_code ec; | |
258 | auto bl = librados::async_operate(service, io, "exist", &op, 0, | |
259 | yield[ec]); | |
260 | EXPECT_FALSE(ec); | |
261 | EXPECT_EQ("hello", bl.to_str()); | |
262 | }; | |
263 | boost::asio::spawn(service, success_cr); | |
264 | ||
265 | auto failure_cr = [&] (boost::asio::yield_context yield) { | |
266 | librados::ObjectReadOperation op; | |
267 | op.read(0, 0, nullptr, nullptr); | |
268 | boost::system::error_code ec; | |
269 | auto bl = librados::async_operate(service, io, "noexist", &op, 0, | |
270 | yield[ec]); | |
271 | EXPECT_EQ(boost::system::errc::no_such_file_or_directory, ec); | |
272 | }; | |
273 | boost::asio::spawn(service, failure_cr); | |
274 | ||
275 | service.run(); | |
276 | } | |
11fdf7f2 TL |
277 | |
278 | TEST_F(AsioRados, AsyncWriteOperationCallback) | |
279 | { | |
280 | boost::asio::io_service service; | |
281 | ||
282 | bufferlist bl; | |
283 | bl.append("hello"); | |
284 | ||
285 | { | |
286 | librados::ObjectWriteOperation op; | |
287 | op.write_full(bl); | |
288 | auto success_cb = [&] (boost::system::error_code ec) { | |
289 | EXPECT_FALSE(ec); | |
290 | }; | |
291 | librados::async_operate(service, io, "exist", &op, 0, success_cb); | |
292 | } | |
293 | { | |
294 | librados::ObjectWriteOperation op; | |
295 | op.write_full(bl); | |
296 | auto failure_cb = [&] (boost::system::error_code ec) { | |
297 | EXPECT_EQ(boost::system::errc::read_only_file_system, ec); | |
298 | }; | |
299 | librados::async_operate(service, snapio, "exist", &op, 0, failure_cb); | |
300 | } | |
301 | service.run(); | |
302 | } | |
303 | ||
304 | TEST_F(AsioRados, AsyncWriteOperationFuture) | |
305 | { | |
306 | boost::asio::io_service service; | |
307 | ||
308 | bufferlist bl; | |
309 | bl.append("hello"); | |
310 | ||
311 | std::future<void> f1; | |
312 | { | |
313 | librados::ObjectWriteOperation op; | |
314 | op.write_full(bl); | |
315 | f1 = librados::async_operate(service, io, "exist", &op, 0, | |
316 | boost::asio::use_future); | |
317 | } | |
318 | std::future<void> f2; | |
319 | { | |
320 | librados::ObjectWriteOperation op; | |
321 | op.write_full(bl); | |
322 | f2 = librados::async_operate(service, snapio, "exist", &op, 0, | |
323 | boost::asio::use_future); | |
324 | } | |
325 | service.run(); | |
326 | ||
327 | EXPECT_NO_THROW(f1.get()); | |
328 | EXPECT_THROW(f2.get(), boost::system::system_error); | |
329 | } | |
330 | ||
11fdf7f2 TL |
331 | TEST_F(AsioRados, AsyncWriteOperationYield) |
332 | { | |
333 | boost::asio::io_service service; | |
334 | ||
335 | bufferlist bl; | |
336 | bl.append("hello"); | |
337 | ||
338 | auto success_cr = [&] (boost::asio::yield_context yield) { | |
339 | librados::ObjectWriteOperation op; | |
340 | op.write_full(bl); | |
341 | boost::system::error_code ec; | |
342 | librados::async_operate(service, io, "exist", &op, 0, yield[ec]); | |
343 | EXPECT_FALSE(ec); | |
344 | }; | |
345 | boost::asio::spawn(service, success_cr); | |
346 | ||
347 | auto failure_cr = [&] (boost::asio::yield_context yield) { | |
348 | librados::ObjectWriteOperation op; | |
349 | op.write_full(bl); | |
350 | boost::system::error_code ec; | |
351 | librados::async_operate(service, snapio, "exist", &op, 0, yield[ec]); | |
352 | EXPECT_EQ(boost::system::errc::read_only_file_system, ec); | |
353 | }; | |
354 | boost::asio::spawn(service, failure_cr); | |
355 | ||
356 | service.run(); | |
357 | } | |
11fdf7f2 TL |
358 | |
359 | int main(int argc, char **argv) | |
360 | { | |
20effc67 | 361 | auto args = argv_to_vec(argc, argv); |
11fdf7f2 TL |
362 | env_to_vec(args); |
363 | ||
364 | auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, | |
365 | CODE_ENVIRONMENT_UTILITY, 0); | |
366 | common_init_finish(cct.get()); | |
367 | ||
368 | ::testing::InitGoogleTest(&argc, argv); | |
369 | return RUN_ALL_TESTS(); | |
370 | } |