Skip to content

Commit

Permalink
test: use pytest-xdist for parallel testing
Browse files Browse the repository at this point in the history
  • Loading branch information
darwintree committed Nov 15, 2024
1 parent ef3bd89 commit d70b69e
Show file tree
Hide file tree
Showing 22 changed files with 331 additions and 253 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
export USE_TESTNET=1 &&
export ENS_ACCOUNT_NAME=${{secrets.ENS_ACCOUNT_NAME}} &&
export ENS_ACCOUNT_SECRET=${{secrets.ENS_ACCOUNT_SECRET}} &&
pytest --cov tests
pytest --cov tests -n logical --dist loadgroup
- name: Upload coverage reports to Codecov
run: |
curl -Os https://uploader.codecov.io/latest/linux/codecov
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/local-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ jobs:
pip install ".[tester]"
- name: Run test
run: |
pytest tests
pytest tests -n logical --dist loadgroup
2 changes: 1 addition & 1 deletion .github/workflows/testnet-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ jobs:
export ENS_ACCOUNT_NAME=${{secrets.ENS_ACCOUNT_NAME}} &&
export ENS_ACCOUNT_SECRET=${{secrets.ENS_ACCOUNT_SECRET}} &&
export TEST_FINALIZATION=1 &&
pytest tests
pytest tests -n logical --dist loadgroup
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

typeCheckingMode = "strict"
exclude=["build/*"]
venv="venv"
venv="sdk-313"
reportUnknownMemberType = "information"
reportUnknownVariableType = "warning"
reportUnknownArgumentType = "information"
Expand All @@ -14,3 +14,4 @@ reportIncompatibleVariableOverride = "information"
reportMissingTypeStubs = "information"
reportPrivateImportUsage = "information"
reportPrivateUsage = "information"
reportUntypedFunctionDecorator = "information"
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
'tester': [
"docker>=7.1.0,<8",
"pytest>=8,<9",
"pytest-xdist>=3,<4",
"typing_extensions",
"pytest-cov",
"ipfshttpclient==0.8.0a2",
Expand Down
1 change: 0 additions & 1 deletion tests/base_features/test_default_account.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from conflux_web3 import Web3
from web3.datastructures import AttributeDict

def test_default_account_set(w3: Web3, secret_key):
local_account = w3.account.from_key(secret_key)
Expand Down
9 changes: 7 additions & 2 deletions tests/cns/test_cns.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def test_cns_from_address(use_testnet: bool, ens_name: str, ens_account: LocalAc
w3 = Web3(provider, cns=cns)
assert w3.cns.address(ens_name) == ens_account.address



def test_cns_with_rpc(w3: Web3, use_testnet: bool, ens_name: str):
if use_testnet:
Expand All @@ -39,7 +39,8 @@ def test_cns_with_rpc(w3: Web3, use_testnet: bool, ens_name: str):
else:
with pytest.raises(NameServiceNotSet):
balance = w3.cfx.get_balance("hello45678oiuytrrtyuiytredcv.web3")


@pytest.mark.xdist_group(name="account")
def test_cns_usage_as_contract_param(w3: Web3, to_test_cns_write_api: bool, account: LocalAccount, ens_name: str):
if to_test_cns_write_api:
w3.cfx.default_account = account
Expand All @@ -50,6 +51,7 @@ def test_cns_usage_as_contract_param(w3: Web3, to_test_cns_write_api: bool, acco
assert erc20.functions.transfer(ens_name, 100).transact().executed()
assert erc20.caller.balanceOf(ens_name) == 100

@pytest.mark.xdist_group(name="account")
def test_cns_as_sender(w3: Web3, to_test_cns_write_api: bool, ens_account: LocalAccount, ens_name: bool):
if to_test_cns_write_api:
w3.wallet.add_account(ens_account)
Expand All @@ -59,6 +61,7 @@ def test_cns_as_sender(w3: Web3, to_test_cns_write_api: bool, ens_account: Local
"from": ens_name
}).executed()

@pytest.mark.xdist_group(name="account")
def test_cns_as_contract_address(w3: Web3, to_test_cns_write_api: bool):
if to_test_cns_write_api:
faucet = w3.cfx.contract("faucet.web3", name="Faucet", with_deployment_info=False)
Expand All @@ -81,6 +84,7 @@ def test_cns_owner(w3: Web3, use_testnet: bool, ens_name: str):
# w3.cfx.default_account = account
# w3.cns.setup_owner("test.web3", wrapped=True)

@pytest.mark.xdist_group(name="account")
def test_setup_address(w3: Web3, to_test_cns_write_api: bool, ens_account: LocalAccount):
if to_test_cns_write_api:
w3.cns.allow_unstable_api = True
Expand All @@ -99,6 +103,7 @@ def test_cns_wallet(w3: Web3, use_testnet: bool):
if use_testnet:
assert w3.wallet is w3.cns.w3.wallet

@pytest.mark.xdist_group(name="account")
def test_cns_default_account(w3: Web3, use_testnet: bool, account: LocalAccount):
if use_testnet:
w3.cfx.default_account = account
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def w3(node_url: str, node: LocalNode) -> Web3:
return w3

@pytest.fixture(scope="session")
def account(node_url: str, secret_key) -> LocalAccount:
def account(node_url: str, secret_key: str) -> LocalAccount:
"""external_account, not supported by node
"""
provider = Web3.HTTPProvider(node_url)
Expand Down
55 changes: 28 additions & 27 deletions tests/middleware/test_pending.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,33 @@
if TYPE_CHECKING:
from conflux_web3 import Web3

def test_pending(w3: "Web3", account: LocalAccount, use_testnet: bool):
# activate by default
# w3.middleware_onion.add(PendingTransactionMiddleware)
# @pytest.mark.xdist_group(name="account")
# def test_pending(w3: "Web3", account: LocalAccount, use_testnet: bool):
# # activate by default
# # w3.middleware_onion.add(PendingTransactionMiddleware)

status = w3.cfx.get_status()
addr = account.address
# status = w3.cfx.get_status()
# addr = account.address

tx = {
'from': addr,
'nonce': w3.cfx.get_next_nonce(addr),
'gas': 21000,
'to': w3.cfx.account.create().address,
'value': 100,
'maxFeePerGas': 2 * w3.cfx.gas_price,
'maxPriorityFeePerGas': 0,
'chainId': w3.cfx.chain_id,
'storageLimit': 0,
'epochHeight': status['epochNumber']
}
signed = account.sign_transaction(tx)
rawTx = signed.raw_transaction
pending = w3.cfx.send_raw_transaction(rawTx)
# hash = cast(PendingTransaction, hash)
pending.mined()
pending.executed()
pending.confirmed()
if use_testnet and os.environ.get("TEST_FINALIZATION", None):
with pytest.warns(UserWarning):
pending.finalized()
# tx = {
# 'from': addr,
# 'nonce': w3.cfx.get_next_nonce(addr),
# 'gas': 21000,
# 'to': w3.cfx.account.create().address,
# 'value': 100,
# 'maxFeePerGas': 2 * w3.cfx.gas_price,
# 'maxPriorityFeePerGas': 0,
# 'chainId': w3.cfx.chain_id,
# 'storageLimit': 0,
# 'epochHeight': status['epochNumber']
# }
# signed = account.sign_transaction(tx)
# rawTx = signed.raw_transaction
# pending = w3.cfx.send_raw_transaction(rawTx)
# # hash = cast(PendingTransaction, hash)
# pending.mined()
# pending.executed()
# pending.confirmed()
# if use_testnet and os.environ.get("TEST_FINALIZATION", None):
# with pytest.warns(UserWarning):
# pending.finalized()
9 changes: 7 additions & 2 deletions tests/middleware/test_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
construct_sign_and_send_raw_middleware
)


@pytest.mark.xdist_group(name="account")
def test_wallet_middleware_single_init(w3:Web3, account: LocalAccount):
wallet = construct_sign_and_send_raw_middleware(account, w3.cfx.chain_id)
w3.middleware_onion.add(wallet)
Expand All @@ -28,6 +28,7 @@ def test_wallet_middleware_single_init(w3:Web3, account: LocalAccount):
assert hash
w3.cfx.wait_for_transaction_receipt(hash)

@pytest.mark.xdist_group(name="account")
def test_no_chain_id_wallet_middleware_single_init(w3:Web3, account: LocalAccount):
wallet = construct_sign_and_send_raw_middleware(account)
w3.middleware_onion.add(wallet)
Expand All @@ -46,6 +47,7 @@ def test_no_chain_id_wallet_middleware_single_init(w3:Web3, account: LocalAccoun
assert hash
w3.cfx.wait_for_transaction_receipt(hash)

@pytest.mark.xdist_group(name="account")
def test_wallet_middleware_list_init(w3:Web3, account: LocalAccount):
wallet = Wallet([account], w3.cfx.chain_id)
w3.middleware_onion.add(wallet)
Expand All @@ -64,6 +66,7 @@ def test_wallet_middleware_list_init(w3:Web3, account: LocalAccount):
assert hash
w3.cfx.wait_for_transaction_receipt(hash)

@pytest.mark.xdist_group(name="account")
def test_wallet_middleware_adding(w3: Web3, account: LocalAccount):
wallet = Wallet(forced_chain_id=w3.cfx.chain_id)
wallet.add_accounts([account])
Expand All @@ -83,6 +86,7 @@ def test_wallet_middleware_adding(w3: Web3, account: LocalAccount):
assert hash
w3.cfx.wait_for_transaction_receipt(hash)

@pytest.mark.xdist_group(name="account")
def test_default_wallet_middleware_adding(w3: Web3, account: LocalAccount):
w3.wallet.add_accounts([account])
tx = {
Expand Down Expand Up @@ -154,7 +158,7 @@ def test_wallet_pop():
assert wallet.pop(account.address).address == account.address
assert account.address not in wallet


@pytest.mark.xdist_group(name="account")
def test_wallet_middleware_sign_1559_transaction(w3:Web3, account: LocalAccount):
wallet = construct_sign_and_send_raw_middleware(account, w3.cfx.chain_id)
w3.middleware_onion.add(wallet)
Expand All @@ -174,6 +178,7 @@ def test_wallet_middleware_sign_1559_transaction(w3:Web3, account: LocalAccount)
assert tx_data['type'] == 2
hash.executed()

@pytest.mark.xdist_group(name="account")
def test_wallet_middleware_sign_legacy_transaction(w3:Web3, account: LocalAccount):
wallet = construct_sign_and_send_raw_middleware(account, w3.cfx.chain_id)
w3.middleware_onion.add(wallet)
Expand Down
1 change: 1 addition & 0 deletions tests/rpcs/cfx/filter/test_log_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def contract(self, moduled_w3: Web3):
assert contract_address is not None
return w3.cfx.contract(contract_address, name="ERC20")

@pytest.mark.xdist_group(name="account")
def test_log_filter(self, moduled_w3: Web3, contract: ConfluxContract):
log_filter_id = moduled_w3.cfx.new_filter(address = contract.address)
contract.functions.transfer(contract.address, 1**18).transact().executed()
Expand Down
2 changes: 2 additions & 0 deletions tests/rpcs/cfx/filter/test_pending_tx_filter.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import pytest
from conflux_web3 import Web3
from conflux_web3.types import Drip
from tests._test_helpers.type_check import TypeValidator

class TestPendingTxFilter:
@pytest.mark.xdist_group(name="account")
def test_pending_tx_filter(self, moduled_w3: Web3):
pending_tx_filter_id = moduled_w3.cfx.new_pending_transaction_filter()
constucted_pending_tx = moduled_w3.cfx.send_transaction({
Expand Down
17 changes: 14 additions & 3 deletions tests/rpcs/cfx/test_cfx_account_query_rpcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from tests._test_helpers.type_check import TypeValidator

class TestAccountQuery:
@pytest.mark.xdist_group(name="account")
def test_get_balance(self, w3: Web3, address: Base32Address):
balance = w3.cfx.get_balance(address, w3.cfx.epoch_number-5)
# the balance is supposed to be non-zero
Expand All @@ -18,12 +19,14 @@ def test_get_balance(self, w3: Web3, address: Base32Address):
# with pytest.raises(TypeError):
# w3.cfx.get_balance()

@pytest.mark.xdist_group(name="account")
def test_get_staking_balance(self, w3: Web3, address: Base32Address):
staking_balance = w3.cfx.get_staking_balance(address, w3.cfx.epoch_number-5)
assert staking_balance >= 0
assert isinstance(staking_balance, Drip)
# TODO: use staking balance contract


@pytest.mark.xdist_group(name="account")
def test_get_code(self, w3: Web3, contract_address: Base32Address):
# test different cases
# contract address / user address
Expand All @@ -33,6 +36,7 @@ def test_get_code(self, w3: Web3, contract_address: Base32Address):
user_code = w3.cfx.get_code(w3.cfx.account.create().address)
assert user_code == HexBytes("0x")

@pytest.mark.xdist_group(name="account")
def test_get_admin(self, w3: Web3, contract_address: Base32Address):
# test different cases
# contract address / user address
Expand All @@ -43,6 +47,7 @@ def test_get_admin(self, w3: Web3, contract_address: Base32Address):
user_admin = w3.cfx.get_admin(random_contract_address)
assert user_admin is None

@pytest.mark.xdist_group(name="account")
def test_get_storage_at(self, w3: Web3, contract_address: Base32Address, use_testnet: bool):
# TODO: a potential bug in RPC, at present we ignore the testing in local node
if use_testnet:
Expand All @@ -51,33 +56,39 @@ def test_get_storage_at(self, w3: Web3, contract_address: Base32Address, use_tes
else:
pass

@pytest.mark.xdist_group(name="account")
def test_get_storage_root(self, w3: Web3, contract_address: Base32Address):
root = w3.cfx.get_storage_root(contract_address, w3.cfx.epoch_number_by_tag("latest_state"))
TypeValidator.validate_typed_dict(root, "StorageRoot")

# TODO: check RPC work pattern
# root = w3.cfx.get_storage_root(w3.account.create().address)
# assert not root


@pytest.mark.xdist_group(name="account")
def test_get_collateral_for_storage(self, w3: Web3, address: Base32Address):
storage = w3.cfx.get_collateral_for_storage(address, w3.cfx.epoch_number_by_tag("latest_state"))

assert isinstance(storage, int)

@pytest.mark.xdist_group(name="account")
def test_get_sponsor_info(self, w3: Web3, contract_address: Base32Address):
sponsor_info = w3.cfx.get_sponsor_info(contract_address, w3.cfx.epoch_number_by_tag("latest_state"))
# assert sponsor_info
TypeValidator.validate_typed_dict(sponsor_info, "SponsorInfo")


@pytest.mark.xdist_group(name="account")
def test_get_account(self, w3: Web3, address: Base32Address):
account_info = w3.cfx.get_account(address, w3.cfx.epoch_number_by_tag("latest_state"))
TypeValidator.validate_typed_dict(account_info, "AccountInfo")

@pytest.mark.xdist_group(name="account")
def test_get_deposit_list(self, w3:Web3, address: Base32Address):
deposit_list = w3.cfx.get_deposit_list(address)
for deposit_info in deposit_list:
TypeValidator.validate_typed_dict(deposit_info, "DepositInfo")

@pytest.mark.xdist_group(name="account")
def test_get_vote_list(self, w3:Web3, address: Base32Address):
vote_list = w3.cfx.get_vote_list(address, w3.cfx.epoch_number_by_tag("latest_state"))
for vote_info in vote_list:
Expand Down
16 changes: 12 additions & 4 deletions tests/rpcs/cfx/test_cfx_block_rpcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,36 +33,42 @@ def no_full_block_data(self, w3:Web3, block_hash: bytes, use_testnet: bool):
block_data = preprocess_block_data(block_data, use_testnet)
return block_data

@pytest.mark.xdist_group(name="account")
def test_get_block_by_hash(self, block_data: BlockData, no_full_block_data: BlockData):
TypeValidator.validate_typed_dict(block_data, "BlockData")
TypeValidator.validate_typed_dict(no_full_block_data, "BlockData")

@pytest.mark.xdist_group(name="account")
def test_get_block_by_epoch_number(self, w3:Web3, block_data: BlockData, use_testnet: bool):
assert block_data['epochNumber'] is not None
data_ = w3.cfx.get_block_by_epoch_number(block_data['epochNumber'], True)
data_ = preprocess_block_data(data_, use_testnet)
TypeValidator.validate_typed_dict(data_, "BlockData")


@pytest.mark.xdist_group(name="account")
def test_get_block_by_block_number(self, w3:Web3, block_data: BlockData, use_testnet: bool):
assert block_data['blockNumber'] is not None
data_ = w3.cfx.get_block_by_block_number(block_data['blockNumber'], True)
data_ = preprocess_block_data(data_, use_testnet)
assert dict(data_) == dict(block_data)

@pytest.mark.xdist_group(name="account")
def test_get_best_block_hash(self, w3:Web3):
best_block_hash = w3.cfx.get_best_block_hash()
assert isinstance(best_block_hash, HexBytes)

@pytest.mark.xdist_group(name="account")
def test_get_blocks_by_epoch(self, w3: Web3):
blocks = w3.cfx.get_blocks_by_epoch("latest_state")
for block_hash in blocks:
assert isinstance(block_hash, bytes)

@pytest.mark.xdist_group(name="account")
def test_get_skipped_blocks(self, w3: Web3):
blocks = w3.cfx.get_skipped_blocks_by_epoch("latest_state")
for block_hash in blocks:
assert isinstance(block_hash, bytes)

def test_get_blocks_by_hash_with_pivot_assumptions(self, w3: Web3, use_testnet: bool):
epoch_number = w3.cfx.epoch_number_by_tag("latest_confirmed")
blocks = w3.cfx.get_blocks_by_epoch(epoch_number)
Expand All @@ -73,7 +79,8 @@ def test_get_blocks_by_hash_with_pivot_assumptions(self, w3: Web3, use_testnet:
)
block_data = preprocess_block_data(block_data, use_testnet)
TypeValidator.validate_typed_dict(block_data, "BlockData")


@pytest.mark.xdist_group(name="account")
def test_get_block(self, w3: Web3, block_data: BlockData, use_testnet: bool):
epoch_number = block_data["epochNumber"]
assert epoch_number is not None
Expand All @@ -84,10 +91,11 @@ def test_get_block(self, w3: Web3, block_data: BlockData, use_testnet: bool):
block = preprocess_block_data(block, use_testnet)
TypeValidator.validate_typed_dict(block, "BlockData")

@pytest.mark.xdist_group(name="account")
def test_epoch_receipts(self, w3: Web3, block_data: BlockData):
epoch_number = block_data["epochNumber"]
assert epoch_number is not None
epoch_receipts = w3.cfx.get_epoch_receipts(epoch_number, True)
for block_receipts in epoch_receipts:
for tx_receipt in block_receipts:
TypeValidator.validate_typed_dict(tx_receipt, "TxReceiptWithSpace")
TypeValidator.validate_typed_dict(tx_receipt, "TxReceiptWithSpace")
Loading

0 comments on commit d70b69e

Please sign in to comment.