Browse Source

Refactor `conftest.py`:

* Uses shlex.split() to avoid unnecessary handling of command lists
* Removes unnecessary globals
* PEP8 fixes
* Uses `yield` instead of `addfinalizer` teardown
* Add docstrings
* Clean up functions
master
PulpCattel 3 years ago
parent
commit
a9deacc010
No known key found for this signature in database
GPG Key ID: BDFD82BA08D9F218
  1. 196
      conftest.py

196
conftest.py

@ -1,51 +1,72 @@
import pytest
import re
import os import os
import time import re
import subprocess import subprocess
from typing import Any from shlex import split
from time import sleep
from typing import Any, Tuple
import pytest
bitcoin_path = None
bitcoin_conf = None
bitcoin_rpcpassword = None
bitcoin_rpcusername = None
miniircd_procs = []
def get_bitcoind_version(version_string: bytes) -> tuple: def get_bitcoind_version(bitcoind_path: str) -> Tuple[int, int]:
# this utility function returns the version number """
# as a tuple in the form (major, minor) This utility function returns the bitcoind version number
as a tuple in the form (major, minor)
"""
version = local_command(f'{bitcoind_path} -version')
if version.returncode != 0:
raise RuntimeError(version.stdout.decode('utf-8'))
version_string = version.stdout.split(b'\n')[0]
version_tuple = re.match( version_tuple = re.match(
br'.*v(?P<major>\d+)\.(?P<minor>\d+)', br'.*v(?P<major>\d+)\.(?P<minor>\d+)', version_string).groups()
version_string).groups() major, minor = map(lambda x: int(x), version_tuple)
return tuple(map(lambda x: int(x), version_tuple)) return major, minor
def local_command(command: str, bg: bool = False): def local_command(command: str, bg: bool = False):
"""
Execute command in a new process.
"""
command = split(command)
if bg: if bg:
#using subprocess.PIPE seems to cause problems # using subprocess.PIPE seems to cause problems
FNULL = open(os.devnull, 'w') FNULL = open(os.devnull, 'w')
return subprocess.Popen(command, return subprocess.Popen(command,
stdout=FNULL, stdout=FNULL,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
close_fds=True) close_fds=True)
else: # in case of foreground execution, we can use the output; if not
#in case of foreground execution, we can use the output; if not # it doesn't matter
#it doesn't matter return subprocess.run(command, stdout=subprocess.PIPE,
return subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stderr=subprocess.STDOUT)
def root_path() -> str: def root_path() -> str:
# returns the directory in which this file is contained """
Returns the directory in which this file is contained.
"""
return os.path.dirname(os.path.realpath(__file__)) return os.path.dirname(os.path.realpath(__file__))
def btc_conf_test_path() -> str:
"""
Returns default Bitcoin conf test path.
"""
return os.path.join(root_path(), 'test/bitcoin.conf')
def pytest_addoption(parser: Any) -> None: def pytest_addoption(parser: Any) -> None:
"""
Pytest initialization hook to register argparse-style options.
"""
parser.addoption("--btcroot", action="store", default='', parser.addoption("--btcroot", action="store", default='',
help="the fully qualified path to the directory containing "+\ help="the fully qualified path to the directory containing " +
"the bitcoin binaries, e.g. /home/user/bitcoin/bin/") "the bitcoin binaries, e.g. /home/user/bitcoin/bin/")
parser.addoption("--btcconf", action="store", parser.addoption("--btcconf", action="store",
default=os.path.join(root_path(), 'test/bitcoin.conf'), default=btc_conf_test_path(),
help="the fully qualified path to the location of the "+\ help="the fully qualified path to the location of the " +
"bitcoin configuration file you use for testing, e.g. "+\ "bitcoin configuration file you use for testing, e.g. " +
"/home/user/.bitcoin/bitcoin.conf") "/home/user/.bitcoin/bitcoin.conf")
parser.addoption("--btcpwd", parser.addoption("--btcpwd",
action="store", action="store",
help="the RPC password for your test bitcoin instance") help="the RPC password for your test bitcoin instance")
@ -54,82 +75,73 @@ def pytest_addoption(parser: Any) -> None:
default='bitcoinrpc', default='bitcoinrpc',
help="the RPC username for your test bitcoin instance (default=bitcoinrpc)") help="the RPC username for your test bitcoin instance (default=bitcoinrpc)")
parser.addoption("--nirc", parser.addoption("--nirc",
type="int", type="int",
action="store", action="store",
default=1, default=1,
help="the number of local miniircd instances") help="the number of local miniircd instances")
def teardown() -> None:
#didn't find a stop command in miniircd, so just kill
global miniircd_procs
for m in miniircd_procs:
m.kill()
#shut down bitcoin and remove the regtest dir
local_command([os.path.join(bitcoin_path, "bitcoin-cli"), "-regtest",
"-rpcuser=" + bitcoin_rpcusername,
"-rpcpassword=" + bitcoin_rpcpassword, "stop"])
#note, it is better to clean out ~/.bitcoin/regtest but too
#dangerous to automate it here perhaps
@pytest.fixture(scope="session", autouse=True) @pytest.fixture(scope="session", autouse=True)
def setup(request) -> None: def setup_miniircd(pytestconfig):
request.addfinalizer(teardown) """
Setup miniircd and handle its clean up.
global bitcoin_conf, bitcoin_path, bitcoin_rpcpassword, bitcoin_rpcusername """
bitcoin_path = request.config.getoption("--btcroot") miniircd_procs = []
bitcoin_conf = request.config.getoption("--btcconf")
print("Here is the bitcoin_conf path:")
print(bitcoin_conf)
bitcoin_rpcpassword = request.config.getoption("--btcpwd")
bitcoin_rpcusername = request.config.getoption("--btcuser")
#start up miniircd
#minor bug in miniircd (seems); need *full* unqualified path for motd file
cwd = os.getcwd() cwd = os.getcwd()
n_irc = request.config.getoption("--nirc") n_irc = pytestconfig.getoption("--nirc")
global miniircd_procs miniircd_path = os.path.join(root_path(), 'miniircd', 'miniircd')
# minor bug in miniircd (seems); need *full* unqualified path for motd file
motd_path = os.path.join(cwd, 'miniircd', 'testmotd')
for i in range(n_irc): for i in range(n_irc):
miniircd_proc = local_command( command = f"{miniircd_path} --ports={16667 + i} --motd={motd_path}"
["./miniircd/miniircd", "--ports=" + str(16667+i), miniircd_proc = local_command(command, bg=True)
"--motd=" + cwd + "/miniircd/testmotd"],
bg=True)
miniircd_procs.append(miniircd_proc) miniircd_procs.append(miniircd_proc)
yield
# didn't find a stop command in miniircd, so just kill
for m in miniircd_procs:
m.kill()
# determine bitcoind version
bitcoind_version_string = subprocess.check_output([
os.path.join(bitcoin_path, "bitcoind"), "-version"]).split(b'\n')[0]
bitcoind_version = get_bitcoind_version(bitcoind_version_string)
#start up regtest blockchain
bitcoin_args = ["-regtest", "-daemon", "-conf=" + bitcoin_conf]
btc_proc = subprocess.call([os.path.join(bitcoin_path, "bitcoind")] + @pytest.fixture(scope="session", autouse=True)
bitcoin_args) def setup_regtest_bitcoind(pytestconfig):
root_cmd = [os.path.join(bitcoin_path, "bitcoin-cli"), "-regtest", """
"-rpcuser=" + bitcoin_rpcusername, Setup regtest bitcoind and handle its clean up.
"-rpcpassword=" + bitcoin_rpcpassword] """
conf = pytestconfig.getoption("--btcconf")
rpcuser = pytestconfig.getoption("--btcuser")
rpcpassword = pytestconfig.getoption("--btcpwd")
bitcoin_path = pytestconfig.getoption("--btcroot")
bitcoind_path = os.path.join(bitcoin_path, "bitcoind")
bitcoincli_path = os.path.join(bitcoin_path, "bitcoin-cli")
start_cmd = f'{bitcoind_path} -regtest -daemon -conf={conf}'
stop_cmd = f'{bitcoincli_path} -regtest -rpcuser={rpcuser} -rpcpassword={rpcpassword} stop'
local_command(start_cmd, bg=True)
# determine bitcoind version
try:
bitcoind_version = get_bitcoind_version(bitcoind_path)
except RuntimeError as exc:
pytest.exit(f"Cannot setup tests, bitcoind failing.\n{exc}")
root_cmd = f'{bitcoincli_path} -regtest -rpcuser={rpcuser} -rpcpassword={rpcpassword}'
wallet_name = 'jm-test-wallet'
# Bitcoin Core v0.21+ does not create default wallet # Bitcoin Core v0.21+ does not create default wallet
# From Bitcoin Core 0.21.0 there is support for descriptor wallets, which # From Bitcoin Core 0.21.0 there is support for descriptor wallets, which
# are default from 23.x+ (including 22.99.0 development versions). # are default from 23.x+ (including 22.99.0 development versions).
# We don't support descriptor wallets yet. # We don't support descriptor wallets yet.
if bitcoind_version[0] >= 22: if bitcoind_version[0] >= 22:
local_command(root_cmd + ["-rpcwait"] + ["-named"] + create_wallet = f'{root_cmd} -rpcwait -named createwallet wallet_name={wallet_name} descriptors=false'
["createwallet",
"wallet_name=jm-test-wallet", "descriptors=false"])
else: else:
local_command(root_cmd + ["-rpcwait"] + create_wallet = f'{root_cmd} -rpcwait createwallet {wallet_name}'
["createwallet", "jm-test-wallet"]) local_command(create_wallet)
local_command(root_cmd + ["loadwallet", "jm-test-wallet"]) local_command(f'{root_cmd} loadwallet {wallet_name}')
for i in range(2): for i in range(2):
cpe = local_command(root_cmd + ["-rpcwallet=jm-test-wallet"] + cpe = local_command(f'{root_cmd} -rpcwallet={wallet_name} getnewaddress')
["getnewaddress"]) if cpe.returncode != 0:
if cpe.returncode == 0: pytest.exit(f"Cannot setup tests, bitcoin-cli failing.\n{cpe.stdout.decode('utf-8')}")
destn_addr = cpe.stdout[:-1].decode('utf-8') destn_addr = cpe.stdout[:-1].decode('utf-8')
local_command(root_cmd + ["-rpcwallet=jm-test-wallet"] + local_command(f'{root_cmd} -rpcwallet={wallet_name} generatetoaddress 301 {destn_addr}')
["generatetoaddress", "301", destn_addr]) sleep(1)
else: yield
pytest.exit("Cannot setup tests, bitcoin-cli failing.\n" + # shut down bitcoind
str(cpe.stdout)) local_command(stop_cmd)
time.sleep(1) # note, it is better to clean out ~/.bitcoin/regtest but too
# dangerous to automate it here perhaps

Loading…
Cancel
Save