mirror of https://github.com/nucypher/nucypher.git
Tightening down config actions tests
parent
722d26bcb4
commit
c425ea6aa5
|
@ -1,39 +1,29 @@
|
|||
import click
|
||||
import pytest
|
||||
from json.decoder import JSONDecodeError
|
||||
from pathlib import Path
|
||||
|
||||
from nucypher.cli.actions import config as config_actions
|
||||
from nucypher.cli.actions.config import (
|
||||
destroy_configuration,
|
||||
forget,
|
||||
get_or_update_configuration,
|
||||
handle_invalid_configuration_file,
|
||||
handle_missing_configuration_file,
|
||||
get_or_update_configuration
|
||||
handle_missing_configuration_file
|
||||
)
|
||||
from nucypher.cli.literature import MISSING_CONFIGURATION_FILE, SUCCESSFUL_DESTRUCTION
|
||||
from nucypher.config.characters import UrsulaConfiguration
|
||||
from nucypher.config.keyring import NucypherKeyring
|
||||
from nucypher.config.node import CharacterConfiguration
|
||||
from tests.constants import YES
|
||||
|
||||
|
||||
BAD_CONFIG_PAYLOADS = (
|
||||
BAD_CONFIG_FILE_CONTENTS = (
|
||||
{'some': 'garbage'},
|
||||
'some garbage',
|
||||
2,
|
||||
''
|
||||
'',
|
||||
)
|
||||
|
||||
|
||||
def test_forget(alice_blockchain_test_config,
|
||||
test_emitter,
|
||||
stdout_trap,
|
||||
mock_click_confirm):
|
||||
mock_click_confirm.return_value = YES
|
||||
forget(emitter=test_emitter, configuration=alice_blockchain_test_config)
|
||||
# TODO: Finish me
|
||||
|
||||
|
||||
# For parameterized fixture
|
||||
CONFIGS = [
|
||||
'alice_blockchain_test_config',
|
||||
'bob_blockchain_test_config',
|
||||
|
@ -68,16 +58,17 @@ def config(request, mocker):
|
|||
return config
|
||||
|
||||
|
||||
def test_update_configuration(config,
|
||||
test_emitter,
|
||||
stdout_trap,
|
||||
test_registry_source_manager):
|
||||
def test_forget(alice_blockchain_test_config, test_emitter, stdout_trap, mock_click_confirm, mocker):
|
||||
"""Tes"""
|
||||
mock_forget = mocker.patch.object(CharacterConfiguration, 'forget_nodes')
|
||||
mock_click_confirm.return_value = YES
|
||||
forget(emitter=test_emitter, configuration=alice_blockchain_test_config)
|
||||
mock_forget.assert_called_once()
|
||||
|
||||
# Setup
|
||||
|
||||
def test_update_configuration(config, test_emitter, stdout_trap, test_registry_source_manager):
|
||||
config_class = config.__class__
|
||||
config_file = config.filepath
|
||||
|
||||
# Test
|
||||
updates = dict(federated_only=True)
|
||||
assert not config.federated_only
|
||||
get_or_update_configuration(emitter=test_emitter,
|
||||
|
@ -97,73 +88,44 @@ def test_update_configuration(config,
|
|||
config_actions.handle_missing_configuration_file.assert_not_called()
|
||||
|
||||
|
||||
def test_destroy_configuration(config,
|
||||
test_emitter,
|
||||
stdout_trap,
|
||||
mocker,
|
||||
mock_click_confirm):
|
||||
|
||||
# Setup
|
||||
def test_destroy_configuration_action(config, test_emitter, stdout_trap, mocker, mock_click_confirm):
|
||||
config_class = config.__class__
|
||||
config_file = config.filepath
|
||||
|
||||
# Isolate from filesystem and Spy on the methods we're testing here
|
||||
spy_keyring_attached = mocker.spy(CharacterConfiguration, 'attach_keyring')
|
||||
spy_keyring_destroy = mocker.spy(NucypherKeyring, 'destroy')
|
||||
mock_os_remove = mocker.patch('os.remove')
|
||||
|
||||
# Test
|
||||
mock_config_destroy = mocker.patch.object(config_class, 'destroy')
|
||||
mock_click_confirm.return_value = YES
|
||||
destroy_configuration(emitter=test_emitter, character_config=config)
|
||||
|
||||
mock_config_destroy.assert_called_once()
|
||||
output = stdout_trap.getvalue()
|
||||
assert SUCCESSFUL_DESTRUCTION in output
|
||||
|
||||
spy_keyring_attached.assert_called_once()
|
||||
spy_keyring_destroy.assert_called_once()
|
||||
mock_os_remove.assert_called_with(str(config_file))
|
||||
|
||||
if config_class is UrsulaConfiguration:
|
||||
mock_os_remove.assert_called_with(filepath=config.db_filepath)
|
||||
|
||||
|
||||
def test_handle_missing_configuration_file(config):
|
||||
|
||||
# Setup
|
||||
config_class = config.__class__
|
||||
config_file = Path(config.filepath)
|
||||
|
||||
# Test Data
|
||||
init_command = f"{config_class.NAME} init"
|
||||
name = config_class.NAME.capitalize()
|
||||
message = MISSING_CONFIGURATION_FILE.format(name=name, init_command=init_command)
|
||||
|
||||
# Context: The config file does not exist
|
||||
assert not config_file.exists()
|
||||
|
||||
# Test
|
||||
with pytest.raises(click.exceptions.FileError, match=message):
|
||||
handle_missing_configuration_file(config_file=str(config_file),
|
||||
character_config_class=config_class)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('bad_config_payload', BAD_CONFIG_PAYLOADS)
|
||||
def test_handle_invalid_configuration_file(mocker,
|
||||
config,
|
||||
test_emitter,
|
||||
stdout_trap,
|
||||
bad_config_payload):
|
||||
|
||||
# Setup
|
||||
@pytest.mark.parametrize('bad_config_payload', BAD_CONFIG_FILE_CONTENTS)
|
||||
def test_handle_invalid_configuration_file_action(mocker, config, test_emitter, stdout_trap, bad_config_payload):
|
||||
config_class = config.__class__
|
||||
config_file = Path(config.filepath)
|
||||
|
||||
# Assume the file exists but is full of garbage
|
||||
mocker.patch.object(CharacterConfiguration,
|
||||
'_read_configuration_file',
|
||||
return_value=bad_config_payload)
|
||||
|
||||
# Test
|
||||
mocker.patch.object(CharacterConfiguration, '_read_configuration_file', return_value=bad_config_payload)
|
||||
with pytest.raises(config_class.ConfigurationError):
|
||||
handle_invalid_configuration_file(emitter=test_emitter,
|
||||
config_class=config_class,
|
||||
filepath=config_file)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('side_effect', (TypeError, JSONDecodeError))
|
||||
def test_handle_corrupted_configuration_file(mocker, config, test_emitter, stdout_trap, side_effect):
|
||||
config_class = config.__class__
|
||||
config_file = Path(config.filepath)
|
||||
mocker.patch.object(CharacterConfiguration, '_read_configuration_file', side_effect=side_effect)
|
||||
with pytest.raises(config_class.ConfigurationError):
|
||||
handle_invalid_configuration_file(emitter=test_emitter,
|
||||
config_class=config_class,
|
||||
|
|
|
@ -22,7 +22,7 @@ def test_missing_configuration_file(default_filepath_mock, click_runner):
|
|||
result = click_runner.invoke(nucypher_cli, cmd_args, catch_exceptions=False)
|
||||
assert result.exit_code != 0
|
||||
assert default_filepath_mock.called
|
||||
assert "run: 'nucypher felix init'" in result.output
|
||||
assert "nucypher felix init" in result.output # TODO: Move install hints to a constants
|
||||
|
||||
|
||||
@pytest_twisted.inlineCallbacks
|
||||
|
|
|
@ -24,6 +24,7 @@ import pytest_twisted as pt
|
|||
import time
|
||||
from twisted.internet import threads
|
||||
|
||||
from nucypher import utilities
|
||||
from nucypher.blockchain.eth.actors import Worker
|
||||
from nucypher.characters.base import Learner
|
||||
from nucypher.cli import actions
|
||||
|
@ -32,7 +33,8 @@ from nucypher.cli.main import nucypher_cli
|
|||
from nucypher.config.characters import UrsulaConfiguration
|
||||
from nucypher.config.constants import NUCYPHER_ENVVAR_KEYRING_PASSWORD, TEMPORARY_DOMAIN
|
||||
from nucypher.network.nodes import Teacher
|
||||
from tests.constants import (INSECURE_DEVELOPMENT_PASSWORD, MOCK_IP_ADDRESS, TEST_PROVIDER_URI)
|
||||
from tests.constants import (FAKE_PASSWORD_CONFIRMED, INSECURE_DEVELOPMENT_PASSWORD, MOCK_IP_ADDRESS, TEST_PROVIDER_URI,
|
||||
YES)
|
||||
from tests.utils.ursula import MOCK_URSULA_STARTING_PORT, start_pytest_ursula_services
|
||||
|
||||
|
||||
|
@ -185,45 +187,23 @@ def test_persistent_node_storage_integration(click_runner,
|
|||
def test_ursula_rest_host_determination(click_runner, mocker):
|
||||
|
||||
# Patch the get_external_ip call
|
||||
mocker.patch.object(actions.network, 'get_external_ip_from_centralized_source', return_value='192.0.2.0')
|
||||
mocker.patch.object(utilities.networking, 'get_external_ip_from_centralized_source', return_value=MOCK_IP_ADDRESS)
|
||||
mocker.patch.object(UrsulaConfiguration, 'to_configuration_file', return_value=None)
|
||||
|
||||
args = ('ursula', 'init',
|
||||
'--federated-only',
|
||||
'--network', TEMPORARY_DOMAIN,
|
||||
)
|
||||
|
||||
user_input = f'Y\n{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}'
|
||||
|
||||
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False,
|
||||
input=user_input)
|
||||
|
||||
args = ('ursula', 'init', '--federated-only', '--network', TEMPORARY_DOMAIN)
|
||||
user_input = YES + FAKE_PASSWORD_CONFIRMED
|
||||
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False, input=user_input)
|
||||
assert result.exit_code == 0
|
||||
assert '(192.0.2.0)' in result.output
|
||||
|
||||
args = ('ursula', 'init',
|
||||
'--federated-only',
|
||||
'--network', TEMPORARY_DOMAIN,
|
||||
'--force'
|
||||
)
|
||||
|
||||
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
|
||||
|
||||
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False,
|
||||
input=user_input)
|
||||
assert MOCK_IP_ADDRESS in result.output
|
||||
|
||||
args = ('ursula', 'init', '--federated-only', '--network', TEMPORARY_DOMAIN, '--force')
|
||||
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False, input=FAKE_PASSWORD_CONFIRMED)
|
||||
assert result.exit_code == 0
|
||||
assert '192.0.2.0' in result.output
|
||||
assert MOCK_IP_ADDRESS in result.output
|
||||
|
||||
# Patch get_external_ip call to error output
|
||||
mocker.patch.object(actions.network, 'get_external_ip_from_centralized_source', side_effect=UnknownIPAddress)
|
||||
|
||||
args = ('ursula', 'init',
|
||||
'--federated-only',
|
||||
'--network', TEMPORARY_DOMAIN,
|
||||
'--force')
|
||||
|
||||
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
|
||||
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=True, input=user_input)
|
||||
mocker.patch.object(utilities.network, 'get_external_ip_from_centralized_source', return_value=MOCK_IP_ADDRESS)
|
||||
args = ('ursula', 'init', '--federated-only', '--network', TEMPORARY_DOMAIN, '--force')
|
||||
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=True, input=FAKE_PASSWORD_CONFIRMED)
|
||||
assert result.exit_code == 1
|
||||
assert isinstance(result.exception, UnknownIPAddress)
|
||||
|
|
|
@ -42,7 +42,7 @@ def test_missing_configuration_file(default_filepath_mock, click_runner):
|
|||
result = click_runner.invoke(nucypher_cli, cmd_args, catch_exceptions=False)
|
||||
assert result.exit_code != 0
|
||||
assert default_filepath_mock.called
|
||||
assert "run: 'nucypher stake init-stakeholder'" in result.output
|
||||
assert "nucypher stake init-stakeholder" in result.output
|
||||
|
||||
|
||||
def test_new_stakeholder(click_runner,
|
||||
|
|
|
@ -146,3 +146,44 @@ def test_ursula_development_configuration(federated_only=True):
|
|||
ursula = config()
|
||||
assert ursula not in ursulas
|
||||
ursulas.append(ursula)
|
||||
|
||||
|
||||
|
||||
|
||||
def test_destroy_configuration(config,
|
||||
test_emitter,
|
||||
stdout_trap,
|
||||
mocker):
|
||||
# Setup
|
||||
config_class = config.__class__
|
||||
config_file = config.filepath
|
||||
|
||||
# Isolate from filesystem and Spy on the methods we're testing here
|
||||
spy_keyring_attached = mocker.spy(CharacterConfiguration, 'attach_keyring')
|
||||
mock_config_destroy = mocker.patch.object(CharacterConfiguration, 'destroy')
|
||||
spy_keyring_destroy = mocker.spy(NucypherKeyring, 'destroy')
|
||||
mock_os_remove = mocker.patch('os.remove')
|
||||
|
||||
# Test
|
||||
destroy_configuration(emitter=test_emitter, character_config=config)
|
||||
|
||||
mock_config_destroy.assert_called_once()
|
||||
output = stdout_trap.getvalue()
|
||||
assert SUCCESSFUL_DESTRUCTION in output
|
||||
|
||||
# spy_keyring_attached.assert_called_once()
|
||||
# spy_keyring_destroy.assert_called_once()
|
||||
# mock_os_remove.assert_called_with(str(config_file))
|
||||
|
||||
# TODO: move this test to config FT
|
||||
# Ensure all destroyed files belong to this Ursula
|
||||
# for call in mock_os_remove.call_args_list:
|
||||
# filepath = str(call.args[0])
|
||||
# assert config.checksum_address in filepath
|
||||
#
|
||||
# expected_removal = 7 # TODO: Source this number from somewhere else
|
||||
# if config_class is UrsulaConfiguration:
|
||||
# expected_removal += 1
|
||||
# mock_os_remove.assert_called_with(config.db_filepath)
|
||||
#
|
||||
# assert mock_os_remove.call_count == expected_removal
|
|
@ -186,12 +186,12 @@ def alice_blockchain_test_config(blockchain_ursulas, testerchain, test_registry)
|
|||
config = make_alice_test_configuration(federated=False,
|
||||
provider_uri=TEST_PROVIDER_URI,
|
||||
known_nodes=blockchain_ursulas,
|
||||
checksum_address=testerchain.alice_account,
|
||||
test_registry=test_registry)
|
||||
yield config
|
||||
config.cleanup()
|
||||
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def bob_blockchain_test_config(blockchain_ursulas, testerchain, test_registry):
|
||||
config = make_bob_test_configuration(federated=False,
|
||||
|
|
Loading…
Reference in New Issue