mirror of
https://github.com/ceph/ceph
synced 2025-04-20 14:25:50 +00:00
rgw/test/lua: add lua integration tests suite
Signed-off-by: Yuval Lifshitz <ylifshit@redhat.com> Fixes: https://tracker.ceph.com/issues/63616
This commit is contained in:
parent
08e655d8ba
commit
46500cace6
@ -283,7 +283,8 @@ BuildRequires: librabbitmq-devel
|
|||||||
BuildRequires: librdkafka-devel
|
BuildRequires: librdkafka-devel
|
||||||
%endif
|
%endif
|
||||||
%if 0%{with lua_packages}
|
%if 0%{with lua_packages}
|
||||||
BuildRequires: %{luarocks_package_name}
|
Requires: lua-devel
|
||||||
|
Requires: %{luarocks_package_name}
|
||||||
%endif
|
%endif
|
||||||
%if 0%{with make_check}
|
%if 0%{with make_check}
|
||||||
BuildRequires: hostname
|
BuildRequires: hostname
|
||||||
|
3
debian/control
vendored
3
debian/control
vendored
@ -72,7 +72,6 @@ Build-Depends: automake,
|
|||||||
libre2-dev,
|
libre2-dev,
|
||||||
libutf8proc-dev (>= 2.2.0),
|
libutf8proc-dev (>= 2.2.0),
|
||||||
librdkafka-dev,
|
librdkafka-dev,
|
||||||
luarocks,
|
|
||||||
libthrift-dev (>= 0.13.0),
|
libthrift-dev (>= 0.13.0),
|
||||||
libyaml-cpp-dev (>= 0.6),
|
libyaml-cpp-dev (>= 0.6),
|
||||||
libzstd-dev <pkg.ceph.check>,
|
libzstd-dev <pkg.ceph.check>,
|
||||||
@ -919,6 +918,8 @@ Section: libs
|
|||||||
Depends: librados2 (= ${binary:Version}),
|
Depends: librados2 (= ${binary:Version}),
|
||||||
${misc:Depends},
|
${misc:Depends},
|
||||||
${shlibs:Depends},
|
${shlibs:Depends},
|
||||||
|
liblua5.3-dev,
|
||||||
|
luarocks,
|
||||||
Description: RADOS Gateway client library
|
Description: RADOS Gateway client library
|
||||||
RADOS is a distributed object store used by the Ceph distributed
|
RADOS is a distributed object store used by the Ceph distributed
|
||||||
storage system. This package provides a REST gateway to the
|
storage system. This package provides a REST gateway to the
|
||||||
|
0
qa/suites/rgw/lua/%
Normal file
0
qa/suites/rgw/lua/%
Normal file
1
qa/suites/rgw/lua/.qa
Symbolic link
1
qa/suites/rgw/lua/.qa
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../.qa/
|
1
qa/suites/rgw/lua/beast.yaml
Symbolic link
1
qa/suites/rgw/lua/beast.yaml
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
.qa/rgw_frontend/beast.yaml
|
1
qa/suites/rgw/lua/bluestore-bitmap.yaml
Symbolic link
1
qa/suites/rgw/lua/bluestore-bitmap.yaml
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
.qa/objectstore/bluestore-bitmap.yaml
|
1
qa/suites/rgw/lua/fixed-2.yaml
Symbolic link
1
qa/suites/rgw/lua/fixed-2.yaml
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
.qa/clusters/fixed-2.yaml
|
9
qa/suites/rgw/lua/overrides.yaml
Normal file
9
qa/suites/rgw/lua/overrides.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
overrides:
|
||||||
|
ceph:
|
||||||
|
conf:
|
||||||
|
client:
|
||||||
|
setuser: ceph
|
||||||
|
setgroup: ceph
|
||||||
|
debug rgw: 20
|
||||||
|
rgw:
|
||||||
|
storage classes: LUKEWARM, FROZEN
|
1
qa/suites/rgw/lua/supported-distros
Symbolic link
1
qa/suites/rgw/lua/supported-distros
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
.qa/distros/supported-random-distro$/
|
0
qa/suites/rgw/lua/tasks/+
Normal file
0
qa/suites/rgw/lua/tasks/+
Normal file
13
qa/suites/rgw/lua/tasks/0-install.yaml
Normal file
13
qa/suites/rgw/lua/tasks/0-install.yaml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
tasks:
|
||||||
|
- install:
|
||||||
|
- ceph:
|
||||||
|
- openssl_keys:
|
||||||
|
- rgw: [client.0]
|
||||||
|
- tox: [client.0]
|
||||||
|
|
||||||
|
overrides:
|
||||||
|
ceph:
|
||||||
|
conf:
|
||||||
|
global:
|
||||||
|
osd_min_pg_log_entries: 10
|
||||||
|
osd_max_pg_log_entries: 10
|
5
qa/suites/rgw/lua/tasks/test_lua.yaml
Normal file
5
qa/suites/rgw/lua/tasks/test_lua.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
tasks:
|
||||||
|
- tox: [client.0]
|
||||||
|
- lua-tests:
|
||||||
|
client.0:
|
||||||
|
rgw_server: client.0
|
254
qa/tasks/lua_tests.py
Normal file
254
qa/tasks/lua_tests.py
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
"""
|
||||||
|
Run a set of lua tests on rgw.
|
||||||
|
"""
|
||||||
|
from io import BytesIO
|
||||||
|
from configobj import ConfigObj
|
||||||
|
import base64
|
||||||
|
import contextlib
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
|
from teuthology import misc as teuthology
|
||||||
|
from teuthology import contextutil
|
||||||
|
from teuthology.orchestra import run
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def download(ctx, config):
|
||||||
|
assert isinstance(config, dict)
|
||||||
|
log.info('Downloading lua-tests...')
|
||||||
|
testdir = teuthology.get_testdir(ctx)
|
||||||
|
branch = ctx.config.get('suite_branch')
|
||||||
|
repo = ctx.config.get('suite_repo')
|
||||||
|
log.info('Using branch %s from %s for lua tests', branch, repo)
|
||||||
|
for (client, client_config) in config.items():
|
||||||
|
|
||||||
|
ctx.cluster.only(client).run(
|
||||||
|
args=['git', 'clone', '-b', branch, repo, '{tdir}/ceph'.format(tdir=testdir)],
|
||||||
|
)
|
||||||
|
|
||||||
|
sha1 = client_config.get('sha1')
|
||||||
|
|
||||||
|
if sha1 is not None:
|
||||||
|
ctx.cluster.only(client).run(
|
||||||
|
args=[
|
||||||
|
'cd', '{tdir}/ceph'.format(tdir=testdir),
|
||||||
|
run.Raw('&&'),
|
||||||
|
'git', 'reset', '--hard', sha1,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
log.info('Removing lua-tests...')
|
||||||
|
testdir = teuthology.get_testdir(ctx)
|
||||||
|
for client in config:
|
||||||
|
ctx.cluster.only(client).run(
|
||||||
|
args=[
|
||||||
|
'rm',
|
||||||
|
'-rf',
|
||||||
|
'{tdir}/ceph'.format(tdir=testdir),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _config_user(luatests_conf, section, user):
|
||||||
|
"""
|
||||||
|
Configure users for this section by stashing away keys, ids, and
|
||||||
|
email addresses.
|
||||||
|
"""
|
||||||
|
luatests_conf[section].setdefault('user_id', user)
|
||||||
|
luatests_conf[section].setdefault('email', '{user}+test@test.test'.format(user=user))
|
||||||
|
luatests_conf[section].setdefault('display_name', 'Mr. {user}'.format(user=user))
|
||||||
|
luatests_conf[section].setdefault('access_key',
|
||||||
|
''.join(random.choice(string.ascii_uppercase) for i in range(20)))
|
||||||
|
luatests_conf[section].setdefault('secret_key',
|
||||||
|
base64.b64encode(os.urandom(40)).decode())
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def create_users(ctx, config):
|
||||||
|
"""
|
||||||
|
Create a main and an alternate s3 user.
|
||||||
|
"""
|
||||||
|
assert isinstance(config, dict)
|
||||||
|
log.info('Creating rgw user...')
|
||||||
|
testdir = teuthology.get_testdir(ctx)
|
||||||
|
|
||||||
|
users = {'s3 main': 'foo'}
|
||||||
|
for client in config['clients']:
|
||||||
|
luatests_conf = config['luatests_conf'][client]
|
||||||
|
for section, user in users.items():
|
||||||
|
_config_user(luatests_conf, section, '{user}.{client}'.format(user=user, client=client))
|
||||||
|
log.debug('Creating user {user} on {host}'.format(user=luatests_conf[section]['user_id'], host=client))
|
||||||
|
cluster_name, daemon_type, client_id = teuthology.split_role(client)
|
||||||
|
client_with_id = daemon_type + '.' + client_id
|
||||||
|
ctx.cluster.only(client).run(
|
||||||
|
args=[
|
||||||
|
'adjust-ulimits',
|
||||||
|
'ceph-coverage',
|
||||||
|
'{tdir}/archive/coverage'.format(tdir=testdir),
|
||||||
|
'radosgw-admin',
|
||||||
|
'-n', client_with_id,
|
||||||
|
'user', 'create',
|
||||||
|
'--uid', luatests_conf[section]['user_id'],
|
||||||
|
'--display-name', luatests_conf[section]['display_name'],
|
||||||
|
'--access-key', luatests_conf[section]['access_key'],
|
||||||
|
'--secret', luatests_conf[section]['secret_key'],
|
||||||
|
'--cluster', cluster_name,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
for client in config['clients']:
|
||||||
|
for user in users.values():
|
||||||
|
uid = '{user}.{client}'.format(user=user, client=client)
|
||||||
|
cluster_name, daemon_type, client_id = teuthology.split_role(client)
|
||||||
|
client_with_id = daemon_type + '.' + client_id
|
||||||
|
ctx.cluster.only(client).run(
|
||||||
|
args=[
|
||||||
|
'adjust-ulimits',
|
||||||
|
'ceph-coverage',
|
||||||
|
'{tdir}/archive/coverage'.format(tdir=testdir),
|
||||||
|
'radosgw-admin',
|
||||||
|
'-n', client_with_id,
|
||||||
|
'user', 'rm',
|
||||||
|
'--uid', uid,
|
||||||
|
'--purge-data',
|
||||||
|
'--cluster', cluster_name,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def configure(ctx, config):
|
||||||
|
assert isinstance(config, dict)
|
||||||
|
log.info('Configuring lua-tests...')
|
||||||
|
testdir = teuthology.get_testdir(ctx)
|
||||||
|
for client, properties in config['clients'].items():
|
||||||
|
(remote,) = ctx.cluster.only(client).remotes.keys()
|
||||||
|
luatests_conf = config['luatests_conf'][client]
|
||||||
|
|
||||||
|
conf_fp = BytesIO()
|
||||||
|
luatests_conf.write(conf_fp)
|
||||||
|
remote.write_file(
|
||||||
|
path='{tdir}/ceph/src/test/rgw/lua/lua-tests.{client}.conf'.format(tdir=testdir, client=client),
|
||||||
|
data=conf_fp.getvalue(),
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
log.info('Removing lua-tests.conf file...')
|
||||||
|
testdir = teuthology.get_testdir(ctx)
|
||||||
|
for client, properties in config['clients'].items():
|
||||||
|
(remote,) = ctx.cluster.only(client).remotes.keys()
|
||||||
|
remote.run(
|
||||||
|
args=['rm', '-f',
|
||||||
|
'{tdir}/ceph/src/test/rgw/lua/lua-tests.{client}.conf'.format(tdir=testdir,client=client),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_toxvenv_dir(ctx):
|
||||||
|
return ctx.tox.venv_path
|
||||||
|
|
||||||
|
|
||||||
|
def toxvenv_sh(ctx, remote, args, **kwargs):
|
||||||
|
activate = get_toxvenv_dir(ctx) + '/bin/activate'
|
||||||
|
return remote.sh(['source', activate, run.Raw('&&')] + args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def run_tests(ctx, config):
|
||||||
|
"""
|
||||||
|
Run the lua tests after everything is set up.
|
||||||
|
:param ctx: Context passed to task
|
||||||
|
:param config: specific configuration information
|
||||||
|
"""
|
||||||
|
assert isinstance(config, dict)
|
||||||
|
log.info('Running lua-tests...')
|
||||||
|
testdir = teuthology.get_testdir(ctx)
|
||||||
|
for client, client_config in config.items():
|
||||||
|
(remote,) = ctx.cluster.only(client).remotes.keys()
|
||||||
|
|
||||||
|
# test marks to use by default
|
||||||
|
attr = ['basic_test', 'request_test', 'example_test']
|
||||||
|
|
||||||
|
if 'extra_attr' in client_config:
|
||||||
|
attr = client_config.get('extra_attr')
|
||||||
|
|
||||||
|
args = ['cd', '{tdir}/ceph/src/test/rgw/lua/'.format(tdir=testdir), run.Raw('&&'),
|
||||||
|
'LUATESTS_CONF=./lua-tests.{client}.conf'.format(client=client),
|
||||||
|
'tox', '--', '-v', '-m', ' or '.join(attr)]
|
||||||
|
|
||||||
|
toxvenv_sh(ctx, remote, args, label="lua tests against rgw")
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def task(ctx,config):
|
||||||
|
"""
|
||||||
|
|
||||||
|
If you want to run the tests against your changes pushed to your remote repo you can provide 'suite_branch' and 'suite_repo'
|
||||||
|
parameters in your teuthology-suite command. Example command for this is as follows::
|
||||||
|
|
||||||
|
teuthology-suite --ceph-repo https://github.com/ceph/ceph-ci.git -s rgw:lua --ceph your_ceph_branch_name -m smithi --suite-repo https://github.com/your_name/ceph.git --suite-branch your_branch_name
|
||||||
|
|
||||||
|
"""
|
||||||
|
assert hasattr(ctx, 'rgw'), 's3tests must run after the rgw task'
|
||||||
|
assert hasattr(ctx, 'tox'), 's3tests must run after the tox task'
|
||||||
|
assert config is None or isinstance(config, list) \
|
||||||
|
or isinstance(config, dict), \
|
||||||
|
"task only supports a list or dictionary for configuration"
|
||||||
|
|
||||||
|
all_clients = ['client.{id}'.format(id=id_)
|
||||||
|
for id_ in teuthology.all_roles_of_type(ctx.cluster, 'client')]
|
||||||
|
if config is None:
|
||||||
|
config = all_clients
|
||||||
|
if isinstance(config, list):
|
||||||
|
config = dict.fromkeys(config)
|
||||||
|
clients=config.keys()
|
||||||
|
|
||||||
|
log.debug('config is %s', config)
|
||||||
|
|
||||||
|
luatests_conf = {}
|
||||||
|
|
||||||
|
for client in clients:
|
||||||
|
endpoint = ctx.rgw.role_endpoints.get(client)
|
||||||
|
assert endpoint, 'luatests: no rgw endpoint for {}'.format(client)
|
||||||
|
|
||||||
|
luatests_conf[client] = ConfigObj(
|
||||||
|
indent_type='',
|
||||||
|
infile={
|
||||||
|
'DEFAULT':
|
||||||
|
{
|
||||||
|
'port':endpoint.port,
|
||||||
|
'host':endpoint.dns_name,
|
||||||
|
},
|
||||||
|
's3 main':{}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
with contextutil.nested(
|
||||||
|
lambda: download(ctx=ctx, config=config),
|
||||||
|
lambda: create_users(ctx=ctx, config=dict(
|
||||||
|
clients=clients,
|
||||||
|
luatests_conf=luatests_conf,
|
||||||
|
)),
|
||||||
|
lambda: configure(ctx=ctx, config=dict(
|
||||||
|
clients=config,
|
||||||
|
luatests_conf=luatests_conf,
|
||||||
|
)),
|
||||||
|
lambda: run_tests(ctx=ctx, config=config),
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
yield
|
||||||
|
|
@ -173,6 +173,31 @@ int create_directory_p(const DoutPrefixProvider *dpp, const fs::path& p) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_luarocks_config(const bp::filesystem::path& process,
|
||||||
|
const std::string& luarocks_path,
|
||||||
|
const bp::environment& env, std::string& output) {
|
||||||
|
bp::ipstream is;
|
||||||
|
auto cmd = process.string();
|
||||||
|
cmd.append(" config");
|
||||||
|
output.append("Lua CMD: ");
|
||||||
|
output.append(cmd);
|
||||||
|
|
||||||
|
try {
|
||||||
|
bp::child c(cmd, env, bp::std_in.close(), (bp::std_err & bp::std_out) > is, bp::start_dir(luarocks_path));
|
||||||
|
std::string line;
|
||||||
|
do {
|
||||||
|
if (!line.empty()) {
|
||||||
|
output.append("\n\t").append(line);
|
||||||
|
}
|
||||||
|
} while (c.running() && std::getline(is, line));
|
||||||
|
|
||||||
|
c.wait();
|
||||||
|
output.append("\n\t").append("exit code: ").append(std::to_string(c.exit_code()));
|
||||||
|
} catch (const std::runtime_error& err) {
|
||||||
|
output.append("\n\t").append(err.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int install_packages(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver,
|
int install_packages(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver,
|
||||||
optional_yield y, const std::string& luarocks_path,
|
optional_yield y, const std::string& luarocks_path,
|
||||||
packages_t& failed_packages, std::string& install_dir) {
|
packages_t& failed_packages, std::string& install_dir) {
|
||||||
@ -202,6 +227,7 @@ int install_packages(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// create a temporary sub-directory to install all luarocks packages
|
// create a temporary sub-directory to install all luarocks packages
|
||||||
std::string tmp_path_template = luarocks_path;// fs::temp_directory_path();
|
std::string tmp_path_template = luarocks_path;// fs::temp_directory_path();
|
||||||
tmp_path_template.append("/XXXXXX");
|
tmp_path_template.append("/XXXXXX");
|
||||||
@ -214,50 +240,46 @@ int install_packages(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver,
|
|||||||
}
|
}
|
||||||
install_dir.assign(tmp_luarocks_path);
|
install_dir.assign(tmp_luarocks_path);
|
||||||
|
|
||||||
{
|
// get a handle to the current environment
|
||||||
bp::ipstream is;
|
auto env = boost::this_process::environment();
|
||||||
const auto cmd = p.string() + " config";
|
bp::environment _env = env;
|
||||||
bp::child c(cmd, bp::std_in.close(), (bp::std_err & bp::std_out) > is);
|
_env["HOME"] = luarocks_path;
|
||||||
|
|
||||||
std::string lines = std::string("Lua CMD: ") + cmd;
|
if (dpp->get_cct()->_conf->subsys.should_gather<ceph_subsys_rgw, 20>()) {
|
||||||
std::string line;
|
std::string output;
|
||||||
|
get_luarocks_config(p, luarocks_path, _env, output);
|
||||||
do {
|
ldpp_dout(dpp, 20) << output << dendl;
|
||||||
if (!line.empty()) {
|
|
||||||
lines.append("\n\t");
|
|
||||||
lines.append(line);
|
|
||||||
}
|
|
||||||
} while (c.running() && std::getline(is, line));
|
|
||||||
|
|
||||||
c.wait();
|
|
||||||
line = "exit code: " + std::to_string(c.exit_code());
|
|
||||||
lines.append("\n\t");
|
|
||||||
lines.append(line);
|
|
||||||
ldpp_dout(dpp, 20) << lines << dendl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the lua rocks install dir will be created by luarocks the first time it is called
|
// the lua rocks install dir will be created by luarocks the first time it is called
|
||||||
for (const auto& package : packages) {
|
for (const auto& package : packages) {
|
||||||
bp::ipstream is;
|
bp::ipstream is;
|
||||||
const auto cmd = p.string() + " install --no-doc --no-manifest --check-lua-versions --lua-version " + CEPH_LUA_VERSION + " --tree " + install_dir + " --deps-mode one " + package;
|
auto cmd = p.string();
|
||||||
bp::child c(cmd, bp::std_in.close(), (bp::std_err & bp::std_out) > is);
|
cmd.append(" install --no-doc --lua-version ").
|
||||||
|
append(CEPH_LUA_VERSION).
|
||||||
|
append(" --tree ").
|
||||||
|
append(install_dir).
|
||||||
|
append(" --deps-mode one ").
|
||||||
|
append(package);
|
||||||
|
bp::child c(cmd, _env, bp::std_in.close(), (bp::std_err & bp::std_out) > is, bp::start_dir(luarocks_path));
|
||||||
|
|
||||||
// once package reload is supported, code should yield when reading output
|
if (dpp->get_cct()->_conf->subsys.should_gather<ceph_subsys_rgw, 20>()) {
|
||||||
std::string lines = std::string("Lua CMD: ") + cmd;
|
// TODO: yield when reading output
|
||||||
|
std::string lines = std::string("Lua CMD: ");
|
||||||
|
lines.append(cmd);
|
||||||
std::string line;
|
std::string line;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!line.empty()) {
|
if (!line.empty()) {
|
||||||
lines.append("\n\t");
|
lines.append("\n\t").append(line);
|
||||||
lines.append(line);
|
|
||||||
}
|
}
|
||||||
} while (c.running() && std::getline(is, line));
|
} while (c.running() && std::getline(is, line));
|
||||||
|
ldpp_dout(dpp, 20) << lines << dendl;
|
||||||
|
}
|
||||||
|
|
||||||
c.wait();
|
c.wait();
|
||||||
if (c.exit_code()) {
|
if (c.exit_code()) {
|
||||||
failed_packages.insert(package);
|
failed_packages.insert(package);
|
||||||
}
|
}
|
||||||
ldpp_dout(dpp, 20) << lines << dendl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
9
src/test/rgw/lua/README.rst
Normal file
9
src/test/rgw/lua/README.rst
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
===================
|
||||||
|
Lua Scripting Tests
|
||||||
|
===================
|
||||||
|
|
||||||
|
* Start the cluster using the `vstart.sh` script
|
||||||
|
* `luarocks` (package manager for lua) must be installed on the machine
|
||||||
|
* Run the test from within the `src/test/rgw/lua` directory:
|
||||||
|
`LUATESTS_CONF=luatests.conf.SAMPLE tox`
|
||||||
|
|
60
src/test/rgw/lua/__init__.py
Normal file
60
src/test/rgw/lua/__init__.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import configparser
|
||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
def setup():
|
||||||
|
cfg = configparser.RawConfigParser()
|
||||||
|
try:
|
||||||
|
path = os.environ['LUATESTS_CONF']
|
||||||
|
except KeyError:
|
||||||
|
raise RuntimeError(
|
||||||
|
'To run tests, point environment '
|
||||||
|
+ 'variable LUATESTS_CONF to a config file.',
|
||||||
|
)
|
||||||
|
cfg.read(path)
|
||||||
|
|
||||||
|
if not cfg.defaults():
|
||||||
|
raise RuntimeError('Your config file is missing the DEFAULT section!')
|
||||||
|
if not cfg.has_section("s3 main"):
|
||||||
|
raise RuntimeError('Your config file is missing the "s3 main" section!')
|
||||||
|
|
||||||
|
defaults = cfg.defaults()
|
||||||
|
|
||||||
|
# vars from the DEFAULT section
|
||||||
|
global default_host
|
||||||
|
default_host = defaults.get("host")
|
||||||
|
|
||||||
|
global default_port
|
||||||
|
default_port = int(defaults.get("port"))
|
||||||
|
# vars from the main section
|
||||||
|
global main_access_key
|
||||||
|
main_access_key = cfg.get('s3 main',"access_key")
|
||||||
|
|
||||||
|
global main_secret_key
|
||||||
|
main_secret_key = cfg.get('s3 main',"secret_key")
|
||||||
|
|
||||||
|
|
||||||
|
def get_config_host():
|
||||||
|
global default_host
|
||||||
|
return default_host
|
||||||
|
|
||||||
|
|
||||||
|
def get_config_port():
|
||||||
|
global default_port
|
||||||
|
return default_port
|
||||||
|
|
||||||
|
|
||||||
|
def get_access_key():
|
||||||
|
global main_access_key
|
||||||
|
return main_access_key
|
||||||
|
|
||||||
|
|
||||||
|
def get_secret_key():
|
||||||
|
global main_secret_key
|
||||||
|
return main_secret_key
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True, scope="package")
|
||||||
|
def configfile():
|
||||||
|
setup()
|
||||||
|
|
10
src/test/rgw/lua/luatests.conf.SAMPLE
Normal file
10
src/test/rgw/lua/luatests.conf.SAMPLE
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
port = 8000
|
||||||
|
host = localhost
|
||||||
|
|
||||||
|
[s3 main]
|
||||||
|
access_key = 0555b35654ad1656d804
|
||||||
|
secret_key = h7GhxuBLTrlhVUyxSPUKUV8r/2EI4ngqJxD7iBdBYLhwluN30JaT3Q==
|
||||||
|
display_name = M. Tester
|
||||||
|
user_id = testid
|
||||||
|
email = tester@ceph.com
|
5
src/test/rgw/lua/pytest.ini
Normal file
5
src/test/rgw/lua/pytest.ini
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[pytest]
|
||||||
|
markers =
|
||||||
|
basic_test
|
||||||
|
request_test
|
||||||
|
example_test
|
2
src/test/rgw/lua/requirements.txt
Normal file
2
src/test/rgw/lua/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
boto3 >=1.0.0
|
||||||
|
pytest
|
476
src/test/rgw/lua/test_lua.py
Normal file
476
src/test/rgw/lua/test_lua.py
Normal file
@ -0,0 +1,476 @@
|
|||||||
|
import logging
|
||||||
|
import json
|
||||||
|
import tempfile
|
||||||
|
import random
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import string
|
||||||
|
import pytest
|
||||||
|
import boto3
|
||||||
|
|
||||||
|
from . import(
|
||||||
|
configfile,
|
||||||
|
get_config_host,
|
||||||
|
get_config_port,
|
||||||
|
get_access_key,
|
||||||
|
get_secret_key
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# configure logging for the tests module
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
num_buckets = 0
|
||||||
|
run_prefix=''.join(random.choice(string.ascii_lowercase) for _ in range(6))
|
||||||
|
|
||||||
|
test_path = os.path.normpath(os.path.dirname(os.path.realpath(__file__))) + '/../'
|
||||||
|
|
||||||
|
def bash(cmd, **kwargs):
|
||||||
|
log.debug('running command: %s', ' '.join(cmd))
|
||||||
|
kwargs['stdout'] = subprocess.PIPE
|
||||||
|
process = subprocess.Popen(cmd, **kwargs)
|
||||||
|
s = process.communicate()[0].decode('utf-8')
|
||||||
|
return (s, process.returncode)
|
||||||
|
|
||||||
|
|
||||||
|
def admin(args, **kwargs):
|
||||||
|
""" radosgw-admin command """
|
||||||
|
cmd = [test_path + 'test-rgw-call.sh', 'call_rgw_admin', 'noname'] + args
|
||||||
|
return bash(cmd, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_all_objects(conn, bucket_name):
|
||||||
|
objects = []
|
||||||
|
for key in conn.list_objects(Bucket=bucket_name)['Contents']:
|
||||||
|
objects.append({'Key': key['Key']})
|
||||||
|
# delete objects from the bucket
|
||||||
|
response = conn.delete_objects(Bucket=bucket_name,
|
||||||
|
Delete={'Objects': objects})
|
||||||
|
|
||||||
|
|
||||||
|
def gen_bucket_name():
|
||||||
|
global num_buckets
|
||||||
|
|
||||||
|
num_buckets += 1
|
||||||
|
return run_prefix + '-' + str(num_buckets)
|
||||||
|
|
||||||
|
|
||||||
|
def get_ip():
|
||||||
|
return 'localhost'
|
||||||
|
|
||||||
|
|
||||||
|
def get_ip_http():
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
try:
|
||||||
|
# address should not be reachable
|
||||||
|
s.connect(('10.255.255.255', 1))
|
||||||
|
ip = s.getsockname()[0]
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
return ip
|
||||||
|
|
||||||
|
|
||||||
|
def connection():
|
||||||
|
hostname = get_config_host()
|
||||||
|
port_no = get_config_port()
|
||||||
|
access_key = get_access_key()
|
||||||
|
secret_key = get_secret_key()
|
||||||
|
if port_no == 443 or port_no == 8443:
|
||||||
|
scheme = 'https://'
|
||||||
|
else:
|
||||||
|
scheme = 'http://'
|
||||||
|
|
||||||
|
client = boto3.client('s3',
|
||||||
|
endpoint_url=scheme+hostname+':'+str(port_no),
|
||||||
|
aws_access_key_id=access_key,
|
||||||
|
aws_secret_access_key=secret_key)
|
||||||
|
|
||||||
|
return client
|
||||||
|
|
||||||
|
|
||||||
|
def another_user(tenant=None):
|
||||||
|
access_key = str(time.time())
|
||||||
|
secret_key = str(time.time())
|
||||||
|
uid = 'superman' + str(time.time())
|
||||||
|
if tenant:
|
||||||
|
_, result = admin(['user', 'create', '--uid', uid, '--tenant', tenant, '--access-key', access_key, '--secret-key', secret_key, '--display-name', '"Super Man"'])
|
||||||
|
else:
|
||||||
|
_, result = admin(['user', 'create', '--uid', uid, '--access-key', access_key, '--secret-key', secret_key, '--display-name', '"Super Man"'])
|
||||||
|
|
||||||
|
assert result == 0
|
||||||
|
hostname = get_config_host()
|
||||||
|
port_no = get_config_port()
|
||||||
|
if port_no == 443 or port_no == 8443:
|
||||||
|
scheme = 'https://'
|
||||||
|
else:
|
||||||
|
scheme = 'http://'
|
||||||
|
|
||||||
|
client = boto3.client('s3',
|
||||||
|
endpoint_url=scheme+hostname+':'+str(port_no),
|
||||||
|
aws_access_key_id=access_key,
|
||||||
|
aws_secret_access_key=secret_key)
|
||||||
|
|
||||||
|
return client
|
||||||
|
|
||||||
|
|
||||||
|
def put_script(script, context, tenant=None):
|
||||||
|
fp = tempfile.NamedTemporaryFile(mode='w+')
|
||||||
|
fp.write(script)
|
||||||
|
fp.flush()
|
||||||
|
if tenant:
|
||||||
|
result = admin(['script', 'put', '--infile', fp.name, '--context', context, '--tenant', tenant])
|
||||||
|
else:
|
||||||
|
result = admin(['script', 'put', '--infile', fp.name, '--context', context])
|
||||||
|
|
||||||
|
fp.close()
|
||||||
|
return result
|
||||||
|
|
||||||
|
class UnixSocket:
|
||||||
|
def __init__(self, socket_path):
|
||||||
|
self.socket_path = socket_path
|
||||||
|
self.stop = False
|
||||||
|
self.started = False
|
||||||
|
self.events = []
|
||||||
|
self.t = threading.Thread(target=self.listen_on_socket)
|
||||||
|
self.t.start()
|
||||||
|
while not self.started:
|
||||||
|
print("UnixSocket: waiting for unix socket server to start")
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
self.stop = True
|
||||||
|
self.t.join()
|
||||||
|
|
||||||
|
def get_and_reset_events(self):
|
||||||
|
tmp = self.events
|
||||||
|
self.events = []
|
||||||
|
return tmp
|
||||||
|
|
||||||
|
def listen_on_socket(self):
|
||||||
|
self.started = True
|
||||||
|
# remove the socket file if it already exists
|
||||||
|
try:
|
||||||
|
os.unlink(self.socket_path)
|
||||||
|
except OSError:
|
||||||
|
if os.path.exists(self.socket_path):
|
||||||
|
raise
|
||||||
|
|
||||||
|
# create and bind the Unix socket server
|
||||||
|
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
server.bind(self.socket_path)
|
||||||
|
|
||||||
|
# give permissions for anyone to write to it
|
||||||
|
os.chmod(self.socket_path, stat.S_IWOTH|stat.S_IWGRP|stat.S_IWUSR)
|
||||||
|
|
||||||
|
# listen for incoming connections
|
||||||
|
server.listen(1)
|
||||||
|
# accept timeout is 30s at the beginning
|
||||||
|
server.settimeout(30)
|
||||||
|
print("UnixSocket '%s' is listening for incoming connections..." % self.socket_path)
|
||||||
|
|
||||||
|
while not self.stop:
|
||||||
|
# accept connections
|
||||||
|
try:
|
||||||
|
connection, _ = server.accept()
|
||||||
|
except Exception as e:
|
||||||
|
print("UnixSocket: accept "+str(e))
|
||||||
|
continue
|
||||||
|
# after we start accept/recv timeouts are 5s
|
||||||
|
server.settimeout(5)
|
||||||
|
connection.settimeout(5)
|
||||||
|
|
||||||
|
try:
|
||||||
|
print("UnixSocket: new connection accepted")
|
||||||
|
# receive data from the client
|
||||||
|
while True:
|
||||||
|
# recv timeout is 5s
|
||||||
|
data = connection.recv(1024)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
event = json.loads(data.decode())
|
||||||
|
self.events.append(event)
|
||||||
|
finally:
|
||||||
|
# close the connection
|
||||||
|
connection.close()
|
||||||
|
print("UnixSocket: connection closed")
|
||||||
|
|
||||||
|
# remove the socket file
|
||||||
|
os.unlink(self.socket_path)
|
||||||
|
|
||||||
|
|
||||||
|
#####################
|
||||||
|
# lua scripting tests
|
||||||
|
#####################
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.basic_test
|
||||||
|
def test_script_management():
|
||||||
|
contexts = ['prerequest', 'postrequest', 'background', 'getdata', 'putdata']
|
||||||
|
scripts = {}
|
||||||
|
for context in contexts:
|
||||||
|
script = 'print("hello from ' + context + '")'
|
||||||
|
result = put_script(script, context)
|
||||||
|
assert result[1] == 0
|
||||||
|
scripts[context] = script
|
||||||
|
for context in contexts:
|
||||||
|
result = admin(['script', 'get', '--context', context])
|
||||||
|
assert result[1] == 0
|
||||||
|
assert result[0].strip() == scripts[context]
|
||||||
|
for context in contexts:
|
||||||
|
result = admin(['script', 'rm', '--context', context])
|
||||||
|
assert result[1] == 0
|
||||||
|
for context in contexts:
|
||||||
|
result = admin(['script', 'get', '--context', context])
|
||||||
|
assert result[1] == 0
|
||||||
|
assert result[0].strip() == 'no script exists for context: ' + context
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.basic_test
|
||||||
|
def test_script_management_with_tenant():
|
||||||
|
tenant = 'mytenant'
|
||||||
|
conn2 = another_user(tenant)
|
||||||
|
contexts = ['prerequest', 'postrequest', 'getdata', 'putdata']
|
||||||
|
scripts = {}
|
||||||
|
for context in contexts:
|
||||||
|
for t in ['', tenant]:
|
||||||
|
script = 'print("hello from ' + context + ' and ' + tenant + '")'
|
||||||
|
result = put_script(script, context, t)
|
||||||
|
assert result[1] == 0
|
||||||
|
scripts[context+t] = script
|
||||||
|
for context in contexts:
|
||||||
|
result = admin(['script', 'get', '--context', context])
|
||||||
|
assert result[1] == 0
|
||||||
|
assert result[0].strip(), scripts[context]
|
||||||
|
result = admin(['script', 'rm', '--context', context])
|
||||||
|
assert result[1] == 0
|
||||||
|
result = admin(['script', 'get', '--context', context])
|
||||||
|
assert result[1] == 0
|
||||||
|
assert result[0].strip(), 'no script exists for context: ' + context
|
||||||
|
result = admin(['script', 'get', '--context', context, '--tenant', tenant])
|
||||||
|
assert result[1] == 0
|
||||||
|
assert result[0].strip(), scripts[context+tenant]
|
||||||
|
result = admin(['script', 'rm', '--context', context, '--tenant', tenant])
|
||||||
|
assert result[1] == 0
|
||||||
|
result = admin(['script', 'get', '--context', context, '--tenant', tenant])
|
||||||
|
assert result[1] == 0
|
||||||
|
assert result[0].strip(), 'no script exists for context: ' + context + ' in tenant: ' + tenant
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.request_test
|
||||||
|
def test_put_obj():
|
||||||
|
script = '''
|
||||||
|
RGWDebugLog("op was: "..Request.RGWOp)
|
||||||
|
if Request.RGWOp == "put_obj" then
|
||||||
|
local object = Request.Object
|
||||||
|
local message = Request.bucket.Name .. "," .. object.Name ..
|
||||||
|
"," .. object.Id .. "," .. object.Size .. "," .. object.MTime
|
||||||
|
RGWDebugLog("set: x-amz-meta-test to: " .. message)
|
||||||
|
Request.HTTP.Metadata["x-amz-meta-test"] = message
|
||||||
|
end
|
||||||
|
'''
|
||||||
|
context = "prerequest"
|
||||||
|
result = put_script(script, context)
|
||||||
|
assert result[1] == 0
|
||||||
|
|
||||||
|
conn = connection()
|
||||||
|
bucket_name = gen_bucket_name()
|
||||||
|
conn.create_bucket(Bucket=bucket_name)
|
||||||
|
key = "hello"
|
||||||
|
conn.put_object(Body="1234567890".encode("ascii"), Bucket=bucket_name, Key=key)
|
||||||
|
|
||||||
|
result = conn.get_object(Bucket=bucket_name, Key=key)
|
||||||
|
message = result['ResponseMetadata']['HTTPHeaders']['x-amz-meta-test']
|
||||||
|
assert message == bucket_name+","+key+","+key+",0,1970-01-01 00:00:00"
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
conn.delete_object(Bucket=bucket_name, Key=key)
|
||||||
|
conn.delete_bucket(Bucket=bucket_name)
|
||||||
|
contexts = ['prerequest', 'postrequest', 'getdata', 'putdata']
|
||||||
|
for context in contexts:
|
||||||
|
result = admin(['script', 'rm', '--context', context])
|
||||||
|
assert result[1] == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.example_test
|
||||||
|
def test_copyfrom():
|
||||||
|
script = '''
|
||||||
|
function print_object(object)
|
||||||
|
RGWDebugLog(" Name: " .. object.Name)
|
||||||
|
RGWDebugLog(" Instance: " .. object.Instance)
|
||||||
|
RGWDebugLog(" Id: " .. object.Id)
|
||||||
|
RGWDebugLog(" Size: " .. object.Size)
|
||||||
|
RGWDebugLog(" MTime: " .. object.MTime)
|
||||||
|
end
|
||||||
|
|
||||||
|
if Request.CopyFrom and Request.Object and Request.CopyFrom.Object then
|
||||||
|
RGWDebugLog("copy from object:")
|
||||||
|
print_object(Request.CopyFrom.Object)
|
||||||
|
RGWDebugLog("to object:")
|
||||||
|
print_object(Request.Object)
|
||||||
|
end
|
||||||
|
RGWDebugLog("op was: "..Request.RGWOp)
|
||||||
|
'''
|
||||||
|
|
||||||
|
contexts = ['prerequest', 'postrequest', 'getdata', 'putdata']
|
||||||
|
for context in contexts:
|
||||||
|
footer = '\nRGWDebugLog("context was: '+context+'\\n\\n")'
|
||||||
|
result = put_script(script+footer, context)
|
||||||
|
assert result[1] == 0
|
||||||
|
|
||||||
|
conn = connection()
|
||||||
|
bucket_name = gen_bucket_name()
|
||||||
|
# create bucket
|
||||||
|
bucket = conn.create_bucket(Bucket=bucket_name)
|
||||||
|
# create objects in the bucket
|
||||||
|
number_of_objects = 5
|
||||||
|
for i in range(number_of_objects):
|
||||||
|
content = str(os.urandom(1024*1024)).encode("ascii")
|
||||||
|
key = str(i)
|
||||||
|
conn.put_object(Body=content, Bucket=bucket_name, Key=key)
|
||||||
|
|
||||||
|
for i in range(number_of_objects):
|
||||||
|
key = str(i)
|
||||||
|
conn.copy_object(Bucket=bucket_name,
|
||||||
|
Key='copyof'+key,
|
||||||
|
CopySource=bucket_name+'/'+key)
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
delete_all_objects(conn, bucket_name)
|
||||||
|
conn.delete_bucket(Bucket=bucket_name)
|
||||||
|
contexts = ['prerequest', 'postrequest', 'getdata', 'putdata']
|
||||||
|
for context in contexts:
|
||||||
|
result = admin(['script', 'rm', '--context', context])
|
||||||
|
assert result[1] == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.example_test
|
||||||
|
def test_entropy():
|
||||||
|
script = '''
|
||||||
|
function object_entropy()
|
||||||
|
local byte_hist = {}
|
||||||
|
local byte_hist_size = 256
|
||||||
|
for i = 1,byte_hist_size do
|
||||||
|
byte_hist[i] = 0
|
||||||
|
end
|
||||||
|
local total = 0
|
||||||
|
|
||||||
|
for i, c in pairs(Data) do
|
||||||
|
local byte = c:byte() + 1
|
||||||
|
byte_hist[byte] = byte_hist[byte] + 1
|
||||||
|
total = total + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
entropy = 0
|
||||||
|
|
||||||
|
for _, count in ipairs(byte_hist) do
|
||||||
|
if count ~= 0 then
|
||||||
|
local p = 1.0 * count / total
|
||||||
|
entropy = entropy - (p * math.log(p)/math.log(byte_hist_size))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return entropy
|
||||||
|
end
|
||||||
|
|
||||||
|
local full_name = Request.Bucket.Name.."-"..Request.Object.Name
|
||||||
|
RGWDebugLog("entropy of chunk of: " .. full_name .. " at offset: " .. tostring(Offset) .. " is: " .. tostring(object_entropy()))
|
||||||
|
RGWDebugLog("payload size of chunk of: " .. full_name .. " is: " .. #Data)
|
||||||
|
'''
|
||||||
|
|
||||||
|
result = put_script(script, "putdata")
|
||||||
|
assert result[1] == 0
|
||||||
|
|
||||||
|
conn = connection()
|
||||||
|
bucket_name = gen_bucket_name()
|
||||||
|
# create bucket
|
||||||
|
bucket = conn.create_bucket(Bucket=bucket_name)
|
||||||
|
# create objects in the bucket (async)
|
||||||
|
number_of_objects = 5
|
||||||
|
for i in range(number_of_objects):
|
||||||
|
content = str(os.urandom(1024*1024*16)).encode("ascii")
|
||||||
|
key = str(i)
|
||||||
|
conn.put_object(Body=content, Bucket=bucket_name, Key=key)
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
delete_all_objects(conn, bucket_name)
|
||||||
|
conn.delete_bucket(Bucket=bucket_name)
|
||||||
|
contexts = ['prerequest', 'postrequest', 'background', 'getdata', 'putdata']
|
||||||
|
for context in contexts:
|
||||||
|
result = admin(['script', 'rm', '--context', context])
|
||||||
|
assert result[1] == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.example_test
|
||||||
|
def test_access_log():
|
||||||
|
bucket_name = gen_bucket_name()
|
||||||
|
socket_path = '/tmp/'+bucket_name
|
||||||
|
|
||||||
|
script = '''
|
||||||
|
if Request.RGWOp == "get_obj" then
|
||||||
|
local json = require("cjson")
|
||||||
|
local socket = require("socket")
|
||||||
|
local unix = require("socket.unix")
|
||||||
|
local s = unix()
|
||||||
|
E = {{}}
|
||||||
|
|
||||||
|
msg = {{bucket = (Request.Bucket or (Request.CopyFrom or E).Bucket).Name,
|
||||||
|
object = Request.Object.Name,
|
||||||
|
time = Request.Time,
|
||||||
|
operation = Request.RGWOp,
|
||||||
|
http_status = Request.Response.HTTPStatusCode,
|
||||||
|
error_code = Request.Response.HTTPStatus,
|
||||||
|
object_size = Request.Object.Size,
|
||||||
|
trans_id = Request.TransactionId}}
|
||||||
|
assert(s:connect("{}"))
|
||||||
|
s:send(json.encode(msg).."\\n")
|
||||||
|
s:close()
|
||||||
|
end
|
||||||
|
'''.format(socket_path)
|
||||||
|
|
||||||
|
result = admin(['script-package', 'add', '--package=lua-cjson', '--allow-compilation'])
|
||||||
|
assert result[1] == 0
|
||||||
|
result = admin(['script-package', 'add', '--package=luasocket', '--allow-compilation'])
|
||||||
|
assert result[1] == 0
|
||||||
|
result = admin(['script-package', 'reload'])
|
||||||
|
assert result[1] == 0
|
||||||
|
result = put_script(script, "postrequest")
|
||||||
|
assert result[1] == 0
|
||||||
|
|
||||||
|
socket_server = UnixSocket(socket_path)
|
||||||
|
try:
|
||||||
|
conn = connection()
|
||||||
|
# create bucket
|
||||||
|
bucket = conn.create_bucket(Bucket=bucket_name)
|
||||||
|
# create objects in the bucket (async)
|
||||||
|
number_of_objects = 5
|
||||||
|
keys = []
|
||||||
|
for i in range(number_of_objects):
|
||||||
|
content = str(os.urandom(1024*1024)).encode("ascii")
|
||||||
|
key = str(i)
|
||||||
|
conn.put_object(Body=content, Bucket=bucket_name, Key=key)
|
||||||
|
keys.append(key)
|
||||||
|
|
||||||
|
for key in conn.list_objects(Bucket=bucket_name)['Contents']:
|
||||||
|
conn.get_object(Bucket=bucket_name, Key=key['Key'])
|
||||||
|
|
||||||
|
time.sleep(5)
|
||||||
|
event_keys = []
|
||||||
|
for event in socket_server.get_and_reset_events():
|
||||||
|
assert event['bucket'] == bucket_name
|
||||||
|
event_keys.append(event['object'])
|
||||||
|
|
||||||
|
assert keys == event_keys
|
||||||
|
|
||||||
|
finally:
|
||||||
|
socket_server.shutdown()
|
||||||
|
delete_all_objects(conn, bucket_name)
|
||||||
|
conn.delete_bucket(Bucket=bucket_name)
|
||||||
|
contexts = ['prerequest', 'postrequest', 'background', 'getdata', 'putdata']
|
||||||
|
for context in contexts:
|
||||||
|
result = admin(['script', 'rm', '--context', context])
|
||||||
|
assert result[1] == 0
|
||||||
|
|
9
src/test/rgw/lua/tox.ini
Normal file
9
src/test/rgw/lua/tox.ini
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[tox]
|
||||||
|
envlist = py
|
||||||
|
skipsdist = True
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
deps = -rrequirements.txt
|
||||||
|
passenv =
|
||||||
|
LUATESTS_CONF
|
||||||
|
commands = pytest {posargs}
|
Loading…
Reference in New Issue
Block a user