zcashd/qa/zcash/smoke_tests.py

744 lines
28 KiB
Python
Executable File

#!/usr/bin/env python3
#
# Execute the standard smoke tests for Zcash releases.
#
# Usage:
#
# ZCASHD=./src/zcashd ZCASHCLI=./src/zcash-cli ./qa/zcash/smoke_tests.py --wallet=wallet.smoketest.dat "$HOME/.zcash"
#
# ZCASHD=./src/zcashd ZCASHCLI=./src/zcash-cli ./qa/zcash/smoke_tests.py --wallet=wallet.smoketest.dat "$HOME/.zcash" --automate --use-faucet
#
import argparse
import datetime
import os
import requests
import subprocess
import sys
import time
import traceback
from decimal import Decimal
from slickrpc import Proxy
from slickrpc.exc import RpcException
DEFAULT_FEE = Decimal('0.00001')
URL_FAUCET_DONATION = 'https://faucet.testnet.z.cash/donations'
URL_FAUCET_TAP = 'https://faucet.testnet.z.cash/'
#
# Smoke test definitions
#
# (case, expected_mainnet, expected_testnet)
SMOKE_TESTS = [
# zcashd start/stop/restart flows
('1a', True, True), # zcashd start
('1b', True, True), # Graceful zcashd stop
('1c', True, True), # Ungraceful zcashd stop
('1d', True, True), # zcashd start; graceful zcashd stop; zcashd start
('1e', True, True), # zcashd start; ungraceful zcashd stop; zcashd start
# Control
('2a', True, True), # Run getinfo
('2b', True, True), # Run help
# Address generation
#('3a', True, True), # Generate a Sprout z-addr
#('3b', True, True), # Generate multiple Sprout z-addrs
('3c', True, True), # Generate a t-addr
('3d', True, True), # Generate multiple t-addrs
('3e', True, True), # Generate a Sapling z-addr
('3f', True, True), # Generate multiple Sapling z-addrs
# Transactions
#('4a', True, True ), # Send funds from Sprout z-addr to same Sprout z-addr
#('4b', True, True ), # Send funds from Sprout z-addr to a different Sprout z-addr
#('4c', True, True ), # Send funds from Sprout z-addr to a t-addr
#('4d', False, False ), # Send funds from t-addr to Sprout z-addr(expected fail as of Canopy)
('4e', True, True ), # Send funds from t-addr to t-addr
('4f', True, True ), # Send funds from t-addr to Sapling z-addr
('4g', True, True ), # Send funds from Sapling z-addr to same Sapling z-addr
('4h', True, True ), # Send funds from Sapling z-addr to a different Sapling z-addr
('4i', True, True ), # Send funds from Sapling z-addr to a t-addr
#('4j', False, False), # Send funds from Sprout z-addr to Sapling z-addr
#('4k', True, True ), # Send funds from Sprout z-addr to multiple Sprout z-addrs
#('4l', True, True ), # Send funds from Sprout z-addr to multiple t-addrs
#('4m', True, True ), # Send funds from Sprout z-addr to t-addr and Sprout z-addrs
#('4n', False, False), # Send funds from Sprout z-addr to t-addr and Sapling z-addr
#('4o', False, False), # Send funds from Sprout z-addr to multiple Sapling z-addrs
('4p', True, True ), # Send funds from t-addr to multiple t-addrs
#('4q', False, False ), # Send funds from t-addr to multiple Sprout z-addrs(expected fail as of Canopy)
('4r', True, True ), # Send funds from t-addr to multiple Sapling z-addrs
#('4s', False, False), # Send funds from t-addr to Sprout z-addr and Sapling z-addr
('4t', True, True ), # Send funds from Sapling z-addr to multiple Sapling z-addrs
#('4u', False, False), # Send funds from Sapling z-addr to multiple Sprout z-addrs
('4v', True, True ), # Send funds from Sapling z-addr to multiple t-addrs
('4w', True, True ), # Send funds from Sapling z-addr to t-addr and Sapling z-addr
#('4x', False, False), # Send funds from Sapling z-addr to Sapling z-addr and Sprout z-addr
#('4y', False, False ), # Send funds from t-addr to Sprout z-addr using z_mergetoaddress(expected fail as of Canopy)
#('4z', False, False ), # Send funds from 2 different t-addrs to Sprout z-addr using z_mergetoaddress(expected fail as of Canopy)
#('4aa', False, False), # Send funds from the same 2 t-addrs to Sprout z-addr using z_mergetoaddress
('4bb', True, True ), # Send funds from 2 different t-addrs to Sapling z-addr using z_mergetoaddress
('4cc', True, True ), # Send funds from t-addr to Sapling z-addr using z_mergetoaddress
#('4dd', False, False ), # Send funds from t-addr and Sprout z-addr to Sprout z-addr using z_mergetoaddress(expected fail as of Canopy)
('4ee', True, True ), # Send funds from t-addr and Sapling z-addr to Sapling z-addr using z_mergetoaddress
#('4ff', True, True ), # Send funds from Sprout z-addr and Sprout z-addr to Sprout z-addr using z_mergetoaddress
('4gg', True, True ), # Send funds from Sapling z-addr and Sapling z-addr to Sapling z-addr using z_mergetoaddress
# Wallet
('5a', True, True), # After generating multiple z-addrs, run z_listaddresses
#('5b', True, True), # Run z_validateaddress with a Sprout z-addr
('5c', True, True), # Run z_validateaddress with a Sapling z-addr
('5d', True, True), # After a transaction, run z_listunspent
('5e', True, True), # After a transaction, run z_listreceivedbyaddress
('5f', True, True), # After a transaction, run z_getbalance
('5g', True, True), # After a transaction, run z_gettotalbalance
('5h', True, True), # Run z_exportkey using a Sprout z-addr
('5i', True, True), # Run z_importkey using the zkey from a Sprout z-addr
('5j', True, True), # Run z_exportkey using a Sapling z-addr
('5k', True, True), # Run z_importkey using the zkey from a Sapling z-addr
('5l', True, True), # Run z_exportwallet
('5m', True, True), # Run z_importwallet
('5n', True, True), # Run z_shieldcoinbase
('5o', True, True), # Run getwalletinfo
# Network
('6a', True, True), # Run getpeerinfo
('6b', True, True), # Run getnetworkinfo
('6c', True, False), # Run getdeprecationinfo
('6d', True, True), # Run getconnectioncount
('6e', True, True), # Run getaddednodeinfo
# Mining
('7a', True, True), # Run getblocksubsidy
('7b', True, True), # Run getblocktemplate
('7c', True, True), # Run getmininginfo
('7d', True, True), # Run getnetworkhashps
('7e', True, True), # Run getnetworksolps
]
TIME_STARTED = datetime.datetime.now()
#
# Test helpers
#
def run_cmd(results, case, zcash, name, args=[]):
print('----- %s -----' % (datetime.datetime.now() - TIME_STARTED))
print('%s $ zcash-cli %s %s' % (
case.ljust(3),
name,
' '.join([str(arg) for arg in args],
)))
try:
res = zcash.__getattr__(name)(*args)
print(res)
print()
if results is not None and len(case) > 0:
results[case] = True
return res
except RpcException as e:
print('ERROR: %s' % str(e))
if results is not None and len(case) > 0:
results[case] = False
return None
def wait_for_balance(zcash, zaddr, expected=None, minconf=1):
if (minconf == 1):
print('Waiting for funds to %s...' % zaddr)
else:
print('Waiting for funds to %s to receive %d confirmations...' % (zaddr, minconf))
unconfirmed_balance = Decimal(zcash.z_getbalance(zaddr, 0)).quantize(Decimal('1.00000000'))
print('Expecting: %s; Unconfirmed Balance: %s' % (expected, unconfirmed_balance))
if expected is not None and unconfirmed_balance != expected:
print('WARNING: Unconfirmed balance does not match expected balance')
# Default timeout is 15 minutes
ttl = 900
while True:
balance = Decimal(zcash.z_getbalance(zaddr, minconf)).quantize(Decimal('1.00000000'))
if (expected is not None and balance == unconfirmed_balance) or (expected is None and balance > 0):
print('Received %s' % balance)
return balance
time.sleep(1)
ttl -= 1
if ttl == 0:
if zcash.automated:
# Reset timeout
ttl = 300
else:
# Ask user if they want to keep waiting
print()
print('Balance: %s Expected: %s' % (balance, expected))
ret = input('Do you wish to continue waiting? (Y/n) ')
if ret.lower() == 'n':
print('Address contained %s at timeout' % balance)
return balance
else:
# Wait another 5 minutes before asking again
ttl = 300
def wait_and_check_balance(results, case, zcash, addr, expected):
#Wait for async call to finish and persist completely to caller
time.sleep(5)
balance = wait_for_balance(zcash, addr, expected)
if balance != expected and results is not None and len(case) > 0:
results[case] = False
return balance
def wait_for_txid_operation(zcash, opid, timeout=300):
print('Waiting for async operation %s' % opid)
result = None
for _ in iter(range(timeout)):
results = zcash.z_getoperationresult([opid])
if len(results) > 0:
result = results[0]
break
time.sleep(1)
status = result['status']
if status == 'failed':
print('Operation failed')
print(result['error']['message'])
return None
elif status == 'success':
txid = result['result']['txid']
print('txid: %s' % txid)
return txid
def async_txid_cmd(results, case, zcash, name, args=[]):
opid = run_cmd(results, case, zcash, name, args)
# Some async commands return a dictionary containing the opid
if isinstance(opid, dict):
opid = opid['opid']
if opid is None:
if results is not None and len(case) > 0:
results[case] = False
return None
txid = wait_for_txid_operation(zcash, opid)
if txid is None:
if results is not None and len(case) > 0:
results[case] = False
return txid
def z_sendmany(results, case, zcash, from_addr, recipients):
return async_txid_cmd(results, case, zcash, 'z_sendmany', [
from_addr,
[{
'address': to_addr,
'amount': amount,
} for (to_addr, amount) in recipients],
1 # minconf
])
def check_z_sendmany(results, case, zcash, from_addr, recipients):
txid = z_sendmany(results, case, zcash, from_addr, recipients)
if txid is None:
return [Decimal('0')]
return [wait_and_check_balance(results, case, zcash, to_addr, amount) for (to_addr, amount) in recipients]
def check_z_sendmany_parallel(results, zcash, runs):
# First attempt to create all the transactions
txids = [(run, z_sendmany(results, run[0], zcash, run[1], run[2])) for run in runs]
# Then wait for balance updates caused by successful transactions
return [
wait_and_check_balance(results, run[0], zcash, to_addr, amount) if txid is not None else Decimal('0')
for (run, txid) in txids
for (to_addr, amount) in run[2]]
def z_mergetoaddress(results, case, zcash, from_addrs, to_addr):
for addr in from_addrs:
balance = Decimal(zcash.z_getbalance(addr, 0)).quantize(Decimal('1.00000000'))
if balance > 0:
wait_for_balance(zcash, addr, balance, minconf=4)
return async_txid_cmd(results, case, zcash, 'z_mergetoaddress', [from_addrs, to_addr])
def check_z_mergetoaddress(results, case, zcash, from_addrs, to_addr, amount):
txid = z_mergetoaddress(results, case, zcash, from_addrs, to_addr)
if txid is None:
return Decimal('0')
return wait_and_check_balance(results, case, zcash, to_addr, amount)
def check_z_mergetoaddress_parallel(results, zcash, runs):
# First attempt to create all the transactions
txids = [(run, z_mergetoaddress(results, run[0], zcash, run[1], run[2])) for run in runs]
# Then wait for balance updates caused by successful transactions
return [
wait_and_check_balance(results, run[0], zcash, run[2], run[3]) if txid is not None else Decimal('0')
for (run, txid) in txids]
def tap_zfaucet(addr):
with requests.Session() as session:
# Get token to request TAZ from faucet with a given zcash address
response = session.get(URL_FAUCET_TAP)
if response.status_code != 200:
print("Error establishing session at:", URL_FAUCET_TAP)
os.sys.exit(1)
csrftoken = response.cookies['csrftoken']
# Request TAZ from the faucet
data_params = dict(csrfmiddlewaretoken=csrftoken, address=addr)
response2 = session.post(URL_FAUCET_TAP, data=data_params, headers=dict(Referer=URL_FAUCET_TAP))
if response2.status_code != 200:
print("Error tapping faucet at:", URL_FAUCET_TAP)
os.sys.exit(1)
def get_zfaucet_addrs():
with requests.Session() as session:
response = session.get(URL_FAUCET_DONATION)
if response.status_code != 200:
print("Error establishing session at:", URL_FAUCET_DONATION)
os.sys.exit(1)
data = response.json()
return data
def get_zfaucet_taddr():
return get_zfaucet_addrs()["t_address"]
def get_zfaucet_zsapaddr():
# At the time of writing this, it appears these(keys) are backwards
return get_zfaucet_addrs()["z_address_legacy"]
def get_zfaucet_zsproutaddr():
# At the time of writing this, it appears these(keys) are backwards
return get_zfaucet_addrs()["z_address_sapling"]
#
# Test runners
#
def simple_commands(zcash):
results = {}
run_cmd(results, '2a', zcash, 'getinfo'),
run_cmd(results, '2b', zcash, 'help'),
run_cmd(results, '5o', zcash, 'getwalletinfo'),
run_cmd(results, '6a', zcash, 'getpeerinfo'),
run_cmd(results, '6b', zcash, 'getnetworkinfo'),
run_cmd(results, '6c', zcash, 'getdeprecationinfo'),
run_cmd(results, '6d', zcash, 'getconnectioncount'),
run_cmd(results, '6e', zcash, 'getaddednodeinfo', [False]),
run_cmd(results, '7a', zcash, 'getblocksubsidy'),
run_cmd(results, '7c', zcash, 'getmininginfo'),
run_cmd(results, '7d', zcash, 'getnetworkhashps'),
run_cmd(results, '7e', zcash, 'getnetworksolps'),
return results
def transaction_chain(zcash):
results = {}
# Generate the various addresses we will use
taddr_1 = run_cmd(results, '3c', zcash, 'getnewaddress')
taddr_2 = run_cmd(results, '3d', zcash, 'getnewaddress')
taddr_3 = run_cmd(results, '3d', zcash, 'getnewaddress')
taddr_4 = run_cmd(results, '3d', zcash, 'getnewaddress')
taddr_5 = run_cmd(results, '3d', zcash, 'getnewaddress')
sapling_zaddr_1 = run_cmd(results, '3e', zcash, 'z_getnewaddress', ['sapling'])
sapling_zaddr_2 = run_cmd(results, '3f', zcash, 'z_getnewaddress', ['sapling'])
sapling_zaddr_3 = run_cmd(results, '3f', zcash, 'z_getnewaddress', ['sapling'])
# Check that the zaddrs are all listed
zaddrs = run_cmd(results, '5a', zcash, 'z_listaddresses')
if ( sapling_zaddr_1 not in zaddrs or
sapling_zaddr_2 not in zaddrs):
results['5a'] = False
# Validate the addresses
ret = run_cmd(results, '5c', zcash, 'z_validateaddress', [sapling_zaddr_1])
if not ret['isvalid'] or ret['type'] != 'sapling':
results['5c'] = False
# Set up beginning and end of the chain
print('#')
print('# Initialising transaction chain')
print('#')
print()
if zcash.use_faucet:
print('Tapping the testnet faucet for testing funds...')
chain_end = get_zfaucet_taddr()
tap_zfaucet(taddr_1)
print('Done! Leftover funds will be sent back to the faucet.')
else:
chain_end = input('Type or paste transparent address where leftover funds should be sent: ')
if not zcash.validateaddress(chain_end)['isvalid']:
print('Invalid transparent address')
return results
print()
print('Please send at least 0.01 ZEC/TAZ to the following address:')
print(taddr_1)
print()
input('Press Enter once the funds have been sent.')
print()
# Wait to receive starting balance
taddr_balance = wait_for_balance(zcash, taddr_1)
starting_balance = taddr_balance
#
# Start the transaction chain!
#
print()
print('#')
print('# Starting transaction chain')
print('#')
print()
try:
# taddr -> Sapling
# Send it all here because z_sendmany pick a new t-addr for change
sapling_balance = check_z_sendmany(
results, '4f', zcash, taddr_1, [(sapling_zaddr_1, taddr_balance - DEFAULT_FEE)])[0]
taddr_balance = Decimal('0')
# Sapling -> taddr
taddr_balance = check_z_sendmany(
results, '4i', zcash, sapling_zaddr_1, [(taddr_1, (starting_balance / Decimal('10')) * Decimal('3'))])[0]
sapling_balance -= taddr_balance + DEFAULT_FEE
#
# Intra-pool tests
#
# Sapling -> same Sapling
sapling_balance = check_z_sendmany(
results, '4g',zcash, sapling_zaddr_1, [(sapling_zaddr_1, sapling_balance - DEFAULT_FEE)])[0]
# taddr -> different taddr
# Sapling -> different Sapling
(taddr_balance, sapling_balance) = check_z_sendmany_parallel(results, zcash, [
('4e', taddr_1, [(taddr_2, taddr_balance - DEFAULT_FEE)]),
('4h', sapling_zaddr_1, [(sapling_zaddr_2, sapling_balance - DEFAULT_FEE)]),
])
# taddr -> multiple taddr
# Sapling -> multiple Sapling
check_z_sendmany_parallel(results, zcash, [
('4p', taddr_2, [
(taddr_1, starting_balance / Decimal('10')),
(taddr_3, taddr_balance - (starting_balance / Decimal('10')) - DEFAULT_FEE),
]),
('4t', sapling_zaddr_2, [
(sapling_zaddr_1, starting_balance / Decimal('10')),
(sapling_zaddr_3, starting_balance / Decimal('10')),
]),
])
taddr_balance -= DEFAULT_FEE
sapling_balance -= DEFAULT_FEE
# multiple Sapling -> Sapling
# multiple taddr -> taddr
check_z_mergetoaddress_parallel(results, zcash, [
('4gg', [sapling_zaddr_1, sapling_zaddr_3], sapling_zaddr_2, sapling_balance - DEFAULT_FEE),
('', [taddr_1, taddr_3], taddr_2, taddr_balance - DEFAULT_FEE),
])
sapling_balance -= DEFAULT_FEE
taddr_balance -= DEFAULT_FEE
taddr_2_balance = taddr_balance
#
# Inter-pool tests
#
# Sapling -> taddr and Sapling
check_z_sendmany(
results, '4w', zcash, sapling_zaddr_2,[
(taddr_3, starting_balance / Decimal('10')),
(sapling_zaddr_1, starting_balance / Decimal('10'))])[0]
sapling_balance -= (starting_balance / Decimal('10')) + DEFAULT_FEE
taddr_balance += starting_balance / Decimal('10')
# taddr and Sapling -> Sapling
check_z_mergetoaddress(results, '4ee', zcash, [taddr_3, sapling_zaddr_1], sapling_zaddr_2, sapling_balance + (starting_balance / Decimal('10')) - DEFAULT_FEE)
sapling_balance += (starting_balance / Decimal('10')) - DEFAULT_FEE
taddr_balance -= starting_balance / Decimal('10')
# Sapling -> multiple taddr
check_z_sendmany(results, '4v', zcash, sapling_zaddr_2, [
(taddr_4, (starting_balance / Decimal('10'))),
(taddr_5, (starting_balance / Decimal('10')))])[0]
sapling_balance -= ((starting_balance / Decimal('10')) * Decimal('2')) + DEFAULT_FEE
taddr_balance += (starting_balance / Decimal('10')) * Decimal('2')
# multiple taddr -> Sapling
check_z_mergetoaddress(results, '4bb',zcash, [taddr_4, taddr_5], sapling_zaddr_2, sapling_balance + ((starting_balance / Decimal('10')) * Decimal('2')) - DEFAULT_FEE)
sapling_balance += ((starting_balance / Decimal('10')) * Decimal('2')) - DEFAULT_FEE
taddr_balance -= (starting_balance / Decimal('10')) * Decimal('2')
# multiple Sapling -> taddr
check_z_mergetoaddress(None, '', zcash, [sapling_zaddr_1, sapling_zaddr_2, sapling_zaddr_3], taddr_2, taddr_2_balance + sapling_balance - DEFAULT_FEE)
taddr_balance += sapling_balance - DEFAULT_FEE
sapling_balance = Decimal('0')
# taddr -> multiple Sapling
taddr_2_balance = Decimal(zcash.z_getbalance(taddr_2)).quantize(Decimal('1.00000000'))
check_z_sendmany(results, '4r', zcash, taddr_2, [
(sapling_zaddr_1, (starting_balance / Decimal('10'))),
(sapling_zaddr_2, taddr_2_balance - (starting_balance / Decimal('10')) - DEFAULT_FEE)])[0]
sapling_balance = taddr_2_balance - DEFAULT_FEE
taddr_balance -= taddr_2_balance
# multiple Sapling -> taddr
check_z_mergetoaddress(None, '', zcash, [sapling_zaddr_1, sapling_zaddr_2], taddr_2, sapling_balance - DEFAULT_FEE)
taddr_balance += sapling_balance - DEFAULT_FEE
sapling_balance = Decimal('0')
# z_mergetoaddress taddr -> Sapling
taddr_2_balance = Decimal(zcash.z_getbalance(taddr_2)).quantize(Decimal('1.00000000'))
check_z_mergetoaddress(results, '4cc', zcash, [taddr_2], sapling_zaddr_1, taddr_2_balance - DEFAULT_FEE)
sapling_balance = taddr_2_balance - DEFAULT_FEE
taddr_balance -= taddr_2_balance
except Exception as e:
print('Error: %s' % e)
traceback.print_exc()
finally:
#
# End the chain by returning the remaining funds
#
print()
print('#')
print('# Finishing transaction chain')
print('#')
all_addrs = [
taddr_1, taddr_2, taddr_3, taddr_4, taddr_5,
sapling_zaddr_1, sapling_zaddr_2, sapling_zaddr_3,
]
print()
print('Waiting for all transactions to be mined')
for addr in all_addrs:
balance = Decimal(zcash.z_getbalance(addr, 0)).quantize(Decimal('1.00000000'))
if balance > 0:
wait_for_balance(zcash, addr, balance)
print()
print('Returning remaining balance minus fees')
for addr in all_addrs:
balance = Decimal(zcash.z_getbalance(addr)).quantize(Decimal('1.00000000'))
if balance > 0:
z_sendmany(None, '', zcash, addr, [(chain_end, balance - DEFAULT_FEE)])
return results
#
# Test stages
#
STAGES = [
'simple-commands',
'transaction-chain'
]
STAGE_COMMANDS = {
'simple-commands': simple_commands,
'transaction-chain': transaction_chain,
}
def run_stage(stage, zcash):
print('Running stage %s' % stage)
print('=' * (len(stage) + 14))
print()
cmd = STAGE_COMMANDS[stage]
if cmd is not None:
ret = cmd(zcash)
else:
print('WARNING: stage not yet implemented, skipping')
ret = {}
print()
print('-' * (len(stage) + 15))
print('Finished stage %s' % stage)
print()
return ret
#
# Zcash wrapper
#
class ZcashNode(object):
def __init__(self, args, zcashd=None, zcash_cli=None):
if zcashd is None:
zcashd = os.getenv('ZCASHD', 'zcashd')
if zcash_cli is None:
zcash_cli = os.getenv('ZCASHCLI', 'zcash-cli')
self.__datadir = args.datadir
self.__wallet = args.wallet
self.__testnet = not args.mainnet
self.__zcashd = zcashd
self.__zcash_cli = zcash_cli
self.__process = None
self.__proxy = None
self.automated = args.automate
self.use_faucet = args.faucet
def start(self, extra_args=None, timewait=None):
if self.__proxy is not None:
raise RuntimeError('Already started')
rpcuser = 'st'
rpcpassword = 'st'
args = [
self.__zcashd,
'-datadir=%s' % self.__datadir,
'-wallet=%s' % self.__wallet,
'-rpcuser=%s' % rpcuser,
'-rpcpassword=%s' % rpcpassword,
'-showmetrics=0',
'-experimentalfeatures',
'-zmergetoaddress',
'-walletrequirebackup=false'
]
if self.__testnet:
args.append('-testnet=1')
if extra_args is not None:
args.extend(extra_args)
self.__process = subprocess.Popen(args)
cli_args = [
self.__zcash_cli,
'-datadir=%s' % self.__datadir,
'-rpcuser=%s' % rpcuser,
'-rpcpassword=%s' % rpcpassword,
'-rpcwait',
]
if self.__testnet:
cli_args.append('-testnet=1')
cli_args.append('getblockcount')
devnull = open('/dev/null', 'w+', encoding='utf8')
if os.getenv('PYTHON_DEBUG', ''):
print('start_node: zcashd started, calling zcash-cli -rpcwait getblockcount')
subprocess.check_call(cli_args, stdout=devnull)
if os.getenv('PYTHON_DEBUG', ''):
print('start_node: calling zcash-cli -rpcwait getblockcount returned')
devnull.close()
rpcuserpass = '%s:%s' % (rpcuser, rpcpassword)
rpchost = '127.0.0.1'
rpcport = 18232 if self.__testnet else 8232
url = 'http://%s@%s:%d' % (rpcuserpass, rpchost, rpcport)
if timewait is not None:
self.__proxy = Proxy(url, timeout=timewait)
else:
self.__proxy = Proxy(url)
def stop(self):
if self.__proxy is None:
raise RuntimeError('Not running')
self.__proxy.stop()
self.__process.wait()
self.__proxy = None
self.__process = None
def __getattr__(self, name):
if self.__proxy is None:
raise RuntimeError('Not running')
return self.__proxy.__getattr__(name)
#
# Test driver
#
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--automate', action='store_true', help='Run the smoke tests without a user present')
parser.add_argument('--list-stages', dest='list', action='store_true')
parser.add_argument('--mainnet', action='store_true', help='Use mainnet instead of testnet')
parser.add_argument('--use-faucet', dest='faucet', action='store_true', help='Use testnet faucet as source of funds')
parser.add_argument('--wallet', default='wallet.dat', help='Wallet file to use (within data directory)')
parser.add_argument('datadir', help='Data directory to use for smoke testing', default=None)
parser.add_argument('stage', nargs='*', default=STAGES, help='One of %s' % STAGES)
args = parser.parse_args()
# Check for list
if args.list:
for s in STAGES:
print(s)
sys.exit(0)
# Check validity of stages
for s in args.stage:
if s not in STAGES:
print("Invalid stage '%s' (choose from %s)" % (s, STAGES))
sys.exit(1)
# Don't allow using the default wallet.dat in mainnet mode
if args.mainnet and args.wallet == 'wallet.dat':
print('Cannot use wallet.dat as wallet file when running mainnet tests. Keep your funds safe!')
sys.exit(1)
# Testnet faucet cannot be used in mainnet mode
if args.mainnet and args.faucet:
print('Cannot use testnet faucet when running mainnet tests.')
sys.exit(1)
# Enforce correctly-configured automatic mode
if args.automate:
if args.mainnet:
print('Cannot yet automate mainnet tests.')
sys.exit(1)
if not args.faucet:
print('--automate requires --use-faucet')
sys.exit(1)
# Start zcashd
zcash = ZcashNode(args)
print('Start time: %s' % TIME_STARTED)
print('Starting zcashd...')
zcash.start()
print()
# Run the stages
results = {}
for s in args.stage:
results.update(run_stage(s, zcash))
# Stop zcashd
print('Stopping zcashd...')
zcash.stop()
passed = True
print()
print('========================')
print(' Results')
print('========================')
print('Case | Expected | Actual')
print('========================')
for test_case in SMOKE_TESTS:
case = test_case[0]
expected = test_case[1 if args.mainnet else 2]
if case in results:
actual = results[case]
actual_str = '%s%s' % (
'Passed' if actual else 'Failed',
'' if expected == actual else '!!!'
)
passed &= (expected == actual)
else:
actual_str = ' N/A'
print('%s | %s | %s' % (
case.ljust(4),
' Passed ' if expected else ' Failed ',
actual_str
))
if not passed:
print()
print("!!! One or more smoke test stages failed !!!")
sys.exit(1)
if __name__ == '__main__':
main()