mirror of
https://github.com/scylladb/scylladb.git
synced 2026-05-12 19:02:12 +00:00
Merge 'test.py: run Alternator tests' from Nadav
We have in alternator-test a set of over 340 functional tests for
Alternator. These tests are written in Python using the pytest
framework, expect Scylla to be running and connect to it using the
DynamoDB API with the "boto3" library (the AWS SDK for Python).
We have a script alternator-test/run which does everything needed
to run all these tests: Starts Scylla with the appropriate parameters
in a temporary directory, runs all the tests against it, and makes
sure the temporary directory is removed (regardless of whether the
tests succeeded or failed).
The goal of this small patch series is to integrate these Alternator
tests into test.py in a *simple* way. The idea is that we add *one*
test which just runs the aforementioned "run" script which does its
own business.
The changes we needed to do in this series to achieve this are:
1. Make the alternator-test/run script pick a unique IP address on which
to listen, instead of always using 127.0.0.1. This allows running
this test in parallel with dtest tests, or even parallel to itself.
2. Move the alternator-test directory to test/alternator. This is
the directory where test.py expects all the tests to live in.
It also makes sense - since we already have multiple subdirectories
in test/, to put the Alternator tests there too.
3. Add a new test suite type, "Run". A "Run" suite is simply a directory
with a script called "run", and this script is run to run the entire
suite, and this script does its own business.
4. Tests (such as the new "Run" ones) who can be killed gently and clean
up after themselves, should be killed with SIGTERM instead of
SIGKILL.
After this series, to run the Alternator tests from test.py, do:
./test.py --mode dev alternator
Note that in this version, the "--mode" has no effect - test/alternator/run
always runs the latest compiled Scylla, regardless of the chosen mode.
This can be fixed later.
The Alternator tests can still be run manually and individually against
a running Scylla or DynamoDB as before - just go to the test/alternator
directory and run "pytest" with the desired parameters.
Fixes #6046
* nyh/alternator-test-v3:
alternator-test: make Alternator tests runnable from test.py
test.py: add xunit XML output file for "Run" tests
test.py: add new test type "Run"
test.py: flag for aborting tests with SIGTERM, not SIGKILL
alternator-test: change "run" script to pick random IP address
alternator-test: add "--url" option to choose Alternator's URL
This commit is contained in:
36
test.py
36
test.py
@@ -203,6 +203,17 @@ class CqlTestSuite(TestSuite):
|
||||
def pattern(self):
|
||||
return "*_test.cql"
|
||||
|
||||
class RunTestSuite(TestSuite):
|
||||
"""TestSuite for test directory with a 'run' script """
|
||||
|
||||
def add_test(self, shortname, mode, options):
|
||||
test = RunTest(self.next_id, shortname, self, mode, options)
|
||||
self.tests.append(test)
|
||||
|
||||
@property
|
||||
def pattern(self):
|
||||
return "run"
|
||||
|
||||
|
||||
class Test:
|
||||
"""Base class for CQL, Unit and Boost tests"""
|
||||
@@ -332,6 +343,24 @@ class CqlTest(Test):
|
||||
if self.is_equal_result is False:
|
||||
print_unidiff(self.result, self.reject)
|
||||
|
||||
class RunTest(Test):
|
||||
"""Run tests in a directory started by a run script"""
|
||||
|
||||
def __init__(self, test_no, shortname, suite, mode, options):
|
||||
super().__init__(test_no, shortname, suite, mode, options)
|
||||
self.path = os.path.join(suite.path, shortname)
|
||||
self.xmlout = os.path.join(options.tmpdir, self.mode, "xml", self.uname + ".xunit.xml")
|
||||
self.args = ["--junit-xml={}".format(self.xmlout)]
|
||||
|
||||
def print_summary(self):
|
||||
print("Output of {} {}:".format(self.path, " ".join(self.args)))
|
||||
print(read_log(self.log_filename))
|
||||
|
||||
async def run(self, options):
|
||||
# This test can and should be killed gently, with SIGTERM, not with SIGKILL
|
||||
self.success = await run_test(self, options, gentle_kill=True)
|
||||
logging.info("Test #%d %s", self.id, "succeeded" if self.success else "failed ")
|
||||
return self
|
||||
|
||||
class TabularConsoleOutput:
|
||||
"""Print test progress to the console"""
|
||||
@@ -375,7 +404,7 @@ class TabularConsoleOutput:
|
||||
print(msg)
|
||||
|
||||
|
||||
async def run_test(test, options):
|
||||
async def run_test(test, options, gentle_kill=False):
|
||||
"""Run test program, return True if success else False"""
|
||||
|
||||
with open(test.log_filename, "wb") as log:
|
||||
@@ -423,7 +452,10 @@ async def run_test(test, options):
|
||||
return True
|
||||
except (asyncio.TimeoutError, asyncio.CancelledError) as e:
|
||||
if process is not None:
|
||||
process.kill()
|
||||
if gentle_kill:
|
||||
process.terminate()
|
||||
else:
|
||||
process.kill()
|
||||
stdout, _ = await process.communicate()
|
||||
if isinstance(e, asyncio.TimeoutError):
|
||||
report_error("Test timed out")
|
||||
|
||||
@@ -54,6 +54,8 @@ def pytest_addoption(parser):
|
||||
parser.addoption("--https", action="store_true",
|
||||
help="communicate via HTTPS protocol on port 8043 instead of HTTP when"
|
||||
" running against a local Scylla installation")
|
||||
parser.addoption("--url", action="store",
|
||||
help="communicate with given URL instead of defaults")
|
||||
|
||||
# "dynamodb" fixture: set up client object for communicating with the DynamoDB
|
||||
# API. Currently this chooses either Amazon's DynamoDB in the default region
|
||||
@@ -70,7 +72,10 @@ def dynamodb(request):
|
||||
# requires us to specify dummy region and credential parameters,
|
||||
# otherwise the user is forced to properly configure ~/.aws even
|
||||
# for local runs.
|
||||
local_url = 'https://localhost:8043' if request.config.getoption('https') else 'http://localhost:8000'
|
||||
if request.config.getoption('url') != None:
|
||||
local_url = request.config.getoption('url')
|
||||
else:
|
||||
local_url = 'https://localhost:8043' if request.config.getoption('https') else 'http://localhost:8000'
|
||||
# Disable verifying in order to be able to use self-signed TLS certificates
|
||||
verify = not request.config.getoption('https')
|
||||
return boto3.resource('dynamodb', endpoint_url=local_url, verify=verify,
|
||||
@@ -4,11 +4,11 @@
|
||||
set -e
|
||||
|
||||
script_path=$(dirname $(readlink -e $0))
|
||||
source_path=$script_path/../..
|
||||
|
||||
# By default, we take the latest build/*/scylla as the executable:
|
||||
SCYLLA=${SCYLLA-$(ls -t "$script_path/../build/"*"/scylla" | head -1)}
|
||||
SCYLLA=${SCYLLA-$(ls -t "$source_path/build/"*"/scylla" | head -1)}
|
||||
SCYLLA=$(readlink -f "$SCYLLA")
|
||||
SCYLLA_IP=${IP-127.0.0.1}
|
||||
CPUSET=${CPUSET-0}
|
||||
|
||||
# Below, we need to use python3 and the Cassandra drive to set up the
|
||||
@@ -21,6 +21,14 @@ then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Pick a loopback IP address for Scylla to run, in an attempt not to collide
|
||||
# other concurrent runs of Scylla. CCM uses 127.0.0.<nodenum>, so if we use
|
||||
# 127.1.*.* which cannot collide with it. Moreover, we'll take the last two
|
||||
# bytes of the address from the current process - so as to allow multiple
|
||||
# concurrent runs of this code to use a different address.
|
||||
SCYLLA_IP=127.1.$(($$ >> 8 & 255)).$(($$ & 255))
|
||||
echo "Running Scylla on $SCYLLA_IP"
|
||||
|
||||
tmp_dir=/tmp/alternator-test-$$
|
||||
mkdir $tmp_dir
|
||||
|
||||
@@ -51,6 +59,7 @@ trap 'cleanup' EXIT
|
||||
# to work. We only need to do this if the "--https" option was explicitly
|
||||
# passed - otherwise the test would not use HTTPS anyway.
|
||||
alternator_port_option="--alternator-port=8000"
|
||||
alternator_url="http://$SCYLLA_IP:8000"
|
||||
for i
|
||||
do
|
||||
if [ "$i" = --https ]
|
||||
@@ -58,17 +67,20 @@ do
|
||||
openssl genrsa 2048 > "$tmp_dir/scylla.key"
|
||||
openssl req -new -x509 -nodes -sha256 -days 365 -subj "/C=IL/ST=None/L=None/O=None/OU=None/CN=example.com" -key "$tmp_dir/scylla.key" -out "$tmp_dir/scylla.crt"
|
||||
alternator_port_option="--alternator-https-port=8043"
|
||||
alternator_url="https://$SCYLLA_IP:8043"
|
||||
fi
|
||||
done
|
||||
"$SCYLLA" --options-file "$script_path/../conf/scylla.yaml" \
|
||||
--alternator-address $SCYLLA_IP \
|
||||
"$SCYLLA" --options-file "$source_path/conf/scylla.yaml" \
|
||||
--alternator-address $SCYLLA_IP \
|
||||
$alternator_port_option \
|
||||
--alternator-enforce-authorization=1 \
|
||||
--developer-mode=1 \
|
||||
--ring-delay-ms 0 --collectd 0 \
|
||||
--cpuset "$CPUSET" -m 1G \
|
||||
--api-address $SCYLLA_IP --rpc-address $SCYLLA_IP \
|
||||
--api-address $SCYLLA_IP \
|
||||
--rpc-address $SCYLLA_IP \
|
||||
--listen-address $SCYLLA_IP \
|
||||
--prometheus-address $SCYLLA_IP \
|
||||
--seed-provider-parameters seeds=$SCYLLA_IP \
|
||||
--workdir "$tmp_dir" \
|
||||
--server-encryption-options keyfile="$tmp_dir/scylla.key" \
|
||||
@@ -81,7 +93,7 @@ SCYLLA_PROCESS=$!
|
||||
# test. This requires connecting to Scylla with CQL - we'll wait up for
|
||||
# one minute for this to work:
|
||||
setup_authentication() {
|
||||
python3 -c 'from cassandra.cluster import Cluster; Cluster().connect().execute("INSERT INTO system_auth.roles (role, salted_hash) VALUES ('\''alternator'\'', '\''secret_pass'\'')")'
|
||||
python3 -c 'from cassandra.cluster import Cluster; Cluster(["'$SCYLLA_IP'"]).connect().execute("INSERT INTO system_auth.roles (role, salted_hash) VALUES ('\''alternator'\'', '\''secret_pass'\'')")'
|
||||
}
|
||||
echo "Scylla is: $SCYLLA."
|
||||
echo -n "Booting Scylla..."
|
||||
@@ -127,7 +139,8 @@ else
|
||||
fi
|
||||
|
||||
cd "$script_path"
|
||||
pytest "$@"
|
||||
set +e
|
||||
pytest --url $alternator_url "$@"
|
||||
code=$?
|
||||
case $code in
|
||||
0) summary="Alternator tests pass";;
|
||||
1
test/alternator/suite.yaml
Normal file
1
test/alternator/suite.yaml
Normal file
@@ -0,0 +1 @@
|
||||
type: Run
|
||||
Reference in New Issue
Block a user