mirror of https://github.com/nucypher/nucypher.git
227 lines
8.0 KiB
Python
227 lines
8.0 KiB
Python
"""
|
|
This file is part of nucypher.
|
|
|
|
nucypher is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
nucypher is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from eth_account.account import Account
|
|
|
|
from nucypher.blockchain.economics import EconomicsFactory
|
|
from nucypher.blockchain.eth.agents import (
|
|
AdjudicatorAgent,
|
|
ContractAgency,
|
|
PREApplicationAgent
|
|
)
|
|
from nucypher.blockchain.eth.interfaces import BlockchainInterface
|
|
from nucypher.blockchain.eth.registry import InMemoryContractRegistry
|
|
from nucypher.blockchain.eth.signers import KeystoreSigner
|
|
from nucypher.config.characters import UrsulaConfiguration
|
|
from tests.constants import (
|
|
KEYFILE_NAME_TEMPLATE,
|
|
MOCK_KEYSTORE_PATH,
|
|
MOCK_ETH_PROVIDER_URI,
|
|
NUMBER_OF_MOCK_KEYSTORE_ACCOUNTS
|
|
)
|
|
from tests.mock.agents import MockContractAgency, MockContractAgent
|
|
from tests.mock.interfaces import MockBlockchain, mock_registry_source_manager
|
|
from tests.mock.io import MockStdinWrapper
|
|
from tests.utils.config import (
|
|
make_alice_test_configuration,
|
|
make_bob_test_configuration,
|
|
make_ursula_test_configuration
|
|
)
|
|
from tests.utils.ursula import MOCK_URSULA_STARTING_PORT
|
|
|
|
|
|
@pytest.fixture(scope='function', autouse=True)
|
|
def mock_contract_agency(monkeypatch, module_mocker, application_economics):
|
|
monkeypatch.setattr(ContractAgency, 'get_agent', MockContractAgency.get_agent)
|
|
module_mocker.patch.object(EconomicsFactory, 'get_economics', return_value=application_economics)
|
|
mock_agency = MockContractAgency()
|
|
yield mock_agency
|
|
mock_agency.reset()
|
|
|
|
|
|
@pytest.fixture(scope='function', autouse=True)
|
|
def mock_application_agent(mock_testerchain, application_economics, mock_contract_agency, mocker):
|
|
mock_agent = mock_contract_agency.get_agent(PREApplicationAgent)
|
|
|
|
# Handle the special case of commit_to_next_period, which returns a txhash due to the fire_and_forget option
|
|
mock_agent.confirm_operator_address = mocker.Mock(return_value=MockContractAgent.FAKE_TX_HASH)
|
|
|
|
yield mock_agent
|
|
mock_agent.reset()
|
|
|
|
|
|
def mock_adjudicator_agent(mock_testerchain, application_economics, mock_contract_agency):
|
|
mock_agent = mock_contract_agency.get_agent(AdjudicatorAgent)
|
|
yield mock_agent
|
|
mock_agent.reset()
|
|
|
|
|
|
@pytest.fixture(scope='function')
|
|
def mock_stdin(mocker):
|
|
|
|
mock = MockStdinWrapper()
|
|
|
|
mocker.patch('sys.stdin', new=mock.mock_stdin)
|
|
mocker.patch('getpass.getpass', new=mock.mock_getpass)
|
|
|
|
yield mock
|
|
|
|
# Sanity check.
|
|
# The user is encouraged to `assert mock_stdin.empty()` explicitly in the test
|
|
# right after the input-consuming function call.
|
|
assert mock.empty(), "Stdin mock was not empty on teardown - some unclaimed input remained"
|
|
|
|
|
|
@pytest.fixture(scope='module', autouse=True)
|
|
def mock_testerchain(_mock_testerchain) -> MockBlockchain:
|
|
yield _mock_testerchain
|
|
|
|
|
|
@pytest.fixture(scope='module', autouse=True)
|
|
def mock_interface(module_mocker):
|
|
mock_transaction_sender = module_mocker.patch.object(BlockchainInterface, 'sign_and_broadcast_transaction')
|
|
mock_transaction_sender.return_value = MockContractAgent.FAKE_RECEIPT
|
|
return mock_transaction_sender
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
def test_registry():
|
|
registry = InMemoryContractRegistry()
|
|
return registry
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
def test_registry_source_manager(mock_testerchain, test_registry):
|
|
with mock_registry_source_manager(test_registry=test_registry) as real_inventory:
|
|
yield real_inventory
|
|
|
|
|
|
@pytest.fixture(scope='module', autouse=True)
|
|
def mock_contract_agency(module_mocker, application_economics):
|
|
|
|
# Patch
|
|
module_mocker.patch.object(EconomicsFactory, 'get_economics', return_value=application_economics)
|
|
|
|
# Monkeypatch # TODO: Use better tooling for this monkeypatch?
|
|
get_agent = ContractAgency.get_agent
|
|
get_agent_by_name = ContractAgency.get_agent_by_contract_name
|
|
ContractAgency.get_agent = MockContractAgency.get_agent
|
|
ContractAgency.get_agent_by_contract_name = MockContractAgency.get_agent_by_contract_name
|
|
|
|
# Test
|
|
yield MockContractAgency()
|
|
|
|
# Restore the monkey patching
|
|
ContractAgency.get_agent = get_agent
|
|
ContractAgency.get_agent_by_contract_name = get_agent_by_name
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
def mock_accounts():
|
|
accounts = dict()
|
|
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
|
|
return accounts
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
def mock_account(mock_accounts):
|
|
return list(mock_accounts.items())[0][1]
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
def operator_account(mock_accounts, mock_testerchain):
|
|
account = list(mock_accounts.values())[0]
|
|
return account
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
def operator_address(operator_account):
|
|
address = operator_account.address
|
|
return address
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
def custom_config_filepath(custom_filepath: Path):
|
|
filepath = custom_filepath / UrsulaConfiguration.generate_filename()
|
|
return filepath
|
|
|
|
|
|
@pytest.fixture(scope='function')
|
|
def patch_keystore(mock_accounts, monkeypatch, mocker):
|
|
def successful_mock_keyfile_reader(_keystore, path):
|
|
|
|
# Ensure the absolute path is passed to the keyfile reader
|
|
assert MOCK_KEYSTORE_PATH in path
|
|
full_path = path
|
|
del path
|
|
|
|
for filename, account in mock_accounts.items(): # Walk the mock filesystem
|
|
if filename in full_path:
|
|
break
|
|
else:
|
|
raise FileNotFoundError(f"No such file {full_path}")
|
|
return account.address, dict(version=3, address=account.address)
|
|
|
|
mocker.patch('pathlib.Path.iterdir', return_value=[Path(key) for key in mock_accounts.keys()])
|
|
monkeypatch.setattr(KeystoreSigner, '_KeystoreSigner__read_keystore', successful_mock_keyfile_reader)
|
|
yield
|
|
monkeypatch.delattr(KeystoreSigner, '_KeystoreSigner__read_keystore')
|
|
|
|
|
|
@pytest.fixture(scope='function')
|
|
def mock_keystore(mocker):
|
|
mocker.patch.object(KeystoreSigner, '_KeystoreSigner__read_keystore')
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def alice_blockchain_test_config(mock_testerchain, test_registry):
|
|
config = make_alice_test_configuration(federated=False,
|
|
eth_provider_uri=MOCK_ETH_PROVIDER_URI,
|
|
test_registry=test_registry,
|
|
checksum_address=mock_testerchain.alice_account)
|
|
yield config
|
|
config.cleanup()
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def bob_blockchain_test_config(mock_testerchain, test_registry):
|
|
config = make_bob_test_configuration(federated=False,
|
|
eth_provider_uri=MOCK_ETH_PROVIDER_URI,
|
|
test_registry=test_registry,
|
|
checksum_address=mock_testerchain.bob_account)
|
|
yield config
|
|
config.cleanup()
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def ursula_decentralized_test_config(mock_testerchain, test_registry):
|
|
config = make_ursula_test_configuration(federated=False,
|
|
eth_provider_uri=MOCK_ETH_PROVIDER_URI, # L1
|
|
payment_provider=MOCK_ETH_PROVIDER_URI, # L1/L2
|
|
test_registry=test_registry,
|
|
rest_port=MOCK_URSULA_STARTING_PORT,
|
|
checksum_address=mock_testerchain.ursula_account(index=0))
|
|
yield config
|
|
config.cleanup()
|