]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/rgw/rgw_cr_test.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / rgw / rgw_cr_test.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
3
4 #include <cerrno>
5 #include <iostream>
6 #include <sstream>
7 #include <string>
8
9 #include <fmt/format.h>
10
11 #include "include/rados/librados.hpp"
12
13 #include "common/common_init.h"
14 #include "common/config.h"
15 #include "common/ceph_argparse.h"
16 #include "common/debug.h"
17
18 #include "rgw_coroutine.h"
19 #include "rgw_cr_rados.h"
20 #include "rgw_sal.h"
21 #include "rgw_sal_rados.h"
22
23 #include "gtest/gtest.h"
24
25 using namespace std::literals;
26
27 static constexpr auto dout_subsys = ceph_subsys_rgw;
28
29 static rgw::sal::RadosStore* store = nullptr;
30
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; }
36 };
37 static GlobalPrefix global_dpp;
38 return &global_dpp;
39 }
40
41 class StoreDestructor {
42 rgw::sal::Driver* driver;
43 public:
44 explicit StoreDestructor(rgw::sal::RadosStore* _s) : driver(_s) {}
45 ~StoreDestructor() {
46 DriverManager::close_storage(store);
47 }
48 };
49
50 struct TempPool {
51 inline static uint64_t num = 0;
52 std::string name =
53 fmt::format("{}-{}-{}", ::time(nullptr), ::getpid(),num++);
54
55 TempPool() {
56 auto r = store->getRados()->get_rados_handle()->pool_create(name.c_str());
57 assert(r == 0);
58 }
59
60 ~TempPool() {
61 auto r = store->getRados()->get_rados_handle()->pool_delete(name.c_str());
62 assert(r == 0);
63 }
64
65 operator rgw_pool() {
66 return { name };
67 }
68
69 operator librados::IoCtx() {
70 librados::IoCtx ioctx;
71 auto r = store->getRados()->get_rados_handle()->ioctx_create(name.c_str(),
72 ioctx);
73 assert(r == 0);
74 return ioctx;
75 }
76 };
77
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);
83 stack->call(cr);
84 stacks.push_back(stack);
85 return cr_mgr.run(dpp(), stacks);
86 }
87
88 TEST(ReadAttrs, Unfiltered) {
89 TempPool pool;
90 ceph::bufferlist bl;
91 auto dummy = "Dummy attribute value"s;
92 encode(dummy, bl);
93 const std::map<std::string, ceph::bufferlist> ref_attrs{
94 { "foo"s, bl }, { "bar"s, bl }, { "baz"s, bl }
95 };
96 auto oid = "object"s;
97 {
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);
104 ASSERT_EQ(0, r);
105 }
106 std::map<std::string, ceph::bufferlist> attrs;
107 auto r = run(new RGWSimpleRadosReadAttrsCR(dpp(), store, {pool, oid}, &attrs,
108 true));
109 ASSERT_EQ(0, r);
110 ASSERT_EQ(ref_attrs, attrs);
111 }
112
113 TEST(ReadAttrs, Filtered) {
114 TempPool pool;
115 ceph::bufferlist bl;
116 auto dummy = "Dummy attribute value"s;
117 encode(dummy, bl);
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 }
122 };
123 auto oid = "object"s;
124 {
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);
132 ASSERT_EQ(0, r);
133 }
134 std::map<std::string, ceph::bufferlist> attrs;
135 auto r = run(new RGWSimpleRadosReadAttrsCR(dpp(), store, {pool, oid}, &attrs,
136 false));
137 ASSERT_EQ(0, r);
138 ASSERT_EQ(ref_attrs, attrs);
139 }
140
141 TEST(Read, Dne) {
142 TempPool pool;
143 std::string result;
144 auto r = run(new RGWSimpleRadosReadCR(dpp(), store, {pool, "doesnotexist"},
145 &result, false));
146 ASSERT_EQ(-ENOENT, r);
147 }
148
149 TEST(Read, Read) {
150 TempPool pool;
151 auto data = "I am test data!"sv;
152 auto oid = "object"s;
153 {
154 bufferlist bl;
155 encode(data, bl);
156 librados::IoCtx ioctx(pool);
157 auto r = ioctx.write_full(oid, bl);
158 ASSERT_EQ(0, r);
159 }
160 std::string result;
161 auto r = run(new RGWSimpleRadosReadCR(dpp(), store, {pool, oid}, &result,
162 false));
163 ASSERT_EQ(0, r);
164 ASSERT_EQ(result, data);
165 }
166
167 TEST(Read, ReadVersion) {
168 TempPool pool;
169 auto data = "I am test data!"sv;
170 auto oid = "object"s;
171 RGWObjVersionTracker wobjv;
172 {
173 bufferlist bl;
174 encode(data, bl);
175 librados::IoCtx ioctx(pool);
176 librados::ObjectWriteOperation op;
177 wobjv.generate_new_write_ver(store->ctx());
178 wobjv.prepare_op_for_write(&op);
179 op.write_full(bl);
180 auto r = ioctx.operate(oid, &op);
181 EXPECT_EQ(0, r);
182 wobjv.apply_write();
183 }
184 RGWObjVersionTracker robjv;
185 std::string result;
186 auto r = run(new RGWSimpleRadosReadCR(dpp(), store, {pool, oid}, &result,
187 false, &robjv));
188 ASSERT_EQ(0, r);
189 ASSERT_EQ(result, data);
190 data = "I am NEW test data!";
191 {
192 bufferlist bl;
193 encode(data, bl);
194 librados::IoCtx ioctx(pool);
195 librados::ObjectWriteOperation op;
196 wobjv.generate_new_write_ver(store->ctx());
197 wobjv.prepare_op_for_write(&op);
198 op.write_full(bl);
199 r = ioctx.operate(oid, &op);
200 EXPECT_EQ(0, r);
201 wobjv.apply_write();
202 }
203 result.clear();
204 r = run(new RGWSimpleRadosReadCR(dpp(), store, {pool, oid}, &result, false,
205 &robjv));
206 ASSERT_EQ(-ECANCELED, r);
207 ASSERT_TRUE(result.empty());
208
209 robjv.clear();
210 r = run(new RGWSimpleRadosReadCR(dpp(), store, {pool, oid}, &result, false,
211 &robjv));
212 ASSERT_EQ(0, r);
213 ASSERT_EQ(result, data);
214 ASSERT_EQ(wobjv.read_version, robjv.read_version);
215 }
216
217 TEST(Write, Exclusive) {
218 TempPool pool;
219 auto oid = "object"s;
220 {
221 bufferlist bl;
222 bl.append("I'm some data!"s);
223 librados::IoCtx ioctx(pool);
224 auto r = ioctx.write_full(oid, bl);
225 ASSERT_EQ(0, r);
226 }
227 auto r = run(new RGWSimpleRadosWriteCR(dpp(), store, {pool, oid},
228 "I am some DIFFERENT data!"s, nullptr,
229 true));
230 ASSERT_EQ(-EEXIST, r);
231 }
232
233 TEST(Write, Write) {
234 TempPool pool;
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));
239 ASSERT_EQ(0, r);
240 bufferlist bl;
241 librados::IoCtx ioctx(pool);
242 ioctx.read(oid, bl, 0, 0);
243 ASSERT_EQ(0, r);
244 std::string result;
245 decode(result, bl);
246 ASSERT_EQ(data, result);
247 }
248
249 TEST(Write, ObjV) {
250 TempPool pool;
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,
256 true));
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));
261 ASSERT_EQ(0, r);
262 r = run(new RGWSimpleRadosWriteCR(dpp(), store, {pool, oid},
263 "I'm some treacherous, obsolete data!"s,
264 &objv, false));
265 ASSERT_EQ(-ECANCELED, r);
266 }
267
268 TEST(WriteAttrs, Attrs) {
269 TempPool pool;
270 auto oid = "object"s;
271 bufferlist bl;
272 bl.append("I'm some data.");
273 std::map<std::string, bufferlist> wrattrs {
274 { "foo", bl }, { "bar", bl }, { "baz", bl }
275 };
276 auto r = run(new RGWSimpleRadosWriteAttrsCR(dpp(), store, {pool, oid},
277 wrattrs, nullptr, true));
278 ASSERT_EQ(0, r);
279 std::map<std::string, bufferlist> rdattrs;
280 librados::IoCtx ioctx(pool);
281 r = ioctx.getxattrs(oid, rdattrs);
282 ASSERT_EQ(0, r);
283 ASSERT_EQ(wrattrs, rdattrs);
284 }
285
286 TEST(WriteAttrs, Empty) {
287 TempPool pool;
288 auto oid = "object"s;
289 bufferlist bl;
290 std::map<std::string, bufferlist> wrattrs {
291 { "foo", bl }, { "bar", bl }, { "baz", bl }
292 };
293 // With an empty bufferlist all attributes should be skipped.
294 auto r = run(new RGWSimpleRadosWriteAttrsCR(dpp(), store, {pool, oid},
295 wrattrs, nullptr, true));
296 ASSERT_EQ(0, r);
297 std::map<std::string, bufferlist> rdattrs;
298 librados::IoCtx ioctx(pool);
299 r = ioctx.getxattrs(oid, rdattrs);
300 ASSERT_EQ(0, r);
301 ASSERT_TRUE(rdattrs.empty());
302 }
303
304 int main(int argc, const char **argv)
305 {
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);
309
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());
313 }
314
315 /* common_init_finish needs to be called after g_conf().set_val() */
316 common_init_finish(g_ceph_context);
317
318
319 DriverManager::Config cfg = DriverManager::get_config(true, g_ceph_context);
320
321 store = static_cast<rgw::sal::RadosStore*>(
322 DriverManager::get_storage(dpp(),
323 g_ceph_context,
324 cfg,
325 false,
326 false,
327 false,
328 false,
329 false,
330 true,
331 false));
332 if (!store) {
333 std::cerr << "couldn't init storage provider" << std::endl;
334 return 5; //EIO
335 }
336 StoreDestructor store_destructor(static_cast<rgw::sal::RadosStore*>(store));
337
338 std::string pool{"rgw_cr_test"};
339 store->getRados()->create_pool(dpp(), pool);
340
341 testing::InitGoogleTest();
342 return RUN_ALL_TESTS();
343 }