1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
9 #include <fmt/format.h>
11 #include "include/rados/librados.hpp"
13 #include "common/common_init.h"
14 #include "common/config.h"
15 #include "common/ceph_argparse.h"
16 #include "common/debug.h"
18 #include "rgw_coroutine.h"
19 #include "rgw_cr_rados.h"
21 #include "rgw_sal_rados.h"
23 #include "gtest/gtest.h"
25 using namespace std::literals
;
27 static constexpr auto dout_subsys
= ceph_subsys_rgw
;
29 static rgw::sal::RadosStore
* store
= nullptr;
31 static const DoutPrefixProvider
* dpp() {
32 struct GlobalPrefix
: public DoutPrefixProvider
{
33 CephContext
*get_cct() const override
{ return g_ceph_context
; }
34 unsigned get_subsys() const override
{ return dout_subsys
; }
35 std::ostream
& gen_prefix(std::ostream
& out
) const override
{ return out
; }
37 static GlobalPrefix global_dpp
;
41 class StoreDestructor
{
42 rgw::sal::Driver
* driver
;
44 explicit StoreDestructor(rgw::sal::RadosStore
* _s
) : driver(_s
) {}
46 DriverManager::close_storage(store
);
51 inline static uint64_t num
= 0;
53 fmt::format("{}-{}-{}", ::time(nullptr), ::getpid(),num
++);
56 auto r
= store
->getRados()->get_rados_handle()->pool_create(name
.c_str());
61 auto r
= store
->getRados()->get_rados_handle()->pool_delete(name
.c_str());
69 operator librados::IoCtx() {
70 librados::IoCtx ioctx
;
71 auto r
= store
->getRados()->get_rados_handle()->ioctx_create(name
.c_str(),
78 int run(RGWCoroutine
* cr
) {
79 RGWCoroutinesManager cr_mgr
{store
->ctx(),
80 store
->getRados()->get_cr_registry()};
81 std::list
<RGWCoroutinesStack
*> stacks
;
82 auto stack
= new RGWCoroutinesStack(store
->ctx(), &cr_mgr
);
84 stacks
.push_back(stack
);
85 return cr_mgr
.run(dpp(), stacks
);
88 TEST(ReadAttrs
, Unfiltered
) {
91 auto dummy
= "Dummy attribute value"s
;
93 const std::map
<std::string
, ceph::bufferlist
> ref_attrs
{
94 { "foo"s
, bl
}, { "bar"s
, bl
}, { "baz"s
, bl
}
98 librados::IoCtx
ioctx(pool
);
99 librados::ObjectWriteOperation op
;
100 op
.setxattr("foo", bl
);
101 op
.setxattr("bar", bl
);
102 op
.setxattr("baz", bl
);
103 auto r
= ioctx
.operate(oid
, &op
);
106 std::map
<std::string
, ceph::bufferlist
> attrs
;
107 auto r
= run(new RGWSimpleRadosReadAttrsCR(dpp(), store
, {pool
, oid
}, &attrs
,
110 ASSERT_EQ(ref_attrs
, attrs
);
113 TEST(ReadAttrs
, Filtered
) {
116 auto dummy
= "Dummy attribute value"s
;
118 const std::map
<std::string
, ceph::bufferlist
> ref_attrs
{
119 { RGW_ATTR_PREFIX
"foo"s
, bl
},
120 { RGW_ATTR_PREFIX
"bar"s
, bl
},
121 { RGW_ATTR_PREFIX
"baz"s
, bl
}
123 auto oid
= "object"s
;
125 librados::IoCtx
ioctx(pool
);
126 librados::ObjectWriteOperation op
;
127 op
.setxattr(RGW_ATTR_PREFIX
"foo", bl
);
128 op
.setxattr(RGW_ATTR_PREFIX
"bar", bl
);
129 op
.setxattr(RGW_ATTR_PREFIX
"baz", bl
);
130 op
.setxattr("oneOfTheseThingsIsNotLikeTheOthers", bl
);
131 auto r
= ioctx
.operate(oid
, &op
);
134 std::map
<std::string
, ceph::bufferlist
> attrs
;
135 auto r
= run(new RGWSimpleRadosReadAttrsCR(dpp(), store
, {pool
, oid
}, &attrs
,
138 ASSERT_EQ(ref_attrs
, attrs
);
144 auto r
= run(new RGWSimpleRadosReadCR(dpp(), store
, {pool
, "doesnotexist"},
146 ASSERT_EQ(-ENOENT
, r
);
151 auto data
= "I am test data!"sv
;
152 auto oid
= "object"s
;
156 librados::IoCtx
ioctx(pool
);
157 auto r
= ioctx
.write_full(oid
, bl
);
161 auto r
= run(new RGWSimpleRadosReadCR(dpp(), store
, {pool
, oid
}, &result
,
164 ASSERT_EQ(result
, data
);
167 TEST(Read
, ReadVersion
) {
169 auto data
= "I am test data!"sv
;
170 auto oid
= "object"s
;
171 RGWObjVersionTracker wobjv
;
175 librados::IoCtx
ioctx(pool
);
176 librados::ObjectWriteOperation op
;
177 wobjv
.generate_new_write_ver(store
->ctx());
178 wobjv
.prepare_op_for_write(&op
);
180 auto r
= ioctx
.operate(oid
, &op
);
184 RGWObjVersionTracker robjv
;
186 auto r
= run(new RGWSimpleRadosReadCR(dpp(), store
, {pool
, oid
}, &result
,
189 ASSERT_EQ(result
, data
);
190 data
= "I am NEW test data!";
194 librados::IoCtx
ioctx(pool
);
195 librados::ObjectWriteOperation op
;
196 wobjv
.generate_new_write_ver(store
->ctx());
197 wobjv
.prepare_op_for_write(&op
);
199 r
= ioctx
.operate(oid
, &op
);
204 r
= run(new RGWSimpleRadosReadCR(dpp(), store
, {pool
, oid
}, &result
, false,
206 ASSERT_EQ(-ECANCELED
, r
);
207 ASSERT_TRUE(result
.empty());
210 r
= run(new RGWSimpleRadosReadCR(dpp(), store
, {pool
, oid
}, &result
, false,
213 ASSERT_EQ(result
, data
);
214 ASSERT_EQ(wobjv
.read_version
, robjv
.read_version
);
217 TEST(Write
, Exclusive
) {
219 auto oid
= "object"s
;
222 bl
.append("I'm some data!"s
);
223 librados::IoCtx
ioctx(pool
);
224 auto r
= ioctx
.write_full(oid
, bl
);
227 auto r
= run(new RGWSimpleRadosWriteCR(dpp(), store
, {pool
, oid
},
228 "I am some DIFFERENT data!"s
, nullptr,
230 ASSERT_EQ(-EEXIST
, r
);
235 auto oid
= "object"s
;
236 auto data
= "I'm some data!"s
;
237 auto r
= run(new RGWSimpleRadosWriteCR(dpp(), store
, {pool
, oid
},
238 data
, nullptr, true));
241 librados::IoCtx
ioctx(pool
);
242 ioctx
.read(oid
, bl
, 0, 0);
246 ASSERT_EQ(data
, result
);
251 auto oid
= "object"s
;
252 RGWObjVersionTracker objv
;
253 objv
.generate_new_write_ver(store
->ctx());
254 auto r
= run(new RGWSimpleRadosWriteCR(dpp(), store
, {pool
, oid
},
255 "I'm some data!"s
, &objv
,
257 RGWObjVersionTracker
interfering_objv(objv
);
258 r
= run(new RGWSimpleRadosWriteCR(dpp(), store
, {pool
, oid
},
259 "I'm some newer, better data!"s
,
260 &interfering_objv
, false));
262 r
= run(new RGWSimpleRadosWriteCR(dpp(), store
, {pool
, oid
},
263 "I'm some treacherous, obsolete data!"s
,
265 ASSERT_EQ(-ECANCELED
, r
);
268 TEST(WriteAttrs
, Attrs
) {
270 auto oid
= "object"s
;
272 bl
.append("I'm some data.");
273 std::map
<std::string
, bufferlist
> wrattrs
{
274 { "foo", bl
}, { "bar", bl
}, { "baz", bl
}
276 auto r
= run(new RGWSimpleRadosWriteAttrsCR(dpp(), store
, {pool
, oid
},
277 wrattrs
, nullptr, true));
279 std::map
<std::string
, bufferlist
> rdattrs
;
280 librados::IoCtx
ioctx(pool
);
281 r
= ioctx
.getxattrs(oid
, rdattrs
);
283 ASSERT_EQ(wrattrs
, rdattrs
);
286 TEST(WriteAttrs
, Empty
) {
288 auto oid
= "object"s
;
290 std::map
<std::string
, bufferlist
> wrattrs
{
291 { "foo", bl
}, { "bar", bl
}, { "baz", bl
}
293 // With an empty bufferlist all attributes should be skipped.
294 auto r
= run(new RGWSimpleRadosWriteAttrsCR(dpp(), store
, {pool
, oid
},
295 wrattrs
, nullptr, true));
297 std::map
<std::string
, bufferlist
> rdattrs
;
298 librados::IoCtx
ioctx(pool
);
299 r
= ioctx
.getxattrs(oid
, rdattrs
);
301 ASSERT_TRUE(rdattrs
.empty());
304 int main(int argc
, const char **argv
)
306 auto args
= argv_to_vec(argc
, argv
);
307 auto cct
= rgw_global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
308 CODE_ENVIRONMENT_UTILITY
, 0);
310 // for region -> zonegroup conversion (must happen before common_init_finish())
311 if (!g_conf()->rgw_region
.empty() && g_conf()->rgw_zonegroup
.empty()) {
312 g_conf().set_val_or_die("rgw_zonegroup", g_conf()->rgw_region
.c_str());
315 /* common_init_finish needs to be called after g_conf().set_val() */
316 common_init_finish(g_ceph_context
);
319 DriverManager::Config cfg
= DriverManager::get_config(true, g_ceph_context
);
321 store
= static_cast<rgw::sal::RadosStore
*>(
322 DriverManager::get_storage(dpp(),
333 std::cerr
<< "couldn't init storage provider" << std::endl
;
336 StoreDestructor
store_destructor(static_cast<rgw::sal::RadosStore
*>(store
));
338 std::string pool
{"rgw_cr_test"};
339 store
->getRados()->create_pool(dpp(), pool
);
341 testing::InitGoogleTest();
342 return RUN_ALL_TESTS();