mirror of
https://github.com/apple/foundationdb.git
synced 2025-05-14 01:42:37 +08:00
Change to use ArgumentParser, set env to use external client library in Popen, enable logging in all tests
This commit is contained in:
parent
b2c063dd93
commit
68b41392a0
@ -79,16 +79,15 @@ if (NOT WIN32 AND NOT OPEN_FOR_IDE)
|
|||||||
add_fdbclient_test(
|
add_fdbclient_test(
|
||||||
NAME single_process_fdbcli_tests
|
NAME single_process_fdbcli_tests
|
||||||
COMMAND ${CMAKE_SOURCE_DIR}/bindings/python/tests/fdbcli_tests.py
|
COMMAND ${CMAKE_SOURCE_DIR}/bindings/python/tests/fdbcli_tests.py
|
||||||
${CMAKE_BINARY_DIR}/bin/fdbcli
|
${CMAKE_BINARY_DIR}
|
||||||
@CLUSTER_FILE@
|
@CLUSTER_FILE@
|
||||||
1
|
|
||||||
)
|
)
|
||||||
add_fdbclient_test(
|
add_fdbclient_test(
|
||||||
NAME multi_process_fdbcli_tests
|
NAME multi_process_fdbcli_tests
|
||||||
PROCESS_NUMBER 5
|
PROCESS_NUMBER 5
|
||||||
TEST_TIMEOUT 120 # The test can take near to 1 minutes sometime, set timeout to 2 minutes to be safe
|
TEST_TIMEOUT 120 # The test can take near to 1 minutes sometime, set timeout to 2 minutes to be safe
|
||||||
COMMAND ${CMAKE_SOURCE_DIR}/bindings/python/tests/fdbcli_tests.py
|
COMMAND ${CMAKE_SOURCE_DIR}/bindings/python/tests/fdbcli_tests.py
|
||||||
${CMAKE_BINARY_DIR}/bin/fdbcli
|
${CMAKE_BINARY_DIR}
|
||||||
@CLUSTER_FILE@
|
@CLUSTER_FILE@
|
||||||
5
|
5
|
||||||
)
|
)
|
||||||
@ -96,20 +95,19 @@ if (NOT WIN32 AND NOT OPEN_FOR_IDE)
|
|||||||
add_fdbclient_test(
|
add_fdbclient_test(
|
||||||
NAME single_process_external_client_fdbcli_tests
|
NAME single_process_external_client_fdbcli_tests
|
||||||
COMMAND ${CMAKE_SOURCE_DIR}/bindings/python/tests/fdbcli_tests.py
|
COMMAND ${CMAKE_SOURCE_DIR}/bindings/python/tests/fdbcli_tests.py
|
||||||
${CMAKE_BINARY_DIR}/bin/fdbcli
|
${CMAKE_BINARY_DIR}
|
||||||
@CLUSTER_FILE@
|
@CLUSTER_FILE@
|
||||||
1
|
--external-client-library ${CMAKE_BINARY_DIR}/bindings/c/libfdb_c.so
|
||||||
${CMAKE_BINARY_DIR}/bindings/c/libfdb_c.so
|
|
||||||
)
|
)
|
||||||
add_fdbclient_test(
|
add_fdbclient_test(
|
||||||
NAME multi_process_external_client_fdbcli_tests
|
NAME multi_process_external_client_fdbcli_tests
|
||||||
PROCESS_NUMBER 5
|
PROCESS_NUMBER 5
|
||||||
TEST_TIMEOUT 120 # The test can take near to 1 minutes sometime, set timeout to 2 minutes to be safe
|
TEST_TIMEOUT 120 # The test can take near to 1 minutes sometime, set timeout to 2 minutes to be safe
|
||||||
COMMAND ${CMAKE_SOURCE_DIR}/bindings/python/tests/fdbcli_tests.py
|
COMMAND ${CMAKE_SOURCE_DIR}/bindings/python/tests/fdbcli_tests.py
|
||||||
${CMAKE_BINARY_DIR}/bin/fdbcli
|
${CMAKE_BINARY_DIR}
|
||||||
@CLUSTER_FILE@
|
@CLUSTER_FILE@
|
||||||
5
|
5
|
||||||
${CMAKE_BINARY_DIR}/bindings/c/libfdb_c.so
|
--external-client-library ${CMAKE_BINARY_DIR}/bindings/c/libfdb_c.so
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -8,9 +8,10 @@ import functools
|
|||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
|
from argparse import ArgumentParser, RawDescriptionHelpFormatter
|
||||||
|
|
||||||
|
|
||||||
def enable_logging(level=logging.ERROR):
|
def enable_logging(level=logging.DEBUG):
|
||||||
"""Enable logging in the function with the specified logging level
|
"""Enable logging in the function with the specified logging level
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -42,7 +43,7 @@ def run_fdbcli_command(*args):
|
|||||||
string: Console output from fdbcli
|
string: Console output from fdbcli
|
||||||
"""
|
"""
|
||||||
commands = command_template + ["{}".format(' '.join(args))]
|
commands = command_template + ["{}".format(' '.join(args))]
|
||||||
return subprocess.run(commands, stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
|
return subprocess.run(commands, stdout=subprocess.PIPE, env=fdbcli_env).stdout.decode('utf-8').strip()
|
||||||
|
|
||||||
|
|
||||||
def run_fdbcli_command_and_get_error(*args):
|
def run_fdbcli_command_and_get_error(*args):
|
||||||
@ -52,7 +53,7 @@ def run_fdbcli_command_and_get_error(*args):
|
|||||||
string: Stderr output from fdbcli
|
string: Stderr output from fdbcli
|
||||||
"""
|
"""
|
||||||
commands = command_template + ["{}".format(' '.join(args))]
|
commands = command_template + ["{}".format(' '.join(args))]
|
||||||
return subprocess.run(commands, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stderr.decode('utf-8').strip()
|
return subprocess.run(commands, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=fdbcli_env).stderr.decode('utf-8').strip()
|
||||||
|
|
||||||
|
|
||||||
@enable_logging()
|
@enable_logging()
|
||||||
@ -156,7 +157,7 @@ def lockAndUnlock(logger):
|
|||||||
output2 = run_fdbcli_command_and_get_error("lock")
|
output2 = run_fdbcli_command_and_get_error("lock")
|
||||||
assert output2 == 'ERROR: Database is locked (1038)'
|
assert output2 == 'ERROR: Database is locked (1038)'
|
||||||
# unlock the database
|
# unlock the database
|
||||||
process = subprocess.Popen(command_template + ['unlock ' + lock_uid], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
process = subprocess.Popen(command_template + ['unlock ' + lock_uid], stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=fdbcli_env)
|
||||||
line1 = process.stdout.readline()
|
line1 = process.stdout.readline()
|
||||||
# The randome passphrease we need to confirm to proceed the unlocking
|
# The randome passphrease we need to confirm to proceed the unlocking
|
||||||
line2 = process.stdout.readline()
|
line2 = process.stdout.readline()
|
||||||
@ -180,7 +181,7 @@ def kill(logger):
|
|||||||
# This is currently an issue with fdbcli,
|
# This is currently an issue with fdbcli,
|
||||||
# where you need to first run 'kill' to initialize processes' list
|
# where you need to first run 'kill' to initialize processes' list
|
||||||
# and then specify the certain process to kill
|
# and then specify the certain process to kill
|
||||||
process = subprocess.Popen(command_template[:-1], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
process = subprocess.Popen(command_template[:-1], stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=fdbcli_env)
|
||||||
#
|
#
|
||||||
output2, err = process.communicate(input='kill; kill {}\n'.format(address).encode())
|
output2, err = process.communicate(input='kill; kill {}\n'.format(address).encode())
|
||||||
logger.debug(output2)
|
logger.debug(output2)
|
||||||
@ -210,7 +211,7 @@ def suspend(logger):
|
|||||||
assert len(pinfo) == 1
|
assert len(pinfo) == 1
|
||||||
pid = pinfo[0].split(' ')[0]
|
pid = pinfo[0].split(' ')[0]
|
||||||
logger.debug("Pid: {}".format(pid))
|
logger.debug("Pid: {}".format(pid))
|
||||||
process = subprocess.Popen(command_template[:-1], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
process = subprocess.Popen(command_template[:-1], stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=fdbcli_env)
|
||||||
# suspend the process for enough long time
|
# suspend the process for enough long time
|
||||||
output2, err = process.communicate(input='suspend; suspend 3600 {}\n'.format(address).encode())
|
output2, err = process.communicate(input='suspend; suspend 3600 {}\n'.format(address).encode())
|
||||||
# the cluster should be unavailable after the only process being suspended
|
# the cluster should be unavailable after the only process being suspended
|
||||||
@ -295,7 +296,7 @@ def transaction(logger):
|
|||||||
"""
|
"""
|
||||||
err1 = run_fdbcli_command_and_get_error('set', 'key', 'value')
|
err1 = run_fdbcli_command_and_get_error('set', 'key', 'value')
|
||||||
assert err1 == 'ERROR: writemode must be enabled to set or clear keys in the database.'
|
assert err1 == 'ERROR: writemode must be enabled to set or clear keys in the database.'
|
||||||
process = subprocess.Popen(command_template[:-1], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
process = subprocess.Popen(command_template[:-1], stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=fdbcli_env)
|
||||||
transaction_flow = ['writemode on', 'begin', 'getversion', 'set key value', 'get key', 'commit']
|
transaction_flow = ['writemode on', 'begin', 'getversion', 'set key value', 'get key', 'commit']
|
||||||
output1, _ = process.communicate(input='\n'.join(transaction_flow).encode())
|
output1, _ = process.communicate(input='\n'.join(transaction_flow).encode())
|
||||||
# split the output into lines
|
# split the output into lines
|
||||||
@ -314,7 +315,7 @@ def transaction(logger):
|
|||||||
output2 = run_fdbcli_command('get', 'key')
|
output2 = run_fdbcli_command('get', 'key')
|
||||||
assert output2 == "`key' is `value'"
|
assert output2 == "`key' is `value'"
|
||||||
# test rollback and read-your-write behavior
|
# test rollback and read-your-write behavior
|
||||||
process = subprocess.Popen(command_template[:-1], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
process = subprocess.Popen(command_template[:-1], stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=fdbcli_env)
|
||||||
transaction_flow = [
|
transaction_flow = [
|
||||||
'writemode on', 'begin', 'getrange a z',
|
'writemode on', 'begin', 'getrange a z',
|
||||||
'clear key', 'get key',
|
'clear key', 'get key',
|
||||||
@ -331,7 +332,7 @@ def transaction(logger):
|
|||||||
output4 = run_fdbcli_command('get', 'key')
|
output4 = run_fdbcli_command('get', 'key')
|
||||||
assert output4 == "`key' is `value'"
|
assert output4 == "`key' is `value'"
|
||||||
# test read_your_write_disable option and clear the inserted key
|
# test read_your_write_disable option and clear the inserted key
|
||||||
process = subprocess.Popen(command_template[:-1], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
process = subprocess.Popen(command_template[:-1], stdin=subprocess.PIPE, stdout=subprocess.PIPE, env=fdbcli_env)
|
||||||
transaction_flow = [
|
transaction_flow = [
|
||||||
'writemode on', 'begin',
|
'writemode on', 'begin',
|
||||||
'option on READ_YOUR_WRITES_DISABLE',
|
'option on READ_YOUR_WRITES_DISABLE',
|
||||||
@ -354,7 +355,7 @@ def get_fdb_process_addresses(logger):
|
|||||||
logger.debug(output)
|
logger.debug(output)
|
||||||
# except the first line, each line is one process
|
# except the first line, each line is one process
|
||||||
addresses = output.split('\n')[1:]
|
addresses = output.split('\n')[1:]
|
||||||
assert len(addresses) == process_number
|
assert len(addresses) == args.process_number
|
||||||
return addresses
|
return addresses
|
||||||
|
|
||||||
|
|
||||||
@ -450,7 +451,9 @@ def read_system_key(k):
|
|||||||
def throttle(logger):
|
def throttle(logger):
|
||||||
# no throttled tags at the beginning
|
# no throttled tags at the beginning
|
||||||
no_throttle_tags_output = 'There are no throttled tags'
|
no_throttle_tags_output = 'There are no throttled tags'
|
||||||
assert run_fdbcli_command('throttle', 'list') == no_throttle_tags_output
|
output = run_fdbcli_command('throttle', 'list')
|
||||||
|
logger.debug(output)
|
||||||
|
assert output == no_throttle_tags_output
|
||||||
# test 'throttle enable auto'
|
# test 'throttle enable auto'
|
||||||
run_fdbcli_command('throttle', 'enable', 'auto')
|
run_fdbcli_command('throttle', 'enable', 'auto')
|
||||||
# verify the change is applied by reading the system key
|
# verify the change is applied by reading the system key
|
||||||
@ -473,21 +476,34 @@ def wait_for_database_available(logger):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# fdbcli_tests.py <path_to_fdbcli_binary> <path_to_fdb_cluster_file> <process_number> [external_client_library_path]
|
parser = ArgumentParser(formatter_class=RawDescriptionHelpFormatter,
|
||||||
assert len(sys.argv) == 4 or len(
|
description="""
|
||||||
sys.argv) == 5, "Please pass arguments: <path_to_fdbcli_binary> <path_to_fdb_cluster_file> <process_number> [external_client_library_path]"
|
The test calls fdbcli commands through fdbcli --exec "<command>" interactively using subprocess.
|
||||||
# set external client library
|
The outputs from fdbcli are returned and compared to predefined results.
|
||||||
if len(sys.argv) == 5:
|
Consequently, changing fdbcli outputs or breaking any commands will casue the test to fail.
|
||||||
external_client_library_path = sys.argv[4]
|
Commands that are easy to test will run against a single process cluster.
|
||||||
|
For complex commands like exclude, they will run against a cluster with multiple(current set to 5) processes.
|
||||||
|
If external_client_library is given, we will disable the local client and use the external client to run fdbcli.
|
||||||
|
""")
|
||||||
|
parser.add_argument('build_dir', metavar='BUILD_DIRECTORY', help='FDB build directory')
|
||||||
|
parser.add_argument('cluster_file', metavar='CLUSTER_FILE', help='FDB cluster file')
|
||||||
|
parser.add_argument('process_number', nargs='?', metavar='PROCESS_NUMBER', help="Number of fdb processes", type=int, default=1)
|
||||||
|
parser.add_argument('--external-client-library', '-e', metavar='EXTERNAL_CLIENT_LIBRARY_PATH', help="External client library path")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# keep current environment variables
|
||||||
|
fdbcli_env = os.environ.copy()
|
||||||
|
# set external client library if provided
|
||||||
|
if args.external_client_library:
|
||||||
# disable local client and use the external client library
|
# disable local client and use the external client library
|
||||||
os.environ['FDB_NETWORK_OPTION_DISABLE_LOCAL_CLIENT'] = ''
|
fdbcli_env['FDB_NETWORK_OPTION_DISABLE_LOCAL_CLIENT'] = ''
|
||||||
os.environ['FDB_NETWORK_OPTION_EXTERNAL_CLIENT_LIBRARY'] = external_client_library_path
|
fdbcli_env['FDB_NETWORK_OPTION_EXTERNAL_CLIENT_LIBRARY'] = args.external_client_library
|
||||||
|
|
||||||
# shell command template
|
# shell command template
|
||||||
command_template = [sys.argv[1], '-C', sys.argv[2], '--exec']
|
command_template = [args.build_dir + '/bin/fdbcli', '-C', args.cluster_file, '--exec']
|
||||||
# tests for fdbcli commands
|
# tests for fdbcli commands
|
||||||
# assertions will fail if fdbcli does not work as expected
|
# assertions will fail if fdbcli does not work as expected
|
||||||
process_number = int(sys.argv[3])
|
if args.process_number == 1:
|
||||||
if process_number == 1:
|
|
||||||
# TODO: disable for now, the change can cause the database unavailable
|
# TODO: disable for now, the change can cause the database unavailable
|
||||||
# advanceversion()
|
# advanceversion()
|
||||||
cache_range()
|
cache_range()
|
||||||
@ -501,6 +517,6 @@ if __name__ == '__main__':
|
|||||||
transaction()
|
transaction()
|
||||||
throttle()
|
throttle()
|
||||||
else:
|
else:
|
||||||
assert process_number > 1, "Process number should be positive"
|
assert args.process_number > 1, "Process number should be positive"
|
||||||
coordinators()
|
coordinators()
|
||||||
exclude()
|
exclude()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user