]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/rgw/test_rgw_lua.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / rgw / test_rgw_lua.cc
CommitLineData
f67539c2
TL
1#include <gtest/gtest.h>
2#include "common/ceph_context.h"
1e59de90
TL
3#include "rgw_common.h"
4#include "rgw_auth_registry.h"
5#include "rgw_process_env.h"
6#include "rgw_sal_rados.h"
7#include "rgw_lua_request.h"
8#include "rgw_lua_background.h"
9#include "rgw_lua_data_filter.h"
f67539c2 10
20effc67 11using namespace std;
f67539c2 12using namespace rgw;
20effc67
TL
13using boost::container::flat_set;
14using rgw::auth::Identity;
15using rgw::auth::Principal;
f67539c2
TL
16
17class CctCleaner {
18 CephContext* cct;
19public:
20 CctCleaner(CephContext* _cct) : cct(_cct) {}
21 ~CctCleaner() {
22#ifdef WITH_SEASTAR
23 delete cct;
24#else
25 cct->put();
26#endif
27 }
28};
29
20effc67 30class FakeIdentity : public Identity {
f67539c2 31public:
20effc67
TL
32 FakeIdentity() = default;
33
34 uint32_t get_perms_from_aclspec(const DoutPrefixProvider* dpp, const aclspec_t& aclspec) const override {
35 return 0;
36 };
37
38 bool is_admin_of(const rgw_user& uid) const override {
39 return false;
40 }
41
42 bool is_owner_of(const rgw_user& uid) const override {
43 return false;
44 }
45
46 virtual uint32_t get_perm_mask() const override {
47 return 0;
48 }
49
50 uint32_t get_identity_type() const override {
51 return TYPE_RGW;
52 }
53
54 string get_acct_name() const override {
55 return "";
56 }
57
58 string get_subuser() const override {
59 return "";
60 }
61
62 void to_str(std::ostream& out) const override {
63 return;
64 }
65
66 bool is_identity(const flat_set<Principal>& ids) const override {
67 return false;
68 }
69};
70
1e59de90 71class TestUser : public sal::StoreUser {
20effc67
TL
72public:
73 virtual std::unique_ptr<User> clone() override {
74 return std::unique_ptr<User>(new TestUser(*this));
75 }
76
77 virtual int list_buckets(const DoutPrefixProvider *dpp, const string&, const string&, uint64_t, bool, sal::BucketList&, optional_yield y) override {
78 return 0;
79 }
80
81 virtual int create_bucket(const DoutPrefixProvider* dpp, const rgw_bucket& b, const std::string& zonegroup_id, rgw_placement_rule& placement_rule, std::string& swift_ver_location, const RGWQuotaInfo* pquota_info, const RGWAccessControlPolicy& policy, sal::Attrs& attrs, RGWBucketInfo& info, obj_version& ep_objv, bool exclusive, bool obj_lock_enabled, bool* existed, req_info& req_info, std::unique_ptr<sal::Bucket>* bucket, optional_yield y) override {
82 return 0;
83 }
84
85 virtual int read_attrs(const DoutPrefixProvider *dpp, optional_yield y) override {
86 return 0;
87 }
88
89 virtual int read_stats(const DoutPrefixProvider *dpp, optional_yield y, RGWStorageStats* stats, ceph::real_time *last_stats_sync, ceph::real_time *last_stats_update) override {
90 return 0;
91 }
92
93 virtual int read_stats_async(const DoutPrefixProvider *dpp, RGWGetUserStats_CB *cb) override {
94 return 0;
95 }
96
97 virtual int complete_flush_stats(const DoutPrefixProvider *dpp, optional_yield y) override {
f67539c2
TL
98 return 0;
99 }
100
20effc67
TL
101 virtual int read_usage(const DoutPrefixProvider *dpp, uint64_t start_epoch, uint64_t end_epoch, uint32_t max_entries, bool *is_truncated, RGWUsageIter& usage_iter, map<rgw_user_bucket, rgw_usage_log_entry>& usage) override {
102 return 0;
103 }
104
105 virtual int trim_usage(const DoutPrefixProvider *dpp, uint64_t start_epoch, uint64_t end_epoch) override {
106 return 0;
f67539c2
TL
107 }
108
20effc67 109 virtual int load_user(const DoutPrefixProvider *dpp, optional_yield y) override {
f67539c2
TL
110 return 0;
111 }
112
20effc67
TL
113 virtual int store_user(const DoutPrefixProvider* dpp, optional_yield y, bool exclusive, RGWUserInfo* old_info) override {
114 return 0;
115 }
116
117 virtual int remove_user(const DoutPrefixProvider* dpp, optional_yield y) override {
118 return 0;
119 }
120 virtual int merge_and_store_attrs(const DoutPrefixProvider *dpp, rgw::sal::Attrs& attrs, optional_yield y) override {
121 return 0;
122 }
1e59de90
TL
123 virtual int verify_mfa(const std::string& mfa_str, bool* verified, const DoutPrefixProvider* dpp, optional_yield y) override {
124 return 0;
125 }
20effc67 126 virtual ~TestUser() = default;
f67539c2
TL
127};
128
129class TestAccounter : public io::Accounter, public io::BasicClient {
130 RGWEnv env;
131
132protected:
133 virtual int init_env(CephContext *cct) override {
134 return 0;
135 }
136
137public:
138 ~TestAccounter() = default;
139
140 virtual void set_account(bool enabled) override {
141 }
142
143 virtual uint64_t get_bytes_sent() const override {
144 return 0;
145 }
146
147 virtual uint64_t get_bytes_received() const override {
148 return 0;
149 }
150
151 virtual RGWEnv& get_env() noexcept override {
152 return env;
153 }
154
155 virtual size_t complete_request() override {
156 return 0;
157 }
158};
159
1e59de90
TL
160auto g_cct = new CephContext(CEPH_ENTITY_TYPE_CLIENT);
161
162CctCleaner cleaner(g_cct);
f67539c2 163
1e59de90
TL
164tracing::Tracer tracer;
165
166#define DEFINE_REQ_STATE RGWProcessEnv pe; RGWEnv e; req_state s(g_cct, pe, &e, 0);
167#define INIT_TRACE tracer.init("test"); \
168 s.trace = tracer.start_trace("test", true);
f67539c2
TL
169
170TEST(TestRGWLua, EmptyScript)
171{
172 const std::string script;
173
1e59de90 174 DEFINE_REQ_STATE;
f67539c2 175
39ae355f 176 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
177 ASSERT_EQ(rc, 0);
178}
179
f67539c2
TL
180TEST(TestRGWLua, SyntaxError)
181{
182 const std::string script = R"(
183 if 3 < 5 then
184 RGWDebugLog("missing 'end'")
185 )";
186
187 DEFINE_REQ_STATE;
188
39ae355f 189 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
190 ASSERT_EQ(rc, -1);
191}
192
193TEST(TestRGWLua, Hello)
194{
195 const std::string script = R"(
196 RGWDebugLog("hello from lua")
197 )";
198
199 DEFINE_REQ_STATE;
200
39ae355f 201 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
202 ASSERT_EQ(rc, 0);
203}
204
205TEST(TestRGWLua, RGWDebugLogNumber)
206{
207 const std::string script = R"(
208 RGWDebugLog(1234567890)
209 )";
210
211 DEFINE_REQ_STATE;
212
39ae355f 213 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
214 ASSERT_EQ(rc, 0);
215}
216
217TEST(TestRGWLua, RGWDebugNil)
218{
219 const std::string script = R"(
220 RGWDebugLog(nil)
221 )";
222
223 DEFINE_REQ_STATE;
224
39ae355f 225 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
226 ASSERT_EQ(rc, -1);
227}
228
229TEST(TestRGWLua, URI)
230{
231 const std::string script = R"(
232 RGWDebugLog(Request.DecodedURI)
233 assert(Request.DecodedURI == "http://hello.world/")
234 )";
235
236 DEFINE_REQ_STATE;
237 s.decoded_uri = "http://hello.world/";
238
39ae355f 239 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
240 ASSERT_EQ(rc, 0);
241}
242
243TEST(TestRGWLua, Response)
244{
245 const std::string script = R"(
246 assert(Request.Response.Message == "This is a bad request")
247 assert(Request.Response.HTTPStatus == "Bad Request")
248 assert(Request.Response.RGWCode == 4000)
249 assert(Request.Response.HTTPStatusCode == 400)
250 )";
251
252 DEFINE_REQ_STATE;
253 s.err.http_ret = 400;
254 s.err.ret = 4000;
255 s.err.err_code = "Bad Request";
256 s.err.message = "This is a bad request";
257
39ae355f 258 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
259 ASSERT_EQ(rc, 0);
260}
261
262TEST(TestRGWLua, SetResponse)
263{
264 const std::string script = R"(
265 assert(Request.Response.Message == "this is a bad request")
266 Request.Response.Message = "this is a good request"
267 assert(Request.Response.Message == "this is a good request")
268 )";
269
270 DEFINE_REQ_STATE;
271 s.err.message = "this is a bad request";
272
39ae355f 273 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
274 ASSERT_EQ(rc, 0);
275}
276
1e59de90 277TEST(TestRGWLua, RGWIdNotWriteable)
f67539c2
TL
278{
279 const std::string script = R"(
280 assert(Request.RGWId == "foo")
281 Request.RGWId = "bar"
282 )";
283
284 DEFINE_REQ_STATE;
285 s.host_id = "foo";
286
39ae355f 287 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
288 ASSERT_NE(rc, 0);
289}
290
291TEST(TestRGWLua, InvalidField)
292{
293 const std::string script = R"(
294 RGWDebugLog(Request.Kaboom)
295 )";
296
297 DEFINE_REQ_STATE;
298 s.host_id = "foo";
299
39ae355f 300 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
301 ASSERT_EQ(rc, -1);
302}
303
304TEST(TestRGWLua, InvalidSubField)
305{
306 const std::string script = R"(
307 RGWDebugLog(Request.Error.Kaboom)
308 )";
309
310 DEFINE_REQ_STATE;
311
39ae355f 312 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
313 ASSERT_EQ(rc, -1);
314}
315
316TEST(TestRGWLua, Bucket)
317{
318 const std::string script = R"(
319 assert(Request.Bucket)
320 RGWDebugLog("Bucket Id: " .. Request.Bucket.Id)
321 assert(Request.Bucket.Marker == "mymarker")
322 assert(Request.Bucket.Name == "myname")
323 assert(Request.Bucket.Tenant == "mytenant")
324 assert(Request.Bucket.Count == 0)
325 assert(Request.Bucket.Size == 0)
326 assert(Request.Bucket.ZoneGroupId)
327 assert(Request.Bucket.CreationTime)
328 assert(Request.Bucket.MTime)
329 assert(Request.Bucket.Quota.MaxSize == -1)
330 assert(Request.Bucket.Quota.MaxObjects == -1)
331 assert(tostring(Request.Bucket.Quota.Enabled))
332 assert(tostring(Request.Bucket.Quota.Rounded))
333 assert(Request.Bucket.User.Id)
334 assert(Request.Bucket.User.Tenant)
335 )";
336
337 DEFINE_REQ_STATE;
338
339 rgw_bucket b;
340 b.tenant = "mytenant";
341 b.name = "myname";
342 b.marker = "mymarker";
343 b.bucket_id = "myid";
20effc67 344 s.bucket.reset(new sal::RadosBucket(nullptr, b));
f67539c2 345
39ae355f 346 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
347 ASSERT_EQ(rc, 0);
348}
349
1e59de90
TL
350TEST(TestRGWLua, WriteBucket)
351{
352 const std::string script = R"(
353 assert(Request.Bucket)
354 assert(Request.Bucket.Name == "myname")
355 Request.Bucket.Name = "othername"
356 )";
357
358 DEFINE_REQ_STATE;
359 s.init_state.url_bucket = "myname";
360
361 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
362 ASSERT_EQ(rc, 0);
363 ASSERT_EQ(s.init_state.url_bucket, "othername");
364}
365
366TEST(TestRGWLua, WriteBucketFail)
367{
368 const std::string script = R"(
369 assert(Request.Bucket)
370 assert(Request.Bucket.Name == "myname")
371 Request.Bucket.Name = "othername"
372 )";
373
374 DEFINE_REQ_STATE;
375 rgw_bucket b;
376 b.name = "myname";
377 s.bucket.reset(new sal::RadosBucket(nullptr, b));
378
379 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
380 ASSERT_NE(rc, 0);
381}
382
f67539c2
TL
383TEST(TestRGWLua, GenericAttributes)
384{
385 const std::string script = R"(
386 assert(Request.GenericAttributes["hello"] == "world")
387 assert(Request.GenericAttributes["foo"] == "bar")
388 assert(Request.GenericAttributes["kaboom"] == nil)
389 assert(#Request.GenericAttributes == 4)
390 for k, v in pairs(Request.GenericAttributes) do
391 assert(k)
392 assert(v)
393 end
394 )";
395
396 DEFINE_REQ_STATE;
397 s.generic_attrs["hello"] = "world";
398 s.generic_attrs["foo"] = "bar";
399 s.generic_attrs["goodbye"] = "cruel world";
400 s.generic_attrs["ka"] = "boom";
401
39ae355f 402 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
403 ASSERT_EQ(rc, 0);
404}
405
406TEST(TestRGWLua, Environment)
407{
408 const std::string script = R"(
409 assert(Request.Environment[""] == "bar")
410 assert(Request.Environment["goodbye"] == "cruel world")
411 assert(Request.Environment["ka"] == "boom")
412 assert(#Request.Environment == 3, #Request.Environment)
413 for k, v in pairs(Request.Environment) do
414 assert(k)
415 assert(v)
416 end
417 )";
418
419 DEFINE_REQ_STATE;
20effc67
TL
420 s.env.emplace("", "bar");
421 s.env.emplace("goodbye", "cruel world");
422 s.env.emplace("ka", "boom");
f67539c2 423
39ae355f 424 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
425 ASSERT_EQ(rc, 0);
426}
427
428TEST(TestRGWLua, Tags)
429{
430 const std::string script = R"(
431 assert(#Request.Tags == 4)
432 assert(Request.Tags["foo"] == "bar")
433 for k, v in pairs(Request.Tags) do
434 assert(k)
435 assert(v)
436 end
437 )";
438
439 DEFINE_REQ_STATE;
440 s.tagset.add_tag("hello", "world");
441 s.tagset.add_tag("foo", "bar");
442 s.tagset.add_tag("goodbye", "cruel world");
443 s.tagset.add_tag("ka", "boom");
444
39ae355f 445 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
446 ASSERT_EQ(rc, 0);
447}
448
449TEST(TestRGWLua, TagsNotWriteable)
450{
451 const std::string script = R"(
452 Request.Tags["hello"] = "goodbye"
453 )";
454
455 DEFINE_REQ_STATE;
456 s.tagset.add_tag("hello", "world");
457
39ae355f 458 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
459 ASSERT_NE(rc, 0);
460}
461
462TEST(TestRGWLua, Metadata)
463{
464 const std::string script = R"(
465 assert(#Request.HTTP.Metadata == 3)
466 for k, v in pairs(Request.HTTP.Metadata) do
467 assert(k)
468 assert(v)
469 end
470 assert(Request.HTTP.Metadata["hello"] == "world")
471 assert(Request.HTTP.Metadata["kaboom"] == nil)
472 Request.HTTP.Metadata["hello"] = "goodbye"
473 Request.HTTP.Metadata["kaboom"] = "boom"
474 assert(#Request.HTTP.Metadata == 4)
475 assert(Request.HTTP.Metadata["hello"] == "goodbye")
476 assert(Request.HTTP.Metadata["kaboom"] == "boom")
477 )";
478
479 DEFINE_REQ_STATE;
480 s.info.x_meta_map["hello"] = "world";
481 s.info.x_meta_map["foo"] = "bar";
482 s.info.x_meta_map["ka"] = "boom";
483
39ae355f 484 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
485 ASSERT_EQ(rc, 0);
486}
487
488TEST(TestRGWLua, Acl)
489{
490 const std::string script = R"(
491 function print_grant(g)
492 print("Grant Type: " .. g.Type)
493 print("Grant Group Type: " .. g.GroupType)
494 print("Grant Referer: " .. g.Referer)
495 if (g.User) then
496 print("Grant User.Tenant: " .. g.User.Tenant)
497 print("Grant User.Id: " .. g.User.Id)
498 end
499 end
500
501 assert(Request.UserAcl.Owner.DisplayName == "jack black", Request.UserAcl.Owner.DisplayName)
502 assert(Request.UserAcl.Owner.User.Id == "black", Request.UserAcl.Owner.User.Id)
503 assert(Request.UserAcl.Owner.User.Tenant == "jack", Request.UserAcl.Owner.User.Tenant)
504 assert(#Request.UserAcl.Grants == 5)
505 print_grant(Request.UserAcl.Grants[""])
506 for k, v in pairs(Request.UserAcl.Grants) do
507 print_grant(v)
508 if k == "john$doe" then
509 assert(v.Permission == 4)
510 elseif k == "jane$doe" then
511 assert(v.Permission == 1)
512 else
513 assert(false)
514 end
515 end
516 )";
517
518 DEFINE_REQ_STATE;
519 ACLOwner owner;
520 owner.set_id(rgw_user("jack", "black"));
521 owner.set_name("jack black");
1e59de90 522 s.user_acl.reset(new RGWAccessControlPolicy(g_cct));
f67539c2
TL
523 s.user_acl->set_owner(owner);
524 ACLGrant grant1, grant2, grant3, grant4, grant5;
525 grant1.set_canon(rgw_user("jane", "doe"), "her grant", 1);
526 grant2.set_group(ACL_GROUP_ALL_USERS ,2);
527 grant3.set_referer("http://localhost/ref2", 3);
528 grant4.set_canon(rgw_user("john", "doe"), "his grant", 4);
529 grant5.set_group(ACL_GROUP_AUTHENTICATED_USERS, 5);
530 s.user_acl->get_acl().add_grant(&grant1);
531 s.user_acl->get_acl().add_grant(&grant2);
532 s.user_acl->get_acl().add_grant(&grant3);
533 s.user_acl->get_acl().add_grant(&grant4);
534 s.user_acl->get_acl().add_grant(&grant5);
39ae355f 535 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
536 ASSERT_EQ(rc, 0);
537}
538
20effc67
TL
539TEST(TestRGWLua, User)
540{
541 const std::string script = R"(
542 assert(Request.User)
543 assert(Request.User.Id == "myid")
544 assert(Request.User.Tenant == "mytenant")
545 )";
546
547 DEFINE_REQ_STATE;
548
549 rgw_user u;
550 u.tenant = "mytenant";
551 u.id = "myid";
552 s.user.reset(new sal::RadosUser(nullptr, u));
553
39ae355f 554 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
20effc67
TL
555 ASSERT_EQ(rc, 0);
556}
557
558
f67539c2
TL
559TEST(TestRGWLua, UseFunction)
560{
561 const std::string script = R"(
562 function print_owner(owner)
563 print("Owner Dispaly Name: " .. owner.DisplayName)
564 print("Owner Id: " .. owner.User.Id)
565 print("Owner Tenanet: " .. owner.User.Tenant)
566 end
567
568 print_owner(Request.ObjectOwner)
569
570 function print_acl(acl_type)
571 index = acl_type .. "ACL"
572 acl = Request[index]
573 if acl then
574 print(acl_type .. "ACL Owner")
575 print_owner(acl.Owner)
576 else
577 print("no " .. acl_type .. " ACL in request: " .. Request.Id)
578 end
579 end
580
581 print_acl("User")
582 print_acl("Bucket")
583 print_acl("Object")
584 )";
585
586 DEFINE_REQ_STATE;
587 s.owner.set_name("user two");
588 s.owner.set_id(rgw_user("tenant2", "user2"));
589 s.user_acl.reset(new RGWAccessControlPolicy());
590 s.user_acl->get_owner().set_name("user three");
591 s.user_acl->get_owner().set_id(rgw_user("tenant3", "user3"));
592 s.bucket_acl.reset(new RGWAccessControlPolicy());
593 s.bucket_acl->get_owner().set_name("user four");
594 s.bucket_acl->get_owner().set_id(rgw_user("tenant4", "user4"));
595 s.object_acl.reset(new RGWAccessControlPolicy());
596 s.object_acl->get_owner().set_name("user five");
597 s.object_acl->get_owner().set_id(rgw_user("tenant5", "user5"));
598
39ae355f 599 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
600 ASSERT_EQ(rc, 0);
601}
602
603TEST(TestRGWLua, WithLib)
604{
605 const std::string script = R"(
606 expected_result = {"my", "bucket", "name", "is", "fish"}
607 i = 1
608 for p in string.gmatch(Request.Bucket.Name, "%a+") do
609 assert(p == expected_result[i])
610 i = i + 1
611 end
612 )";
613
614 DEFINE_REQ_STATE;
615
616 rgw_bucket b;
617 b.name = "my-bucket-name-is-fish";
20effc67 618 s.bucket.reset(new sal::RadosBucket(nullptr, b));
f67539c2 619
39ae355f 620 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
621 ASSERT_EQ(rc, 0);
622}
623
624TEST(TestRGWLua, NotAllowedInLib)
625{
626 const std::string script = R"(
627 os.clock() -- this should be ok
628 os.exit() -- this should fail (os.exit() is removed)
629 )";
630
631 DEFINE_REQ_STATE;
632
39ae355f 633 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
f67539c2
TL
634 ASSERT_NE(rc, 0);
635}
f67539c2 636
1e59de90
TL
637#define MAKE_STORE auto store = std::unique_ptr<sal::RadosStore>(new sal::RadosStore); \
638 store->setRados(new RGWRados);
f67539c2
TL
639
640TEST(TestRGWLua, OpsLog)
641{
f67539c2
TL
642 const std::string script = R"(
643 if Request.Response.HTTPStatusCode == 200 then
644 assert(Request.Response.Message == "Life is great")
645 else
646 assert(Request.Bucket)
647 assert(Request.Log() == 0)
648 end
649 )";
650
1e59de90
TL
651 MAKE_STORE;
652
653 struct MockOpsLogSink : OpsLogSink {
654 bool logged = false;
655 int log(req_state*, rgw_log_entry&) override { logged = true; return 0; }
656 };
657 MockOpsLogSink olog;
f67539c2
TL
658
659 DEFINE_REQ_STATE;
660 s.err.http_ret = 200;
661 s.err.ret = 0;
662 s.err.err_code = "200OK";
663 s.err.message = "Life is great";
664 rgw_bucket b;
665 b.tenant = "tenant";
666 b.name = "name";
667 b.marker = "marker";
668 b.bucket_id = "id";
20effc67 669 s.bucket.reset(new sal::RadosBucket(nullptr, b));
f67539c2
TL
670 s.bucket_name = "name";
671 s.enable_ops_log = true;
672 s.enable_usage_log = false;
20effc67 673 s.user.reset(new TestUser());
f67539c2
TL
674 TestAccounter ac;
675 s.cio = &ac;
676 s.cct->_conf->rgw_ops_log_rados = false;
677
20effc67
TL
678 s.auth.identity = std::unique_ptr<rgw::auth::Identity>(
679 new FakeIdentity());
680
1e59de90 681 auto rc = lua::request::execute(store.get(), nullptr, &olog, &s, nullptr, script);
f67539c2 682 EXPECT_EQ(rc, 0);
1e59de90 683 EXPECT_FALSE(olog.logged); // don't log http_ret=200
f67539c2
TL
684
685 s.err.http_ret = 400;
1e59de90 686 rc = lua::request::execute(store.get(), nullptr, &olog, &s, nullptr, script);
f67539c2 687 EXPECT_EQ(rc, 0);
1e59de90
TL
688 EXPECT_TRUE(olog.logged);
689}
690
691class TestBackground : public rgw::lua::Background {
692 const unsigned read_time;
693
694protected:
695 int read_script() override {
696 // don't read the object from the store
697 std::this_thread::sleep_for(std::chrono::seconds(read_time));
698 return 0;
699 }
700
701public:
702 TestBackground(sal::RadosStore* store, const std::string& script, unsigned read_time = 0) :
703 rgw::lua::Background(store, g_cct, "", /* luarocks path */ 1 /* run every second */),
704 read_time(read_time) {
705 // the script is passed in the constructor
706 rgw_script = script;
707 }
708
709 ~TestBackground() override {
710 shutdown();
711 }
712};
713
714TEST(TestRGWLuaBackground, Start)
715{
716 MAKE_STORE;
717 {
718 // ctr and dtor without running
719 TestBackground lua_background(store.get(), "");
720 }
721 {
722 // ctr and dtor with running
723 TestBackground lua_background(store.get(), "");
724 lua_background.start();
725 }
726}
727
728
729constexpr auto wait_time = std::chrono::seconds(3);
730
731template<typename T>
732const T& get_table_value(const TestBackground& b, const std::string& index) {
733 try {
734 return std::get<T>(b.get_table_value(index));
735 } catch (std::bad_variant_access const& ex) {
736 std::cout << "expected RGW[" << index << "] to be: " << typeid(T).name() << std::endl;
737 throw(ex);
738 }
739}
740
741TEST(TestRGWLuaBackground, Script)
742{
743 const std::string script = R"(
744 local key = "hello"
745 local value = "world"
746 RGW[key] = value
747 )";
748
749 MAKE_STORE;
750 TestBackground lua_background(store.get(), script);
751 lua_background.start();
752 std::this_thread::sleep_for(wait_time);
753 EXPECT_EQ(get_table_value<std::string>(lua_background, "hello"), "world");
754}
755
756TEST(TestRGWLuaBackground, RequestScript)
757{
758 const std::string background_script = R"(
759 local key = "hello"
760 local value = "from background"
761 RGW[key] = value
762 )";
763
764 MAKE_STORE;
765 TestBackground lua_background(store.get(), background_script);
766 lua_background.start();
767 std::this_thread::sleep_for(wait_time);
768
769 const std::string request_script = R"(
770 local key = "hello"
771 assert(RGW[key] == "from background")
772 local value = "from request"
773 RGW[key] = value
774 )";
775
776 DEFINE_REQ_STATE;
777 pe.lua.background = &lua_background;
778
779 // to make sure test is consistent we have to puase the background
780 lua_background.pause();
781 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
782 ASSERT_EQ(rc, 0);
783 EXPECT_EQ(get_table_value<std::string>(lua_background, "hello"), "from request");
784 // now we resume and let the background set the value
785 lua_background.resume(store.get());
786 std::this_thread::sleep_for(wait_time);
787 EXPECT_EQ(get_table_value<std::string>(lua_background, "hello"), "from background");
788}
789
790TEST(TestRGWLuaBackground, Pause)
791{
792 const std::string script = R"(
793 local key = "hello"
794 local value = "1"
795 if RGW[key] then
796 RGW[key] = value..RGW[key]
797 else
798 RGW[key] = value
799 end
800 )";
801
802 MAKE_STORE;
803 TestBackground lua_background(store.get(), script);
804 lua_background.start();
805 std::this_thread::sleep_for(wait_time);
806 const auto value_len = get_table_value<std::string>(lua_background, "hello").size();
807 EXPECT_GT(value_len, 0);
808 lua_background.pause();
809 std::this_thread::sleep_for(wait_time);
810 // no change in len
811 EXPECT_EQ(value_len, get_table_value<std::string>(lua_background, "hello").size());
812}
813
814TEST(TestRGWLuaBackground, PauseWhileReading)
815{
816 const std::string script = R"(
817 local key = "hello"
818 local value = "world"
819 RGW[key] = value
820 if RGW[key] then
821 RGW[key] = value..RGW[key]
822 else
823 RGW[key] = value
824 end
825 )";
826
827 MAKE_STORE;
828 constexpr auto long_wait_time = std::chrono::seconds(6);
829 TestBackground lua_background(store.get(), script, 2);
830 lua_background.start();
831 std::this_thread::sleep_for(long_wait_time);
832 const auto value_len = get_table_value<std::string>(lua_background, "hello").size();
833 EXPECT_GT(value_len, 0);
834 lua_background.pause();
835 std::this_thread::sleep_for(long_wait_time);
836 // one execution might occur after pause
837 EXPECT_TRUE(value_len + 1 >= get_table_value<std::string>(lua_background, "hello").size());
838}
839
840TEST(TestRGWLuaBackground, ReadWhilePaused)
841{
842 const std::string script = R"(
843 local key = "hello"
844 local value = "world"
845 RGW[key] = value
846 )";
847
848 MAKE_STORE;
849 TestBackground lua_background(store.get(), script);
850 lua_background.pause();
851 lua_background.start();
852 std::this_thread::sleep_for(wait_time);
853 EXPECT_EQ(get_table_value<std::string>(lua_background, "hello"), "");
854 lua_background.resume(store.get());
855 std::this_thread::sleep_for(wait_time);
856 EXPECT_EQ(get_table_value<std::string>(lua_background, "hello"), "world");
857}
858
859TEST(TestRGWLuaBackground, PauseResume)
860{
861 const std::string script = R"(
862 local key = "hello"
863 local value = "1"
864 if RGW[key] then
865 RGW[key] = value..RGW[key]
866 else
867 RGW[key] = value
868 end
869 )";
870
871 MAKE_STORE;
872 TestBackground lua_background(store.get(), script);
873 lua_background.start();
874 std::this_thread::sleep_for(wait_time);
875 const auto value_len = get_table_value<std::string>(lua_background, "hello").size();
876 EXPECT_GT(value_len, 0);
877 lua_background.pause();
878 std::this_thread::sleep_for(wait_time);
879 // no change in len
880 EXPECT_EQ(value_len, get_table_value<std::string>(lua_background, "hello").size());
881 lua_background.resume(store.get());
882 std::this_thread::sleep_for(wait_time);
883 // should be a change in len
884 EXPECT_GT(get_table_value<std::string>(lua_background, "hello").size(), value_len);
885}
886
887TEST(TestRGWLuaBackground, MultipleStarts)
888{
889 const std::string script = R"(
890 local key = "hello"
891 local value = "1"
892 if RGW[key] then
893 RGW[key] = value..RGW[key]
894 else
895 RGW[key] = value
896 end
897 )";
898
899 MAKE_STORE;
900 TestBackground lua_background(store.get(), script);
901 lua_background.start();
902 std::this_thread::sleep_for(wait_time);
903 const auto value_len = get_table_value<std::string>(lua_background, "hello").size();
904 EXPECT_GT(value_len, 0);
905 lua_background.start();
906 lua_background.shutdown();
907 lua_background.shutdown();
908 std::this_thread::sleep_for(wait_time);
909 lua_background.start();
910 std::this_thread::sleep_for(wait_time);
911 // should be a change in len
912 EXPECT_GT(get_table_value<std::string>(lua_background, "hello").size(), value_len);
913}
914
915TEST(TestRGWLuaBackground, TableValues)
916{
917 MAKE_STORE;
918 TestBackground lua_background(store.get(), "");
919
920 const std::string request_script = R"(
921 RGW["key1"] = "string value"
922 RGW["key2"] = 42
923 RGW["key3"] = 42.2
924 RGW["key4"] = true
925 )";
926
927 DEFINE_REQ_STATE;
928 pe.lua.background = &lua_background;
929
930 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
931 ASSERT_EQ(rc, 0);
932 EXPECT_EQ(get_table_value<std::string>(lua_background, "key1"), "string value");
933 EXPECT_EQ(get_table_value<long long int>(lua_background, "key2"), 42);
934 EXPECT_EQ(get_table_value<double>(lua_background, "key3"), 42.2);
935 EXPECT_TRUE(get_table_value<bool>(lua_background, "key4"));
936}
937
938TEST(TestRGWLuaBackground, TablePersist)
939{
940 MAKE_STORE;
941 TestBackground lua_background(store.get(), "");
942
943 std::string request_script = R"(
944 RGW["key1"] = "string value"
945 RGW["key2"] = 42
946 )";
947
948 DEFINE_REQ_STATE;
949 pe.lua.background = &lua_background;
950
951 auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
952 ASSERT_EQ(rc, 0);
953 EXPECT_EQ(get_table_value<std::string>(lua_background, "key1"), "string value");
954 EXPECT_EQ(get_table_value<long long int>(lua_background, "key2"), 42);
955
956 request_script = R"(
957 RGW["key3"] = RGW["key1"]
958 RGW["key4"] = RGW["key2"]
959 )";
960
961 rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
962 ASSERT_EQ(rc, 0);
963 EXPECT_EQ(get_table_value<std::string>(lua_background, "key1"), "string value");
964 EXPECT_EQ(get_table_value<long long int>(lua_background, "key2"), 42);
965 EXPECT_EQ(get_table_value<std::string>(lua_background, "key3"), "string value");
966 EXPECT_EQ(get_table_value<long long int>(lua_background, "key4"), 42);
967}
968
969TEST(TestRGWLuaBackground, TableValuesFromRequest)
970{
971 MAKE_STORE;
972 TestBackground lua_background(store.get(), "");
973 lua_background.start();
974
975 const std::string request_script = R"(
976 RGW["key1"] = Request.Response.RGWCode
977 RGW["key2"] = Request.Response.Message
978 RGW["key3"] = Request.Response.RGWCode*0.1
979 RGW["key4"] = Request.Tags["key1"] == Request.Tags["key2"]
980 )";
981
982 DEFINE_REQ_STATE;
983 pe.lua.background = &lua_background;
984
985 s.tagset.add_tag("key1", "val1");
986 s.tagset.add_tag("key2", "val1");
987 s.err.ret = -99;
988 s.err.message = "hi";
989
990 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
991 ASSERT_EQ(rc, 0);
992 EXPECT_EQ(get_table_value<long long int>(lua_background, "key1"), -99);
993 EXPECT_EQ(get_table_value<std::string>(lua_background, "key2"), "hi");
994 EXPECT_EQ(get_table_value<double>(lua_background, "key3"), -9.9);
995 EXPECT_EQ(get_table_value<bool>(lua_background, "key4"), true);
996}
997
998TEST(TestRGWLuaBackground, TableInvalidValue)
999{
1000 MAKE_STORE;
1001 TestBackground lua_background(store.get(), "");
1002 lua_background.start();
1003
1004 const std::string request_script = R"(
1005 RGW["key1"] = "val1"
1006 RGW["key2"] = 42
1007 RGW["key3"] = 42.2
1008 RGW["key4"] = true
1009 RGW["key5"] = Request.Tags
1010 )";
1011
1012 DEFINE_REQ_STATE;
1013 pe.lua.background = &lua_background;
1014 s.tagset.add_tag("key1", "val1");
1015 s.tagset.add_tag("key2", "val2");
1016
1017 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1018 ASSERT_NE(rc, 0);
1019 EXPECT_EQ(get_table_value<std::string>(lua_background, "key1"), "val1");
1020 EXPECT_EQ(get_table_value<long long int>(lua_background, "key2"), 42);
1021 EXPECT_EQ(get_table_value<double>(lua_background, "key3"), 42.2);
1022 EXPECT_EQ(get_table_value<bool>(lua_background, "key4"), true);
1023}
1024
1025TEST(TestRGWLuaBackground, TableErase)
1026{
1027 MAKE_STORE;
1028 TestBackground lua_background(store.get(), "");
1029
1030 std::string request_script = R"(
1031 RGW["size"] = 0
1032 RGW["key1"] = "string value"
1033 RGW["key2"] = 42
1034 RGW["key3"] = "another string value"
1035 RGW["size"] = #RGW
1036 )";
1037
1038 DEFINE_REQ_STATE;
1039 pe.lua.background = &lua_background;
1040
1041 auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1042 ASSERT_EQ(rc, 0);
1043 EXPECT_EQ(get_table_value<std::string>(lua_background, "key1"), "string value");
1044 EXPECT_EQ(get_table_value<long long int>(lua_background, "key2"), 42);
1045 EXPECT_EQ(get_table_value<std::string>(lua_background, "key3"), "another string value");
1046 EXPECT_EQ(get_table_value<long long int>(lua_background, "size"), 4);
1047
1048 request_script = R"(
1049 -- erase key1
1050 RGW["key1"] = nil
1051 -- following should be a no op
1052 RGW["key4"] = nil
1053 RGW["size"] = #RGW
1054 )";
1055
1056 rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1057 ASSERT_EQ(rc, 0);
1058 EXPECT_EQ(get_table_value<std::string>(lua_background, "key1"), "");
1059 EXPECT_EQ(get_table_value<long long int>(lua_background, "key2"), 42);
1060 EXPECT_EQ(get_table_value<std::string>(lua_background, "key3"), "another string value");
1061 EXPECT_EQ(get_table_value<long long int>(lua_background, "size"), 3);
1062}
1063
1064TEST(TestRGWLuaBackground, TableIterate)
1065{
1066 MAKE_STORE;
1067 TestBackground lua_background(store.get(), "");
1068
1069 const std::string request_script = R"(
1070 RGW["key1"] = "string value"
1071 RGW["key2"] = 42
1072 RGW["key3"] = 42.2
1073 RGW["key4"] = true
1074 RGW["size"] = 0
1075 for k, v in pairs(RGW) do
1076 RGW["size"] = RGW["size"] + 1
1077 end
1078 )";
1079
1080 DEFINE_REQ_STATE;
1081 pe.lua.background = &lua_background;
1082
1083 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1084 ASSERT_EQ(rc, 0);
1085 EXPECT_EQ(get_table_value<std::string>(lua_background, "key1"), "string value");
1086 EXPECT_EQ(get_table_value<long long int>(lua_background, "key2"), 42);
1087 EXPECT_EQ(get_table_value<double>(lua_background, "key3"), 42.2);
1088 EXPECT_TRUE(get_table_value<bool>(lua_background, "key4"));
1089 EXPECT_EQ(get_table_value<long long int>(lua_background, "size"), 5);
1090}
1091
1092TEST(TestRGWLuaBackground, TableIncrement)
1093{
1094 MAKE_STORE;
1095 TestBackground lua_background(store.get(), "");
1096
1097 const std::string request_script = R"(
1098 RGW["key1"] = 42
1099 RGW["key2"] = 42.2
1100 RGW.increment("key1")
1101 assert(RGW["key1"] == 43)
1102 RGW.increment("key2")
1103 assert(RGW["key2"] == 43.2)
1104 )";
1105
1106 DEFINE_REQ_STATE;
1107 pe.lua.background = &lua_background;
1108
1109 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1110 ASSERT_EQ(rc, 0);
1111}
1112
1113TEST(TestRGWLuaBackground, TableIncrementBy)
1114{
1115 MAKE_STORE;
1116 TestBackground lua_background(store.get(), "");
1117
1118 const std::string request_script = R"(
1119 RGW["key1"] = 42
1120 RGW["key2"] = 42.2
1121 RGW.increment("key1", 10)
1122 assert(RGW["key1"] == 52)
1123 RGW.increment("key2", 10)
1124 assert(RGW["key2"] == 52.2)
1125 RGW.increment("key1", 0.2)
1126 assert(RGW["key1"] == 52.2)
1127 )";
1128
1129 DEFINE_REQ_STATE;
1130 pe.lua.background = &lua_background;
1131
1132 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1133 ASSERT_EQ(rc, 0);
1134}
1135
1136TEST(TestRGWLuaBackground, TableDecrement)
1137{
1138 MAKE_STORE;
1139 TestBackground lua_background(store.get(), "");
1140
1141 const std::string request_script = R"(
1142 RGW["key1"] = 42
1143 RGW["key2"] = 42.2
1144 RGW.decrement("key1")
1145 assert(RGW["key1"] == 41)
1146 RGW.decrement("key2")
1147 assert(RGW["key2"] == 41.2)
1148 )";
1149
1150 DEFINE_REQ_STATE;
1151 pe.lua.background = &lua_background;
1152
1153 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1154 ASSERT_EQ(rc, 0);
1155}
1156
1157TEST(TestRGWLuaBackground, TableDecrementBy)
1158{
1159 MAKE_STORE;
1160 TestBackground lua_background(store.get(), "");
1161
1162 const std::string request_script = R"(
1163 RGW["key1"] = 42
1164 RGW["key2"] = 42.2
1165 RGW.decrement("key1", 10)
1166 assert(RGW["key1"] == 32)
1167 RGW.decrement("key2", 10)
1168 assert(RGW["key2"] == 32.2)
1169 RGW.decrement("key1", 0.8)
1170 assert(RGW["key1"] == 31.2)
1171 )";
1172
1173 DEFINE_REQ_STATE;
1174 pe.lua.background = &lua_background;
1175
1176 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1177 ASSERT_EQ(rc, 0);
1178}
1179
1180TEST(TestRGWLuaBackground, TableIncrementValueError)
1181{
1182 MAKE_STORE;
1183 TestBackground lua_background(store.get(), "");
1184
1185 std::string request_script = R"(
1186 -- cannot increment string values
1187 RGW["key1"] = "hello"
1188 RGW.increment("key1")
1189 )";
f67539c2 1190
1e59de90
TL
1191 DEFINE_REQ_STATE;
1192 pe.lua.background = &lua_background;
1193
1194 auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1195 ASSERT_NE(rc, 0);
1196
1197 request_script = R"(
1198 -- cannot increment bool values
1199 RGW["key1"] = true
1200 RGW.increment("key1")
1201 )";
1202
1203 rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1204 ASSERT_NE(rc, 0);
1205
1206 request_script = R"(
1207 -- cannot increment by string values
1208 RGW["key1"] = 99
1209 RGW.increment("key1", "kaboom")
1210 )";
1211
1212 rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1213 ASSERT_NE(rc, 0);
1214}
1215
1216TEST(TestRGWLuaBackground, TableIncrementError)
1217{
1218 MAKE_STORE;
1219 TestBackground lua_background(store.get(), "");
1220
1221 std::string request_script = R"(
1222 -- missing argument
1223 RGW["key1"] = 11
1224 RGW.increment()
1225 )";
1226
1227 DEFINE_REQ_STATE;
1228 pe.lua.background = &lua_background;
1229
1230 auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1231 ASSERT_NE(rc, 0);
1232
1233 request_script = R"(
1234 -- used as settable field
1235 RGW.increment = 11
1236 )";
1237
1238 rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script);
1239 ASSERT_NE(rc, 0);
1240}
1241
1242TEST(TestRGWLua, TracingSetAttribute)
1243{
1244 const std::string script = R"(
1245 Request.Trace.SetAttribute("str-attr", "value")
1246 Request.Trace.SetAttribute("int-attr", 42)
1247 Request.Trace.SetAttribute("double-attr", 42.5)
1248 )";
1249
1250 DEFINE_REQ_STATE;
1251 INIT_TRACE;
1252 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
1253 ASSERT_EQ(rc, 0);
1254}
1255
1256TEST(TestRGWLua, TracingSetBadAttribute)
1257{
1258 const std::string script = R"(
1259 Request.Trace.SetAttribute("attr", nil)
1260 )";
1261
1262 DEFINE_REQ_STATE;
1263 INIT_TRACE;
1264 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
1265 #ifdef HAVE_JAEGER
1266 ASSERT_NE(rc, 0);
1267 #else
1268 ASSERT_EQ(rc, 0);
1269 #endif
1270}
1271
1272TEST(TestRGWLua, TracingAddEvent)
1273{
1274 const std::string script = R"(
1275 event_attrs = {}
1276 event_attrs["x"] = "value-x"
1277 event_attrs[42] = 42
1278 event_attrs[42.5] = 42.5
1279 event_attrs["y"] = "value-y"
1280
1281 Request.Trace.AddEvent("my_event", event_attrs)
1282 )";
1283
1284 DEFINE_REQ_STATE;
1285 INIT_TRACE;
1286 const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, script);
1287 ASSERT_EQ(rc, 0);
1288}
1289
1290TEST(TestRGWLua, Data)
1291{
1292 const std::string script = R"(
1293 local expected = "The quick brown fox jumps over the lazy dog"
1294 local actual = ""
1295 RGW["key1"] = 0
1296
1297 for i, c in pairs(Data) do
1298 actual = actual .. c
1299 RGW.increment("key1")
1300 end
1301 assert(expected == actual)
1302 assert(#Data == #expected);
1303 assert(RGW["key1"] == #Data)
1304 assert(Request.RGWId == "foo")
1305 assert(Offset == 12345678)
1306 )";
1307
1308 MAKE_STORE;
1309 TestBackground lua_background(store.get(), "");
1310 DEFINE_REQ_STATE;
1311 s.host_id = "foo";
1312 pe.lua.background = &lua_background;
1313 lua::RGWObjFilter filter(&s, script);
1314 bufferlist bl;
1315 bl.append("The quick brown fox jumps over the lazy dog");
1316 off_t offset = 12345678;
1317 const auto rc = filter.execute(bl, offset, "put_obj");
1318 ASSERT_EQ(rc, 0);
1319}
1320
1321TEST(TestRGWLua, WriteDataFail)
1322{
1323 const std::string script = R"(
1324 Data[1] = "h"
1325 Data[2] = "e"
1326 Data[3] = "l"
1327 Data[4] = "l"
1328 Data[5] = "o"
1329 )";
1330
1331 DEFINE_REQ_STATE;
1332 lua::RGWObjFilter filter(&s, script);
1333 bufferlist bl;
1334 bl.append("The quick brown fox jumps over the lazy dog");
1335 const auto rc = filter.execute(bl, 0, "put_obj");
1336 ASSERT_NE(rc, 0);
f67539c2
TL
1337}
1338