]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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) 2013 Inktank | |
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 | ||
15 | #include <iostream> | |
16 | #include <errno.h> | |
9f95a23c | 17 | #include <string> |
7c673cae FG |
18 | |
19 | #include "include/rados/librados.hpp" | |
20 | #include "include/encoding.h" | |
11fdf7f2 | 21 | #include "test/librados/test_cxx.h" |
7c673cae | 22 | #include "gtest/gtest.h" |
9f95a23c | 23 | #include "json_spirit/json_spirit.h" |
7c673cae FG |
24 | |
25 | using namespace librados; | |
26 | ||
27 | TEST(ClsHello, SayHello) { | |
28 | Rados cluster; | |
29 | std::string pool_name = get_temp_pool_name(); | |
30 | ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); | |
31 | IoCtx ioctx; | |
32 | cluster.ioctx_create(pool_name.c_str(), ioctx); | |
33 | ||
34 | bufferlist in, out; | |
35 | ASSERT_EQ(-ENOENT, ioctx.exec("myobject", "hello", "say_hello", in, out)); | |
36 | ASSERT_EQ(0, ioctx.write_full("myobject", in)); | |
37 | ASSERT_EQ(0, ioctx.exec("myobject", "hello", "say_hello", in, out)); | |
38 | ASSERT_EQ(std::string("Hello, world!"), std::string(out.c_str(), out.length())); | |
39 | ||
40 | out.clear(); | |
41 | in.append("Tester"); | |
42 | ASSERT_EQ(0, ioctx.exec("myobject", "hello", "say_hello", in, out)); | |
43 | ASSERT_EQ(std::string("Hello, Tester!"), std::string(out.c_str(), out.length())); | |
44 | ||
45 | out.clear(); | |
46 | in.clear(); | |
47 | char buf[4096]; | |
48 | memset(buf, 1, sizeof(buf)); | |
49 | in.append(buf, sizeof(buf)); | |
50 | ASSERT_EQ(-EINVAL, ioctx.exec("myobject", "hello", "say_hello", in, out)); | |
51 | ||
52 | ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); | |
53 | } | |
54 | ||
55 | TEST(ClsHello, RecordHello) { | |
56 | Rados cluster; | |
57 | std::string pool_name = get_temp_pool_name(); | |
58 | ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); | |
59 | IoCtx ioctx; | |
60 | cluster.ioctx_create(pool_name.c_str(), ioctx); | |
61 | ||
62 | bufferlist in, out; | |
63 | ASSERT_EQ(0, ioctx.exec("myobject", "hello", "record_hello", in, out)); | |
64 | ASSERT_EQ(-EEXIST, ioctx.exec("myobject", "hello", "record_hello", in, out)); | |
65 | ||
66 | in.append("Tester"); | |
67 | ASSERT_EQ(0, ioctx.exec("myobject2", "hello", "record_hello", in, out)); | |
68 | ASSERT_EQ(-EEXIST, ioctx.exec("myobject2", "hello", "record_hello", in, out)); | |
69 | ASSERT_EQ(0u, out.length()); | |
70 | ||
71 | in.clear(); | |
72 | out.clear(); | |
73 | ASSERT_EQ(0, ioctx.exec("myobject", "hello", "replay", in, out)); | |
74 | ASSERT_EQ(std::string("Hello, world!"), std::string(out.c_str(), out.length())); | |
75 | out.clear(); | |
76 | ASSERT_EQ(0, ioctx.exec("myobject2", "hello", "replay", in, out)); | |
77 | ASSERT_EQ(std::string("Hello, Tester!"), std::string(out.c_str(), out.length())); | |
78 | ||
79 | ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); | |
80 | } | |
81 | ||
9f95a23c TL |
82 | static std::string _get_required_osd_release(Rados& cluster) |
83 | { | |
84 | bufferlist inbl; | |
85 | std::string cmd = std::string("{\"prefix\": \"osd dump\",\"format\":\"json\"}"); | |
86 | bufferlist outbl; | |
87 | int r = cluster.mon_command(cmd, inbl, &outbl, NULL); | |
88 | ceph_assert(r >= 0); | |
89 | std::string outstr(outbl.c_str(), outbl.length()); | |
90 | json_spirit::Value v; | |
91 | if (!json_spirit::read(outstr, v)) { | |
92 | std::cerr <<" unable to parse json " << outstr << std::endl; | |
93 | return ""; | |
94 | } | |
95 | ||
96 | json_spirit::Object& o = v.get_obj(); | |
97 | for (json_spirit::Object::size_type i=0; i<o.size(); i++) { | |
98 | json_spirit::Pair& p = o[i]; | |
99 | if (p.name_ == "require_osd_release") { | |
100 | std::cout << "require_osd_release = " << p.value_.get_str() << std::endl; | |
101 | return p.value_.get_str(); | |
102 | } | |
103 | } | |
104 | std::cerr << "didn't find require_osd_release in " << outstr << std::endl; | |
105 | return ""; | |
106 | } | |
107 | ||
7c673cae FG |
108 | TEST(ClsHello, WriteReturnData) { |
109 | Rados cluster; | |
110 | std::string pool_name = get_temp_pool_name(); | |
111 | ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); | |
112 | IoCtx ioctx; | |
113 | cluster.ioctx_create(pool_name.c_str(), ioctx); | |
114 | ||
9f95a23c TL |
115 | // skip test if not yet mimic |
116 | if (_get_required_osd_release(cluster) < "octopus") { | |
117 | std::cout << "cluster is not yet octopus, skipping test" << std::endl; | |
118 | return; | |
119 | } | |
120 | ||
f67539c2 | 121 | // this will return nothing -- no flag is set |
7c673cae | 122 | bufferlist in, out; |
9f95a23c | 123 | ASSERT_EQ(0, ioctx.exec("myobject", "hello", "write_return_data", in, out)); |
7c673cae FG |
124 | ASSERT_EQ(std::string(), std::string(out.c_str(), out.length())); |
125 | ||
9f95a23c TL |
126 | // this will return an error due to unexpected input. |
127 | // note that we set the RETURNVEC flag here so that we *reliably* get the | |
128 | // "too much input data!" return data string. do it lots of times so we are | |
129 | // more likely to resend a request and hit the dup op handling path. | |
7c673cae FG |
130 | char buf[4096]; |
131 | memset(buf, 1, sizeof(buf)); | |
9f95a23c TL |
132 | for (unsigned i=0; i<1000; ++i) { |
133 | std::cout << i << std::endl; | |
134 | in.clear(); | |
135 | in.append(buf, sizeof(buf)); | |
136 | int rval; | |
137 | ObjectWriteOperation o; | |
138 | o.exec("hello", "write_return_data", in, &out, &rval); | |
139 | librados::AioCompletion *completion = cluster.aio_create_completion(); | |
140 | ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &o, | |
141 | librados::OPERATION_RETURNVEC)); | |
142 | completion->wait_for_complete(); | |
143 | ASSERT_EQ(-EINVAL, completion->get_return_value()); | |
144 | ASSERT_EQ(-EINVAL, rval); | |
145 | ASSERT_EQ(std::string("too much input data!"), std::string(out.c_str(), out.length())); | |
146 | } | |
7c673cae FG |
147 | ASSERT_EQ(-ENOENT, ioctx.getxattr("myobject2", "foo", out)); |
148 | ||
9f95a23c TL |
149 | // this *will* return data due to the RETURNVEC flag |
150 | // using a-sync call | |
151 | { | |
152 | in.clear(); | |
153 | out.clear(); | |
154 | int rval; | |
155 | ObjectWriteOperation o; | |
156 | o.exec("hello", "write_return_data", in, &out, &rval); | |
157 | librados::AioCompletion *completion = cluster.aio_create_completion(); | |
158 | ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &o, | |
159 | librados::OPERATION_RETURNVEC)); | |
160 | completion->wait_for_complete(); | |
161 | ASSERT_EQ(42, completion->get_return_value()); | |
162 | ASSERT_EQ(42, rval); | |
163 | out.hexdump(std::cout); | |
164 | ASSERT_EQ("you might see this", std::string(out.c_str(), out.length())); | |
165 | } | |
166 | // using sync call | |
167 | { | |
168 | in.clear(); | |
169 | out.clear(); | |
170 | int rval; | |
171 | ObjectWriteOperation o; | |
172 | o.exec("hello", "write_return_data", in, &out, &rval); | |
173 | ASSERT_EQ(42, ioctx.operate("foo", &o, | |
174 | librados::OPERATION_RETURNVEC)); | |
175 | ASSERT_EQ(42, rval); | |
176 | out.hexdump(std::cout); | |
177 | ASSERT_EQ("you might see this", std::string(out.c_str(), out.length())); | |
178 | } | |
179 | ||
180 | // this will overflow because the return data is too big | |
181 | { | |
182 | in.clear(); | |
183 | out.clear(); | |
184 | int rval; | |
185 | ObjectWriteOperation o; | |
186 | o.exec("hello", "write_too_much_return_data", in, &out, &rval); | |
187 | librados::AioCompletion *completion = cluster.aio_create_completion(); | |
188 | ASSERT_EQ(0, ioctx.aio_operate("foo", completion, &o, | |
189 | librados::OPERATION_RETURNVEC)); | |
190 | completion->wait_for_complete(); | |
191 | ASSERT_EQ(-EOVERFLOW, completion->get_return_value()); | |
192 | ASSERT_EQ(-EOVERFLOW, rval); | |
193 | ASSERT_EQ("", std::string(out.c_str(), out.length())); | |
194 | } | |
195 | ||
7c673cae FG |
196 | ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); |
197 | } | |
198 | ||
199 | TEST(ClsHello, Loud) { | |
200 | Rados cluster; | |
201 | std::string pool_name = get_temp_pool_name(); | |
202 | ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); | |
203 | IoCtx ioctx; | |
204 | cluster.ioctx_create(pool_name.c_str(), ioctx); | |
205 | ||
206 | bufferlist in, out; | |
207 | ASSERT_EQ(0, ioctx.exec("myobject", "hello", "record_hello", in, out)); | |
208 | ASSERT_EQ(0, ioctx.exec("myobject", "hello", "replay", in, out)); | |
209 | ASSERT_EQ(std::string("Hello, world!"), std::string(out.c_str(), out.length())); | |
210 | ||
211 | ASSERT_EQ(0, ioctx.exec("myobject", "hello", "turn_it_to_11", in, out)); | |
212 | ASSERT_EQ(0, ioctx.exec("myobject", "hello", "replay", in, out)); | |
213 | ASSERT_EQ(std::string("HELLO, WORLD!"), std::string(out.c_str(), out.length())); | |
214 | ||
215 | ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); | |
216 | } | |
217 | ||
218 | TEST(ClsHello, BadMethods) { | |
219 | Rados cluster; | |
220 | std::string pool_name = get_temp_pool_name(); | |
221 | ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); | |
222 | IoCtx ioctx; | |
223 | cluster.ioctx_create(pool_name.c_str(), ioctx); | |
224 | ||
225 | bufferlist in, out; | |
226 | ||
227 | ASSERT_EQ(0, ioctx.write_full("myobject", in)); | |
228 | ASSERT_EQ(-EIO, ioctx.exec("myobject", "hello", "bad_reader", in, out)); | |
229 | ASSERT_EQ(-EIO, ioctx.exec("myobject", "hello", "bad_writer", in, out)); | |
230 | ||
231 | ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); | |
232 | } | |
233 | ||
234 | TEST(ClsHello, Filter) { | |
235 | Rados cluster; | |
236 | std::string pool_name = get_temp_pool_name(); | |
237 | ASSERT_EQ("", create_one_pool_pp(pool_name, cluster)); | |
238 | IoCtx ioctx; | |
239 | cluster.ioctx_create(pool_name.c_str(), ioctx); | |
240 | ||
241 | char buf[128]; | |
242 | memset(buf, 0xcc, sizeof(buf)); | |
243 | bufferlist obj_content; | |
244 | obj_content.append(buf, sizeof(buf)); | |
245 | ||
246 | std::string target_str = "content"; | |
247 | ||
248 | // Write xattr bare, no ::encod'ing | |
249 | bufferlist target_val; | |
250 | target_val.append(target_str); | |
251 | bufferlist nontarget_val; | |
252 | nontarget_val.append("rhubarb"); | |
253 | ||
254 | ASSERT_EQ(0, ioctx.write("has_xattr", obj_content, obj_content.length(), 0)); | |
255 | ASSERT_EQ(0, ioctx.write("has_wrong_xattr", obj_content, obj_content.length(), 0)); | |
256 | ASSERT_EQ(0, ioctx.write("no_xattr", obj_content, obj_content.length(), 0)); | |
257 | ||
258 | ASSERT_EQ(0, ioctx.setxattr("has_xattr", "theattr", target_val)); | |
259 | ASSERT_EQ(0, ioctx.setxattr("has_wrong_xattr", "theattr", nontarget_val)); | |
260 | ||
261 | bufferlist filter_bl; | |
262 | std::string filter_name = "hello.hello"; | |
11fdf7f2 TL |
263 | encode(filter_name, filter_bl); |
264 | encode("_theattr", filter_bl); | |
265 | encode(target_str, filter_bl); | |
7c673cae FG |
266 | |
267 | NObjectIterator iter(ioctx.nobjects_begin(filter_bl)); | |
268 | bool foundit = false; | |
269 | int k = 0; | |
270 | while (iter != ioctx.nobjects_end()) { | |
271 | foundit = true; | |
272 | // We should only see the object that matches the filter | |
273 | ASSERT_EQ((*iter).get_oid(), "has_xattr"); | |
274 | // We should only see it once | |
275 | ASSERT_EQ(k, 0); | |
276 | ++iter; | |
277 | ++k; | |
278 | } | |
279 | ASSERT_TRUE(foundit); | |
280 | ||
281 | ASSERT_EQ(0, destroy_one_pool_pp(pool_name, cluster)); | |
282 | } | |
283 |