tests: Make it possible to run functional tests on Windows
This commit is contained in:
parent
3832c25f17
commit
2148c36b6e
5 changed files with 59 additions and 26 deletions
|
@ -25,10 +25,6 @@ def main():
|
|||
parser.add_argument('--html', dest='html', action='store_true', help='outputs the combined log as html. Requires jinja2. pip install jinja2')
|
||||
args, unknown_args = parser.parse_known_args()
|
||||
|
||||
if args.color and os.name != 'posix':
|
||||
print("Color output requires posix terminal colors.")
|
||||
sys.exit(1)
|
||||
|
||||
if args.html and args.color:
|
||||
print("Only one out of --color or --html should be specified")
|
||||
sys.exit(1)
|
||||
|
|
|
@ -827,7 +827,7 @@ class FullBlockTest(BitcoinTestFramework):
|
|||
tx.vin.append(CTxIn(COutPoint(b64a.vtx[1].sha256, 0)))
|
||||
b64a = self.update_block("64a", [tx])
|
||||
assert_equal(len(b64a.serialize()), MAX_BLOCK_BASE_SIZE + 8)
|
||||
self.sync_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize(): iostream error')
|
||||
self.sync_blocks([b64a], success=False, reject_reason='non-canonical ReadCompactSize():')
|
||||
|
||||
# bitcoind doesn't disconnect us for sending a bloated block, but if we subsequently
|
||||
# resend the header message, it won't send us the getdata message again. Just
|
||||
|
|
|
@ -38,6 +38,7 @@ import decimal
|
|||
import http.client
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import time
|
||||
import urllib.parse
|
||||
|
@ -71,19 +72,12 @@ class AuthServiceProxy():
|
|||
self._service_name = service_name
|
||||
self.ensure_ascii = ensure_ascii # can be toggled on the fly by tests
|
||||
self.__url = urllib.parse.urlparse(service_url)
|
||||
port = 80 if self.__url.port is None else self.__url.port
|
||||
user = None if self.__url.username is None else self.__url.username.encode('utf8')
|
||||
passwd = None if self.__url.password is None else self.__url.password.encode('utf8')
|
||||
authpair = user + b':' + passwd
|
||||
self.__auth_header = b'Basic ' + base64.b64encode(authpair)
|
||||
|
||||
if connection:
|
||||
# Callables re-use the connection of the original proxy
|
||||
self.__conn = connection
|
||||
elif self.__url.scheme == 'https':
|
||||
self.__conn = http.client.HTTPSConnection(self.__url.hostname, port, timeout=timeout)
|
||||
else:
|
||||
self.__conn = http.client.HTTPConnection(self.__url.hostname, port, timeout=timeout)
|
||||
self.timeout = timeout
|
||||
self._set_conn(connection)
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name.startswith('__') and name.endswith('__'):
|
||||
|
@ -102,6 +96,10 @@ class AuthServiceProxy():
|
|||
'User-Agent': USER_AGENT,
|
||||
'Authorization': self.__auth_header,
|
||||
'Content-type': 'application/json'}
|
||||
if os.name == 'nt':
|
||||
# Windows somehow does not like to re-use connections
|
||||
# TODO: Find out why the connection would disconnect occasionally and make it reusable on Windows
|
||||
self._set_conn()
|
||||
try:
|
||||
self.__conn.request(method, path, postdata, headers)
|
||||
return self._get_response()
|
||||
|
@ -178,3 +176,13 @@ class AuthServiceProxy():
|
|||
|
||||
def __truediv__(self, relative_uri):
|
||||
return AuthServiceProxy("{}/{}".format(self.__service_url, relative_uri), self._service_name, connection=self.__conn)
|
||||
|
||||
def _set_conn(self, connection=None):
|
||||
port = 80 if self.__url.port is None else self.__url.port
|
||||
if connection:
|
||||
self.__conn = connection
|
||||
self.timeout = connection.timeout
|
||||
elif self.__url.scheme == 'https':
|
||||
self.__conn = http.client.HTTPSConnection(self.__url.hostname, port, timeout=self.timeout)
|
||||
else:
|
||||
self.__conn = http.client.HTTPConnection(self.__url.hostname, port, timeout=self.timeout)
|
||||
|
|
|
@ -29,7 +29,7 @@ import re
|
|||
import logging
|
||||
|
||||
# Formatting. Default colors to empty strings.
|
||||
BOLD, BLUE, RED, GREY = ("", ""), ("", ""), ("", ""), ("", "")
|
||||
BOLD, GREEN, RED, GREY = ("", ""), ("", ""), ("", ""), ("", "")
|
||||
try:
|
||||
# Make sure python thinks it can write unicode to its stdout
|
||||
"\u2713".encode("utf_8").decode(sys.stdout.encoding)
|
||||
|
@ -41,11 +41,27 @@ except UnicodeDecodeError:
|
|||
CROSS = "x "
|
||||
CIRCLE = "o "
|
||||
|
||||
if os.name == 'posix':
|
||||
if os.name != 'nt' or sys.getwindowsversion() >= (10, 0, 14393):
|
||||
if os.name == 'nt':
|
||||
import ctypes
|
||||
kernel32 = ctypes.windll.kernel32
|
||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
|
||||
STD_OUTPUT_HANDLE = -11
|
||||
STD_ERROR_HANDLE = -12
|
||||
# Enable ascii color control to stdout
|
||||
stdout = kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
|
||||
stdout_mode = ctypes.c_int32()
|
||||
kernel32.GetConsoleMode(stdout, ctypes.byref(stdout_mode))
|
||||
kernel32.SetConsoleMode(stdout, stdout_mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||
# Enable ascii color control to stderr
|
||||
stderr = kernel32.GetStdHandle(STD_ERROR_HANDLE)
|
||||
stderr_mode = ctypes.c_int32()
|
||||
kernel32.GetConsoleMode(stderr, ctypes.byref(stderr_mode))
|
||||
kernel32.SetConsoleMode(stderr, stderr_mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||
# primitive formatting on supported
|
||||
# terminal via ANSI escape sequences:
|
||||
BOLD = ('\033[0m', '\033[1m')
|
||||
BLUE = ('\033[0m', '\033[0;34m')
|
||||
GREEN = ('\033[0m', '\033[0;32m')
|
||||
RED = ('\033[0m', '\033[0;31m')
|
||||
GREY = ('\033[0m', '\033[1;30m')
|
||||
|
||||
|
@ -227,6 +243,11 @@ def main():
|
|||
|
||||
# Create base test directory
|
||||
tmpdir = "%s/test_runner_₿_🏃_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
|
||||
|
||||
# If we fixed the command-line and filename encoding issue on Windows, these two lines could be removed
|
||||
if config["environment"]["EXEEXT"] == ".exe":
|
||||
tmpdir = "%s/test_runner_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
|
||||
|
||||
os.makedirs(tmpdir)
|
||||
|
||||
logging.debug("Temporary test directory at %s" % tmpdir)
|
||||
|
@ -264,7 +285,7 @@ def main():
|
|||
|
||||
# Remove the test cases that the user has explicitly asked to exclude.
|
||||
if args.exclude:
|
||||
exclude_tests = [re.sub("\.py$", "", test) + ".py" for test in args.exclude.split(',')]
|
||||
exclude_tests = [re.sub("\.py$", "", test) + (".py" if ".py" not in test else "") for test in args.exclude.split(',')]
|
||||
for exclude_test in exclude_tests:
|
||||
if exclude_test in test_list:
|
||||
test_list.remove(exclude_test)
|
||||
|
@ -359,7 +380,10 @@ def run_tests(test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=Fal
|
|||
print('\n============')
|
||||
print('{}Combined log for {}:{}'.format(BOLD[1], testdir, BOLD[0]))
|
||||
print('============\n')
|
||||
combined_logs, _ = subprocess.Popen([sys.executable, os.path.join(tests_dir, 'combine_logs.py'), '-c', testdir], universal_newlines=True, stdout=subprocess.PIPE).communicate()
|
||||
combined_logs_args = [sys.executable, os.path.join(tests_dir, 'combine_logs.py'), testdir]
|
||||
if BOLD[0]:
|
||||
combined_logs_args += ['--color']
|
||||
combined_logs, _ = subprocess.Popen(combined_logs_args, universal_newlines=True, stdout=subprocess.PIPE).communicate()
|
||||
print("\n".join(deque(combined_logs.splitlines(), combined_logs_len)))
|
||||
|
||||
if failfast:
|
||||
|
@ -498,7 +522,7 @@ class TestResult():
|
|||
|
||||
def __repr__(self):
|
||||
if self.status == "Passed":
|
||||
color = BLUE
|
||||
color = GREEN
|
||||
glyph = TICK
|
||||
elif self.status == "Failed":
|
||||
color = RED
|
||||
|
|
|
@ -44,8 +44,9 @@ class MultiWalletTest(BitcoinTestFramework):
|
|||
|
||||
# create symlink to verify wallet directory path can be referenced
|
||||
# through symlink
|
||||
os.mkdir(wallet_dir('w7'))
|
||||
os.symlink('w7', wallet_dir('w7_symlink'))
|
||||
if os.name != 'nt':
|
||||
os.mkdir(wallet_dir('w7'))
|
||||
os.symlink('w7', wallet_dir('w7_symlink'))
|
||||
|
||||
# rename wallet.dat to make sure plain wallet file paths (as opposed to
|
||||
# directory paths) can be loaded
|
||||
|
@ -66,6 +67,8 @@ class MultiWalletTest(BitcoinTestFramework):
|
|||
# w8 - to verify existing wallet file is loaded correctly
|
||||
# '' - to verify default wallet file is created correctly
|
||||
wallet_names = ['w1', 'w2', 'w3', 'w', 'sub/w5', os.path.join(self.options.tmpdir, 'extern/w6'), 'w7_symlink', 'w8', '']
|
||||
if os.name == 'nt':
|
||||
wallet_names.remove('w7_symlink')
|
||||
extra_args = ['-wallet={}'.format(n) for n in wallet_names]
|
||||
self.start_node(0, extra_args)
|
||||
assert_equal(set(node.listwallets()), set(wallet_names))
|
||||
|
@ -76,7 +79,7 @@ class MultiWalletTest(BitcoinTestFramework):
|
|||
assert_equal(os.path.isfile(wallet_file(wallet_name)), True)
|
||||
|
||||
# should not initialize if wallet path can't be created
|
||||
exp_stderr = "boost::filesystem::create_directory: (The system cannot find the path specified|Not a directory):"
|
||||
exp_stderr = "boost::filesystem::create_directory:"
|
||||
self.nodes[0].assert_start_raises_init_error(['-wallet=wallet.dat/bad'], exp_stderr, match=ErrorMatch.PARTIAL_REGEX)
|
||||
|
||||
self.nodes[0].assert_start_raises_init_error(['-walletdir=wallets'], 'Error: Specified -walletdir "wallets" does not exist')
|
||||
|
@ -92,8 +95,9 @@ class MultiWalletTest(BitcoinTestFramework):
|
|||
self.nodes[0].assert_start_raises_init_error(['-wallet=w8', '-wallet=w8_copy'], exp_stderr, match=ErrorMatch.PARTIAL_REGEX)
|
||||
|
||||
# should not initialize if wallet file is a symlink
|
||||
os.symlink('w8', wallet_dir('w8_symlink'))
|
||||
self.nodes[0].assert_start_raises_init_error(['-wallet=w8_symlink'], 'Error: Invalid -wallet path \'w8_symlink\'\. .*', match=ErrorMatch.FULL_REGEX)
|
||||
if os.name != 'nt':
|
||||
os.symlink('w8', wallet_dir('w8_symlink'))
|
||||
self.nodes[0].assert_start_raises_init_error(['-wallet=w8_symlink'], 'Error: Invalid -wallet path \'w8_symlink\'\. .*', match=ErrorMatch.FULL_REGEX)
|
||||
|
||||
# should not initialize if the specified walletdir does not exist
|
||||
self.nodes[0].assert_start_raises_init_error(['-walletdir=bad'], 'Error: Specified -walletdir "bad" does not exist')
|
||||
|
@ -220,7 +224,8 @@ class MultiWalletTest(BitcoinTestFramework):
|
|||
assert_raises_rpc_error(-1, "BerkeleyBatch: Can't open database w8_copy (duplicates fileid", self.nodes[0].loadwallet, 'w8_copy')
|
||||
|
||||
# Fail to load if wallet file is a symlink
|
||||
assert_raises_rpc_error(-4, "Wallet file verification failed: Invalid -wallet path 'w8_symlink'", self.nodes[0].loadwallet, 'w8_symlink')
|
||||
if os.name != 'nt':
|
||||
assert_raises_rpc_error(-4, "Wallet file verification failed: Invalid -wallet path 'w8_symlink'", self.nodes[0].loadwallet, 'w8_symlink')
|
||||
|
||||
# Fail to load if a directory is specified that doesn't contain a wallet
|
||||
os.mkdir(wallet_dir('empty_wallet_dir'))
|
||||
|
|
Loading…
Reference in a new issue