#!/usr/bin/env python3 # Use the run.py library from ../cqlpy: import sys sys.path.insert(1, sys.path[0] + '/../cqlpy') import run import os import requests import glob # When tests are to be run against AWS (the "--aws" option), it is not # necessary to start Scylla at all. All we need to do is to run pytest. if '--aws' in sys.argv: success = run.run_pytest(sys.path[0], ['-o', 'xfail_strict=false'] + sys.argv[1:]) exit(0 if success else 1) # check_alternator() below uses verify=False to accept self-signed SSL # certificates but then we get scary warnings. This trick disables them: import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # If the first option is "--release", download that release (see # fetch_scylla.py for supported release numbers), and use that. # The downloaded Scylla will be cached in the directory build/, # where is the specific release downloaded - E.g., if the user # asks "--release 2022.1" and the downloaded release is 2022.1.9, it # will be stored in build/2022.1.9. if len(sys.argv) > 1 and sys.argv[1] == '--release': release = sys.argv[2] exe = run.download_precompiled_scylla(release) run_scylla_cmd = lambda pid, dir: run.run_precompiled_scylla_cmd(exe, pid, dir) sys.argv = sys.argv[0:1] + sys.argv[3:] os.environ['SCYLLA'] = exe # so find_scylla() prints the right one else: run_scylla_cmd = run.run_scylla_cmd print('Scylla is: ' + run.find_scylla() + '.') extra_scylla_options = [] remove_scylla_options = [] # If the "--vnodes" option is given, drop the "tablets" experimental # feature (turned on in run.py) so that all tests will be run with the # old vnode-based replication instead of tablets. This option only has # temporary usefulness, and should eventually be removed. if '--vnodes' in sys.argv: sys.argv.remove('--vnodes') remove_scylla_options.append('--enable-tablets=true') # Tablets are now enabled by default on some releases, it is not enough to remove the enable above. extra_scylla_options.append('--enable-tablets=false') if "-h" in sys.argv or "--help" in sys.argv: run.run_pytest(sys.path[0], sys.argv) exit(0) # run_alternator_cmd runs the same as run_scylla_cmd with *additional* # parameters, so in particular both CQL and Alternator will be enabled. # This is useful for us because we need CQL to setup authentication. def run_alternator_cmd(pid, dir): (cmd, env) = run_scylla_cmd(pid, dir) ip = run.pid_to_ip(pid) cmd += [ '--alternator-address', ip, '--alternator-enforce-authorization', '1', '--alternator-write-isolation', 'only_rmw_uses_lwt', '--alternator-streams-time-window-s', '0', '--alternator-timeout-in-ms', '30000', # no longer needed here because it's defined in test/cqlpy/run.py # now that this parameter is used also by CQL's per-row TTL. #'--alternator-ttl-period-in-seconds', '0.5', '--alternator-allow-system-table-write=1', # this is required by test_streams.py test_parent_filtering and test_get_records_with_alternating_tablets_count # setting the value using scylla_config_temporary won't work, because the value is read # at the start and then periodically with `tablet-load-stats-refresh-interval-in-seconds` # interval, which by default is 60 seconds. '--tablet-load-stats-refresh-interval-in-seconds=1', ] if '--https' in sys.argv: run.setup_ssl_certificate(dir) cmd += ['--alternator-https-port', '8043', '--alternator-encryption-options', f'keyfile={dir}/scylla.key', '--alternator-encryption-options', f'certificate={dir}/scylla.crt', ] else: cmd += ['--alternator-port', '8000'] if '--vs' in sys.argv: cmd += ['--vector-store-primary-uri', f'http://{ip}:6080'] cmd += extra_scylla_options for i in remove_scylla_options: cmd.remove(i) # Unfortunately, earlier Scylla versions required different command line # options to run, so for some old versions we need to drop some of the # command line options added above, or add more options. In cqlpy/run.py's # run_precompiled_scylla_cmd we already do this for most Scylla options, # but here we just need to take care of the Alternator-specific options # that we added here and were different in older versions. if 'release' in globals(): version = release.split('~')[0].split('.') major = [int(version[0]), int(version[1])] print(major) if major < [2025,4]: cmd.remove('--alternator-allow-system-table-write=1') return (cmd, env) pid = run.run_with_temporary_dir(run_alternator_cmd) ip = run.pid_to_ip(pid) if '--https' in sys.argv: alternator_url=f"https://{ip}:8043" else: alternator_url=f"http://{ip}:8000" # If the "--vs" option is given, also run the vector store process. # The vector store is run in its own temporary directory, but runs # on the same IP address as Scylla (otherwise, the first of the two # which we will run will not know where to find the second). def run_vector_store_cmd(pid, dir): global ip # same IP as Scylla, see comment above print('Booting Vector Store on ' + ip + ' in ' + dir + '...') with open(f'{dir}/.password', 'w') as f: print('cassandra', file=f) env = { 'VECTOR_STORE_URI': f'{ip}:6080', 'VECTOR_STORE_SCYLLADB_URI': f'{ip}:9042', 'VECTOR_STORE_SCYLLADB_USERNAME': 'cassandra', 'VECTOR_STORE_SCYLLADB_PASSWORD_FILE': f'{dir}/.password', } global vector_store_executable # set by the code below cmd = [ vector_store_executable ] return (cmd, env) if '--vs' in sys.argv: sys.argv.remove('--vs') # Find the vector-store executable. We look for it in the vector-store/ # directory next to the Scylla working directory taking the newest built # executable, but it can also be specified by the user by setting the # VECTOR_STORE environment variable to the path of if os.getenv('SCYLLA'): global vector_store_executable if os.getenv('VECTOR_STORE'): vector_store_executable = os.path.abspath(os.getenv('VECTOR_STORE')) else: vector_store_dir = os.path.join(os.path.dirname(run.source_path), 'vector-store') vector_stores = glob.glob(os.path.join(vector_store_dir, 'target/*/vector-store')) if not vector_stores: print(f"Can't find a compiled Vector Store in {vector_store_dir}.\nPlease build Vector Store or set VECTOR_STORE to the path of a Vector Store executable.") exit(1) vector_store_executable = max(vector_stores, key=os.path.getmtime) if not os.access(vector_store_executable, os.X_OK): print(f"Cannot execute '{vector_store_executable}'.\nPlease set VECTOR_STORE to the path of a Vector Store executable.") exit(1) print(f"Vector Store is: {vector_store_executable}.") run.run_with_temporary_dir(run_vector_store_cmd) # Wait for both CQL and Alternator APIs to become responsive. We obviously # need the Alternator API to test Alternator, but currently we also need # CQL for setting up authentication. def check_alternator(url): try: requests.get(url, verify=False) except requests.ConnectionError: raise run.NotYetUp # Any other exception may indicate a problem, and is passed to the caller. run.wait_for_services(pid, [ lambda: run.check_cql(ip), lambda: check_alternator(alternator_url), ]) # Finally run pytest: success = run.run_pytest(sys.path[0], ['--url', alternator_url] + sys.argv[1:]) run.summary = 'Alternator tests pass' if success else 'Alternator tests failure' exit(0 if success else 1) # Note that the run.cleanup_all() function runs now, just like on any exit # for any reason in this script. It will delete the temporary files and # announce the failure or success of the test (printing run.summary).