1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2017 Red Hat, Inc.
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.
14 #include "librados/librados_asio.h"
15 #include <gtest/gtest.h>
17 #include "common/ceph_argparse.h"
18 #include "common/debug.h"
19 #include "common/errno.h"
20 #include "global/global_init.h"
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>
28 #include <boost/asio/use_future.hpp>
30 #define dout_subsys ceph_subsys_rados
31 #define dout_context g_ceph_context
33 // test fixture for global setup/teardown
34 class AsioRados
: public ::testing::Test
{
35 static constexpr auto poolname
= "ceph_test_rados_api_asio";
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
;
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
);
52 r
= rados
.pool_create(poolname
);
56 r
= rados
.ioctx_create(poolname
, io
);
60 ASSERT_EQ(0, rados
.ioctx_create(poolname
, snapio
));
61 snapio
.snap_set_read(1);
62 // initialize the "exist" object
65 ASSERT_EQ(0, io
.write_full("exist", bl
));
68 static void TearDownTestCase() {
72 librados::Rados
AsioRados::rados
;
73 librados::IoCtx
AsioRados::io
;
74 librados::IoCtx
AsioRados::snapio
;
76 TEST_F(AsioRados
, AsyncReadCallback
)
78 boost::asio::io_service service
;
80 auto success_cb
= [&] (boost::system::error_code ec
, bufferlist bl
) {
82 EXPECT_EQ("hello", bl
.to_str());
84 librados::async_read(service
, io
, "exist", 256, 0, success_cb
);
86 auto failure_cb
= [&] (boost::system::error_code ec
, bufferlist bl
) {
87 EXPECT_EQ(boost::system::errc::no_such_file_or_directory
, ec
);
89 librados::async_read(service
, io
, "noexist", 256, 0, failure_cb
);
94 TEST_F(AsioRados
, AsyncReadFuture
)
96 boost::asio::io_service service
;
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
);
107 EXPECT_EQ("hello", bl
.to_str());
109 EXPECT_THROW(f2
.get(), boost::system::system_error
);
112 #ifdef HAVE_BOOST_CONTEXT
113 TEST_F(AsioRados
, AsyncReadYield
)
115 boost::asio::io_service service
;
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
]);
121 EXPECT_EQ("hello", bl
.to_str());
123 boost::asio::spawn(service
, success_cr
);
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
);
130 boost::asio::spawn(service
, failure_cr
);
136 TEST_F(AsioRados
, AsyncWriteCallback
)
138 boost::asio::io_service service
;
143 auto success_cb
= [&] (boost::system::error_code ec
) {
146 librados::async_write(service
, io
, "exist", bl
, bl
.length(), 0,
149 auto failure_cb
= [&] (boost::system::error_code ec
) {
150 EXPECT_EQ(boost::system::errc::read_only_file_system
, ec
);
152 librados::async_write(service
, snapio
, "exist", bl
, bl
.length(), 0,
158 TEST_F(AsioRados
, AsyncWriteFuture
)
160 boost::asio::io_service service
;
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
);
172 EXPECT_NO_THROW(f1
.get());
173 EXPECT_THROW(f2
.get(), boost::system::system_error
);
176 #ifdef HAVE_BOOST_CONTEXT
177 TEST_F(AsioRados
, AsyncWriteYield
)
179 boost::asio::io_service service
;
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,
189 EXPECT_EQ("hello", bl
.to_str());
191 boost::asio::spawn(service
, success_cr
);
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,
197 EXPECT_EQ(boost::system::errc::read_only_file_system
, ec
);
199 boost::asio::spawn(service
, failure_cr
);
205 TEST_F(AsioRados
, AsyncReadOperationCallback
)
207 boost::asio::io_service service
;
209 librados::ObjectReadOperation op
;
210 op
.read(0, 0, nullptr, nullptr);
211 auto success_cb
= [&] (boost::system::error_code ec
, bufferlist bl
) {
213 EXPECT_EQ("hello", bl
.to_str());
215 librados::async_operate(service
, io
, "exist", &op
, 0, success_cb
);
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
);
223 librados::async_operate(service
, io
, "noexist", &op
, 0, failure_cb
);
228 TEST_F(AsioRados
, AsyncReadOperationFuture
)
230 boost::asio::io_service service
;
231 std::future
<bufferlist
> f1
;
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
);
238 std::future
<bufferlist
> f2
;
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
);
249 EXPECT_EQ("hello", bl
.to_str());
251 EXPECT_THROW(f2
.get(), boost::system::system_error
);
254 #ifdef HAVE_BOOST_CONTEXT
255 TEST_F(AsioRados
, AsyncReadOperationYield
)
257 boost::asio::io_service service
;
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,
266 EXPECT_EQ("hello", bl
.to_str());
268 boost::asio::spawn(service
, success_cr
);
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,
276 EXPECT_EQ(boost::system::errc::no_such_file_or_directory
, ec
);
278 boost::asio::spawn(service
, failure_cr
);
284 TEST_F(AsioRados
, AsyncWriteOperationCallback
)
286 boost::asio::io_service service
;
292 librados::ObjectWriteOperation op
;
294 auto success_cb
= [&] (boost::system::error_code ec
) {
297 librados::async_operate(service
, io
, "exist", &op
, 0, success_cb
);
300 librados::ObjectWriteOperation op
;
302 auto failure_cb
= [&] (boost::system::error_code ec
) {
303 EXPECT_EQ(boost::system::errc::read_only_file_system
, ec
);
305 librados::async_operate(service
, snapio
, "exist", &op
, 0, failure_cb
);
310 TEST_F(AsioRados
, AsyncWriteOperationFuture
)
312 boost::asio::io_service service
;
317 std::future
<void> f1
;
319 librados::ObjectWriteOperation op
;
321 f1
= librados::async_operate(service
, io
, "exist", &op
, 0,
322 boost::asio::use_future
);
324 std::future
<void> f2
;
326 librados::ObjectWriteOperation op
;
328 f2
= librados::async_operate(service
, snapio
, "exist", &op
, 0,
329 boost::asio::use_future
);
333 EXPECT_NO_THROW(f1
.get());
334 EXPECT_THROW(f2
.get(), boost::system::system_error
);
337 #ifdef HAVE_BOOST_CONTEXT
338 TEST_F(AsioRados
, AsyncWriteOperationYield
)
340 boost::asio::io_service service
;
345 auto success_cr
= [&] (boost::asio::yield_context yield
) {
346 librados::ObjectWriteOperation op
;
348 boost::system::error_code ec
;
349 librados::async_operate(service
, io
, "exist", &op
, 0, yield
[ec
]);
352 boost::asio::spawn(service
, success_cr
);
354 auto failure_cr
= [&] (boost::asio::yield_context yield
) {
355 librados::ObjectWriteOperation op
;
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
);
361 boost::asio::spawn(service
, failure_cr
);
367 int main(int argc
, char **argv
)
369 vector
<const char*> args
;
370 argv_to_vec(argc
, (const char **)argv
, args
);
373 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
374 CODE_ENVIRONMENT_UTILITY
, 0);
375 common_init_finish(cct
.get());
377 ::testing::InitGoogleTest(&argc
, argv
);
378 return RUN_ALL_TESTS();