]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librados/asio.cc
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / test / librados / asio.cc
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/range/begin.hpp>
25 #include <boost/range/end.hpp>
26 #include <boost/asio/spawn.hpp>
27 #endif
28 #include <boost/asio/use_future.hpp>
29
30 #define dout_subsys ceph_subsys_rados
31 #define dout_context g_ceph_context
32
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
112 #ifdef HAVE_BOOST_CONTEXT
113 TEST_F(AsioRados, AsyncReadYield)
114 {
115 boost::asio::io_service service;
116
117 auto success_cr = [&] (boost::asio::yield_context yield) {
118 boost::system::error_code ec;
119 auto bl = librados::async_read(service, io, "exist", 256, 0, yield[ec]);
120 EXPECT_FALSE(ec);
121 EXPECT_EQ("hello", bl.to_str());
122 };
123 boost::asio::spawn(service, success_cr);
124
125 auto failure_cr = [&] (boost::asio::yield_context yield) {
126 boost::system::error_code ec;
127 auto bl = librados::async_read(service, io, "noexist", 256, 0, yield[ec]);
128 EXPECT_EQ(boost::system::errc::no_such_file_or_directory, ec);
129 };
130 boost::asio::spawn(service, failure_cr);
131
132 service.run();
133 }
134 #endif
135
136 TEST_F(AsioRados, AsyncWriteCallback)
137 {
138 boost::asio::io_service service;
139
140 bufferlist bl;
141 bl.append("hello");
142
143 auto success_cb = [&] (boost::system::error_code ec) {
144 EXPECT_FALSE(ec);
145 };
146 librados::async_write(service, io, "exist", bl, bl.length(), 0,
147 success_cb);
148
149 auto failure_cb = [&] (boost::system::error_code ec) {
150 EXPECT_EQ(boost::system::errc::read_only_file_system, ec);
151 };
152 librados::async_write(service, snapio, "exist", bl, bl.length(), 0,
153 failure_cb);
154
155 service.run();
156 }
157
158 TEST_F(AsioRados, AsyncWriteFuture)
159 {
160 boost::asio::io_service service;
161
162 bufferlist bl;
163 bl.append("hello");
164
165 auto f1 = librados::async_write(service, io, "exist", bl, bl.length(), 0,
166 boost::asio::use_future);
167 auto f2 = librados::async_write(service, snapio, "exist", bl, bl.length(), 0,
168 boost::asio::use_future);
169
170 service.run();
171
172 EXPECT_NO_THROW(f1.get());
173 EXPECT_THROW(f2.get(), boost::system::system_error);
174 }
175
176 #ifdef HAVE_BOOST_CONTEXT
177 TEST_F(AsioRados, AsyncWriteYield)
178 {
179 boost::asio::io_service service;
180
181 bufferlist bl;
182 bl.append("hello");
183
184 auto success_cr = [&] (boost::asio::yield_context yield) {
185 boost::system::error_code ec;
186 librados::async_write(service, io, "exist", bl, bl.length(), 0,
187 yield[ec]);
188 EXPECT_FALSE(ec);
189 EXPECT_EQ("hello", bl.to_str());
190 };
191 boost::asio::spawn(service, success_cr);
192
193 auto failure_cr = [&] (boost::asio::yield_context yield) {
194 boost::system::error_code ec;
195 librados::async_write(service, snapio, "exist", bl, bl.length(), 0,
196 yield[ec]);
197 EXPECT_EQ(boost::system::errc::read_only_file_system, ec);
198 };
199 boost::asio::spawn(service, failure_cr);
200
201 service.run();
202 }
203 #endif
204
205 TEST_F(AsioRados, AsyncReadOperationCallback)
206 {
207 boost::asio::io_service service;
208 {
209 librados::ObjectReadOperation op;
210 op.read(0, 0, nullptr, nullptr);
211 auto success_cb = [&] (boost::system::error_code ec, bufferlist bl) {
212 EXPECT_FALSE(ec);
213 EXPECT_EQ("hello", bl.to_str());
214 };
215 librados::async_operate(service, io, "exist", &op, 0, success_cb);
216 }
217 {
218 librados::ObjectReadOperation op;
219 op.read(0, 0, nullptr, nullptr);
220 auto failure_cb = [&] (boost::system::error_code ec, bufferlist bl) {
221 EXPECT_EQ(boost::system::errc::no_such_file_or_directory, ec);
222 };
223 librados::async_operate(service, io, "noexist", &op, 0, failure_cb);
224 }
225 service.run();
226 }
227
228 TEST_F(AsioRados, AsyncReadOperationFuture)
229 {
230 boost::asio::io_service service;
231 std::future<bufferlist> f1;
232 {
233 librados::ObjectReadOperation op;
234 op.read(0, 0, nullptr, nullptr);
235 f1 = librados::async_operate(service, io, "exist", &op, 0,
236 boost::asio::use_future);
237 }
238 std::future<bufferlist> f2;
239 {
240 librados::ObjectReadOperation op;
241 op.read(0, 0, nullptr, nullptr);
242 f2 = librados::async_operate(service, io, "noexist", &op, 0,
243 boost::asio::use_future);
244 }
245 service.run();
246
247 EXPECT_NO_THROW({
248 auto bl = f1.get();
249 EXPECT_EQ("hello", bl.to_str());
250 });
251 EXPECT_THROW(f2.get(), boost::system::system_error);
252 }
253
254 #ifdef HAVE_BOOST_CONTEXT
255 TEST_F(AsioRados, AsyncReadOperationYield)
256 {
257 boost::asio::io_service service;
258
259 auto success_cr = [&] (boost::asio::yield_context yield) {
260 librados::ObjectReadOperation op;
261 op.read(0, 0, nullptr, nullptr);
262 boost::system::error_code ec;
263 auto bl = librados::async_operate(service, io, "exist", &op, 0,
264 yield[ec]);
265 EXPECT_FALSE(ec);
266 EXPECT_EQ("hello", bl.to_str());
267 };
268 boost::asio::spawn(service, success_cr);
269
270 auto failure_cr = [&] (boost::asio::yield_context yield) {
271 librados::ObjectReadOperation op;
272 op.read(0, 0, nullptr, nullptr);
273 boost::system::error_code ec;
274 auto bl = librados::async_operate(service, io, "noexist", &op, 0,
275 yield[ec]);
276 EXPECT_EQ(boost::system::errc::no_such_file_or_directory, ec);
277 };
278 boost::asio::spawn(service, failure_cr);
279
280 service.run();
281 }
282 #endif
283
284 TEST_F(AsioRados, AsyncWriteOperationCallback)
285 {
286 boost::asio::io_service service;
287
288 bufferlist bl;
289 bl.append("hello");
290
291 {
292 librados::ObjectWriteOperation op;
293 op.write_full(bl);
294 auto success_cb = [&] (boost::system::error_code ec) {
295 EXPECT_FALSE(ec);
296 };
297 librados::async_operate(service, io, "exist", &op, 0, success_cb);
298 }
299 {
300 librados::ObjectWriteOperation op;
301 op.write_full(bl);
302 auto failure_cb = [&] (boost::system::error_code ec) {
303 EXPECT_EQ(boost::system::errc::read_only_file_system, ec);
304 };
305 librados::async_operate(service, snapio, "exist", &op, 0, failure_cb);
306 }
307 service.run();
308 }
309
310 TEST_F(AsioRados, AsyncWriteOperationFuture)
311 {
312 boost::asio::io_service service;
313
314 bufferlist bl;
315 bl.append("hello");
316
317 std::future<void> f1;
318 {
319 librados::ObjectWriteOperation op;
320 op.write_full(bl);
321 f1 = librados::async_operate(service, io, "exist", &op, 0,
322 boost::asio::use_future);
323 }
324 std::future<void> f2;
325 {
326 librados::ObjectWriteOperation op;
327 op.write_full(bl);
328 f2 = librados::async_operate(service, snapio, "exist", &op, 0,
329 boost::asio::use_future);
330 }
331 service.run();
332
333 EXPECT_NO_THROW(f1.get());
334 EXPECT_THROW(f2.get(), boost::system::system_error);
335 }
336
337 #ifdef HAVE_BOOST_CONTEXT
338 TEST_F(AsioRados, AsyncWriteOperationYield)
339 {
340 boost::asio::io_service service;
341
342 bufferlist bl;
343 bl.append("hello");
344
345 auto success_cr = [&] (boost::asio::yield_context yield) {
346 librados::ObjectWriteOperation op;
347 op.write_full(bl);
348 boost::system::error_code ec;
349 librados::async_operate(service, io, "exist", &op, 0, yield[ec]);
350 EXPECT_FALSE(ec);
351 };
352 boost::asio::spawn(service, success_cr);
353
354 auto failure_cr = [&] (boost::asio::yield_context yield) {
355 librados::ObjectWriteOperation op;
356 op.write_full(bl);
357 boost::system::error_code ec;
358 librados::async_operate(service, snapio, "exist", &op, 0, yield[ec]);
359 EXPECT_EQ(boost::system::errc::read_only_file_system, ec);
360 };
361 boost::asio::spawn(service, failure_cr);
362
363 service.run();
364 }
365 #endif
366
367 int main(int argc, char **argv)
368 {
369 vector<const char*> args;
370 argv_to_vec(argc, (const char **)argv, args);
371 env_to_vec(args);
372
373 auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
374 CODE_ENVIRONMENT_UTILITY, 0);
375 common_init_finish(cct.get());
376
377 ::testing::InitGoogleTest(&argc, argv);
378 return RUN_ALL_TESTS();
379 }