Tightening down config actions tests

pull/1989/head
Kieran Prasch 2020-05-17 11:38:20 -07:00
parent 722d26bcb4
commit c425ea6aa5
No known key found for this signature in database
GPG Key ID: 199AB839D4125A62
6 changed files with 89 additions and 106 deletions

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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,