mirror of https://github.com/nucypher/nucypher.git
100% coverage on interactive eth account selection
parent
cc66d9310a
commit
f583567222
|
@ -96,6 +96,9 @@ def select_client_account(emitter,
|
|||
Note: Showing ETH and/or NU balances, causes an eager blockchain connection.
|
||||
"""
|
||||
|
||||
if wallet and (provider_uri or signer_uri or signer):
|
||||
raise ValueError("If pass a wallet, don't pass a signer, provider URI, or signer URI also.")
|
||||
|
||||
# We use Wallet internally as an account management abstraction
|
||||
if not wallet:
|
||||
|
||||
|
@ -115,9 +118,6 @@ def select_client_account(emitter,
|
|||
|
||||
wallet = Wallet(provider_uri=provider_uri, signer=signer)
|
||||
|
||||
elif provider_uri or signer_uri:
|
||||
raise ValueError("If you input a wallet, don't pass a provider URI or signer URI too")
|
||||
|
||||
# Display accounts info
|
||||
if show_nu_balance or show_staking: # Lazy registry fetching
|
||||
if not registry:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import click
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
@ -5,66 +6,119 @@ from eth_utils import is_checksum_address
|
|||
from web3 import Web3
|
||||
|
||||
from nucypher.blockchain.eth.actors import Wallet
|
||||
from nucypher.blockchain.eth.clients import EthereumClient, EthereumTesterClient
|
||||
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
|
||||
from nucypher.blockchain.eth.token import NU
|
||||
from nucypher.cli.actions.select import select_client_account
|
||||
from nucypher.cli.literature import NO_ETH_ACCOUNTS
|
||||
from nucypher.config.constants import TEMPORARY_DOMAIN
|
||||
from tests.constants import MOCK_PROVIDER_URI, MOCK_SIGNER_URI, NUMBER_OF_ETH_TEST_ACCOUNTS
|
||||
|
||||
|
||||
def test_select_client_account(mock_click_prompt, test_emitter, mock_testerchain):
|
||||
@pytest.mark.parametrize('selection', range(NUMBER_OF_ETH_TEST_ACCOUNTS))
|
||||
def test_select_client_account(mock_click_prompt, test_emitter, mock_testerchain, selection):
|
||||
"""Fine-grained assertions about the return value of interactive client account selection"""
|
||||
selection = 0
|
||||
mock_click_prompt.return_value = selection
|
||||
expected_account = mock_testerchain.client.accounts[selection]
|
||||
selected_account = select_client_account(emitter=test_emitter, provider_uri=MOCK_PROVIDER_URI)
|
||||
assert selected_account, "Account selection returned Falsy instead of an address"
|
||||
assert isinstance(selected_account, str), "Selection is not a str"
|
||||
assert is_checksum_address(selected_account), "Selection is not a valid checksum address"
|
||||
assert selected_account == mock_testerchain.etherbase_account, "Selection returned the wrong address"
|
||||
assert selected_account == expected_account, "Selection returned the wrong address"
|
||||
|
||||
|
||||
def test_select_client_account_invalid_input(mock_click_prompt, test_emitter, mock_testerchain):
|
||||
def test_select_client_account_with_no_accounts(mocker,
|
||||
mock_click_prompt,
|
||||
test_emitter,
|
||||
mock_testerchain,
|
||||
stdout_trap):
|
||||
mocker.patch.object(EthereumClient, 'accounts', return_value=[])
|
||||
with pytest.raises(click.Abort):
|
||||
select_client_account(emitter=test_emitter, provider_uri=MOCK_PROVIDER_URI)
|
||||
output = stdout_trap.getvalue()
|
||||
assert NO_ETH_ACCOUNTS in output
|
||||
|
||||
|
||||
def test_select_client_account_ambiguous_source(mock_click_prompt, test_emitter, mock_testerchain):
|
||||
|
||||
#
|
||||
# Implicit wallet
|
||||
#
|
||||
|
||||
# Provider URI Problems
|
||||
error_message = "At least a provider URI or signer URI is necessary to select an account"
|
||||
with pytest.raises(ValueError, match=error_message):
|
||||
select_client_account(emitter=test_emitter)
|
||||
|
||||
# Signer Problems
|
||||
error_message = "Pass either signer or signer_uri but not both."
|
||||
with pytest.raises(ValueError, match=error_message):
|
||||
select_client_account(emitter=test_emitter, signer=Mock(), signer_uri=MOCK_SIGNER_URI)
|
||||
|
||||
#
|
||||
# Explicit wallet
|
||||
#
|
||||
|
||||
def test_select_client_account_valid_inputs(mock_click_prompt,
|
||||
test_emitter,
|
||||
mock_testerchain,
|
||||
patch_keystore,
|
||||
mock_accounts):
|
||||
selection = 0
|
||||
error_message = "If pass a wallet, don't pass a signer, provider URI, or signer URI also."
|
||||
with pytest.raises(ValueError, match=error_message):
|
||||
select_client_account(emitter=test_emitter,
|
||||
signer_uri=Mock(),
|
||||
wallet=Mock())
|
||||
|
||||
with pytest.raises(ValueError, match=error_message):
|
||||
select_client_account(emitter=test_emitter,
|
||||
signer=Mock(),
|
||||
wallet=Mock())
|
||||
|
||||
with pytest.raises(ValueError, match=error_message):
|
||||
select_client_account(emitter=test_emitter,
|
||||
provider_uri=Mock(),
|
||||
wallet=Mock())
|
||||
|
||||
|
||||
@pytest.mark.parametrize('selection', range(NUMBER_OF_ETH_TEST_ACCOUNTS))
|
||||
def test_select_client_account_valid_sources(mocker,
|
||||
mock_click_prompt,
|
||||
test_emitter,
|
||||
mock_testerchain,
|
||||
patch_keystore,
|
||||
mock_accounts,
|
||||
selection):
|
||||
|
||||
# Setup
|
||||
mock_click_prompt.return_value = selection
|
||||
|
||||
# From Provider
|
||||
selected_account = select_client_account(emitter=test_emitter, provider_uri=MOCK_PROVIDER_URI)
|
||||
assert selected_account == mock_testerchain.etherbase_account
|
||||
|
||||
# From Wallet
|
||||
wallet = Wallet(provider_uri=MOCK_PROVIDER_URI)
|
||||
selected_account = select_client_account(emitter=test_emitter, wallet=wallet)
|
||||
assert selected_account == mock_testerchain.etherbase_account
|
||||
|
||||
# From External Signer
|
||||
selected_account = select_client_account(emitter=test_emitter, signer_uri=MOCK_SIGNER_URI)
|
||||
signer_etherbase_keystore = list(mock_accounts.items())[0]
|
||||
signer_etherbase_keystore = list(mock_accounts.items())[selection]
|
||||
_filename, signer_etherbase_account = signer_etherbase_keystore
|
||||
assert selected_account == signer_etherbase_account.address
|
||||
expected_account = signer_etherbase_account.address
|
||||
assert selected_account == expected_account
|
||||
|
||||
# From Wallet
|
||||
expected_account = mock_testerchain.client.accounts[selection]
|
||||
wallet = Wallet(provider_uri=MOCK_PROVIDER_URI)
|
||||
selected_account = select_client_account(emitter=test_emitter, wallet=wallet)
|
||||
assert selected_account == expected_account
|
||||
|
||||
# From pre-initialized Provider
|
||||
expected_account = mock_testerchain.client.accounts[selection]
|
||||
selected_account = select_client_account(emitter=test_emitter, provider_uri=MOCK_PROVIDER_URI)
|
||||
assert selected_account == expected_account
|
||||
|
||||
# From uninitialized Provider
|
||||
mocker.patch.object(BlockchainInterfaceFactory, 'is_interface_initialized', return_value=False)
|
||||
mocker.patch.object(BlockchainInterfaceFactory, '_interfaces', return_value={})
|
||||
mocker.patch.object(BlockchainInterfaceFactory, 'get_interface', return_value=mock_testerchain)
|
||||
selected_account = select_client_account(emitter=test_emitter, provider_uri=MOCK_PROVIDER_URI)
|
||||
assert selected_account == expected_account
|
||||
|
||||
|
||||
@pytest.mark.parametrize('selection,show_staking,show_eth,show_tokens,mock_stakes',(
|
||||
@pytest.mark.parametrize('selection,show_staking,show_eth,show_tokens,mock_stakes', (
|
||||
(0, True, True, True, []),
|
||||
(1, True, True, True, []),
|
||||
(5, True, True, True, []),
|
||||
(NUMBER_OF_ETH_TEST_ACCOUNTS-1, True, True, True, []),
|
||||
(4, True, True, True, [(1, 2, 3)]),
|
||||
(7, True, True, True, [(1, 2, 3), (1, 2, 3)]),
|
||||
(0, False, True, True, []),
|
||||
(0, False, False, True, []),
|
||||
(0, False, False, False, []),
|
||||
|
@ -82,6 +136,7 @@ def test_select_client_account_with_balance_display(mock_click_prompt,
|
|||
show_tokens,
|
||||
mock_stakes):
|
||||
|
||||
# Setup
|
||||
mock_click_prompt.return_value = selection
|
||||
|
||||
# Missing network kwarg with balance display active
|
||||
|
|
|
@ -23,13 +23,13 @@ from eth_account.account import Account
|
|||
from io import StringIO
|
||||
|
||||
from nucypher.blockchain.economics import EconomicsFactory
|
||||
from nucypher.blockchain.eth import KeystoreSigner
|
||||
from nucypher.blockchain.eth.agents import ContractAgency
|
||||
from nucypher.blockchain.eth.interfaces import BlockchainInterface, BlockchainInterfaceFactory
|
||||
from nucypher.blockchain.eth.registry import InMemoryContractRegistry
|
||||
from nucypher.blockchain.eth.signers import KeystoreSigner
|
||||
from nucypher.characters.control.emitters import StdoutEmitter
|
||||
from nucypher.config.characters import UrsulaConfiguration
|
||||
from tests.constants import KEYFILE_NAME_TEMPLATE, MOCK_KEYSTORE_PATH, NUMBER_OF_ETH_TEST_ACCOUNTS
|
||||
from tests.constants import KEYFILE_NAME_TEMPLATE, MOCK_KEYSTORE_PATH, NUMBER_OF_MOCK_KEYSTORE_ACCOUNTS
|
||||
from tests.fixtures import _make_testerchain, make_token_economics
|
||||
from tests.mock.agents import FAKE_RECEIPT, MockContractAgency, MockNucypherToken, MockStakingAgent, MockWorkLockAgent
|
||||
from tests.mock.interfaces import MockBlockchain, make_mock_registry_source_manager
|
||||
|
@ -151,7 +151,7 @@ def mock_contract_agency(module_mocker, token_economics):
|
|||
@pytest.fixture(scope='module')
|
||||
def mock_accounts():
|
||||
accounts = dict()
|
||||
for i in range(NUMBER_OF_ETH_TEST_ACCOUNTS):
|
||||
for i in range(NUMBER_OF_MOCK_KEYSTORE_ACCOUNTS):
|
||||
account = Account.create()
|
||||
filename = KEYFILE_NAME_TEMPLATE.format(month=i+1, address=account.address)
|
||||
accounts[filename] = account
|
||||
|
|
|
@ -50,7 +50,7 @@ MOCK_KEYSTORE_PATH = '/home/fakeMcfakeson/.ethereum/llamanet/keystore/'
|
|||
|
||||
MOCK_SIGNER_URI = f'keystore://{MOCK_KEYSTORE_PATH}'
|
||||
|
||||
NUMBER_OF_MOCK_ACCOUNTS = 3
|
||||
NUMBER_OF_MOCK_KEYSTORE_ACCOUNTS = NUMBER_OF_ETH_TEST_ACCOUNTS
|
||||
|
||||
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue