-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement getting node configurations #25
Changes from 11 commits
3ed2d50
ee6bfa6
c348666
c26799a
36cd046
d2b225a
9b77b81
a532eac
0710491
a2848a0
d03ebdd
d13366b
0ed94c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -17,6 +17,7 @@ | |||||
* [Configuration file](#configuration-file) | ||||||
* [Service](#service) | ||||||
* [Account](#account) | ||||||
* [Node](#node) | ||||||
* [Development](#development) | ||||||
* [Requirements](#development-requirements) | ||||||
* [Docker](#docker) | ||||||
|
@@ -139,6 +140,26 @@ $ remme account transfer-tokens \ | |||||
} | ||||||
``` | ||||||
|
||||||
### Node | ||||||
|
||||||
Get node configurations — ``remme node get-configurations``: | ||||||
|
||||||
| Arguments | Type | Required | Description | | ||||||
| :-------: | :----: | :-------: | ------------------------------------ | | ||||||
| node-url | String | No | Node URL to apply a command to. | | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @anastasiia-bilova, done. |
||||||
|
||||||
```bash | ||||||
$ remme node get-configs --node-url=node-genesis-testnet.remme.io | ||||||
{ | ||||||
"result": { | ||||||
"configurations": { | ||||||
"node_address": "1168296ecf036e857f42129b58303bcf1e03723764a1702cbe98529802aad8514ee3cf", | ||||||
"node_public_key": "03738df3f4ac3621ba8e89413d3ff4ad036c3a0a4dbb164b695885aab6aab614ad" | ||||||
} | ||||||
} | ||||||
} | ||||||
``` | ||||||
|
||||||
## Development | ||||||
|
||||||
<h3 id="development-requirements">Requirements</h4> | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
""" | ||
Provide implementation of the command line interface's node commands. | ||
""" | ||
import asyncio | ||
import sys | ||
|
||
import click | ||
from remme import Remme | ||
|
||
from cli.constants import ( | ||
FAILED_EXIT_FROM_COMMAND_CODE, | ||
NODE_URL_ARGUMENT_HELP_MESSAGE, | ||
) | ||
from cli.node.forms import GetNodeConfigurationsForm | ||
from cli.node.service import Node | ||
from cli.utils import ( | ||
default_node_url, | ||
print_errors, | ||
print_result, | ||
) | ||
|
||
loop = asyncio.get_event_loop() | ||
|
||
|
||
@click.group('node', chain=True) | ||
def node_commands(): | ||
""" | ||
Provide commands for working with node. | ||
""" | ||
pass | ||
|
||
|
||
@click.option('--node-url', type=str, required=False, help=NODE_URL_ARGUMENT_HELP_MESSAGE, default=default_node_url()) | ||
@node_commands.command('get-configs') | ||
def get_config(node_url): | ||
""" | ||
Get node configurations. | ||
""" | ||
arguments, errors = GetNodeConfigurationsForm().load({ | ||
'node_url': node_url, | ||
}) | ||
|
||
if errors: | ||
print_errors(errors=errors) | ||
sys.exit(FAILED_EXIT_FROM_COMMAND_CODE) | ||
|
||
node_url = arguments.get('node_url') | ||
|
||
remme = Remme(network_config={ | ||
'node_address': str(node_url) + ':8080', | ||
}) | ||
|
||
result, errors = Node(service=remme).get_configs() | ||
|
||
if errors is not None: | ||
print_errors(errors=errors) | ||
sys.exit(FAILED_EXIT_FROM_COMMAND_CODE) | ||
|
||
print_result(result=result) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
""" | ||
Provide forms for command line interface's node commands. | ||
""" | ||
from marshmallow import Schema | ||
|
||
from cli.generic.forms.fields import NodeURLField | ||
|
||
|
||
class GetNodeConfigurationsForm(Schema): | ||
""" | ||
Get node configurations. | ||
""" | ||
|
||
node_url = NodeURLField(allow_none=True, required=False) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
""" | ||
Provide implementation of the node interfaces. | ||
""" | ||
|
||
|
||
class NodeInterface: | ||
""" | ||
Implements node interface. | ||
""" | ||
|
||
def get_configs(self): | ||
""" | ||
Get node configurations. | ||
""" | ||
pass |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,40 @@ | ||||||
""" | ||||||
Provide implementation of the node. | ||||||
""" | ||||||
import asyncio | ||||||
|
||||||
from accessify import implements | ||||||
|
||||||
from cli.node.interfaces import NodeInterface | ||||||
|
||||||
loop = asyncio.get_event_loop() | ||||||
|
||||||
|
||||||
@implements(NodeInterface) | ||||||
class Node: | ||||||
""" | ||||||
Implements account. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @anastasiia-bilova, done. |
||||||
""" | ||||||
|
||||||
def __init__(self, service): | ||||||
""" | ||||||
Constructor. | ||||||
|
||||||
Arguments: | ||||||
service: object to interact with Remme core API. | ||||||
""" | ||||||
self.service = service | ||||||
|
||||||
def get_configs(self): | ||||||
""" | ||||||
Get node configurations. | ||||||
""" | ||||||
try: | ||||||
configurations = loop.run_until_complete(self.service.node_management.get_node_config()) | ||||||
|
||||||
except Exception as error: | ||||||
return None, str(error) | ||||||
|
||||||
return { | ||||||
'configurations': configurations.data, | ||||||
}, None |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
""" | ||
Provide tests for command line interface's node get configurations command. | ||
""" | ||
import json | ||
|
||
from click.testing import CliRunner | ||
|
||
from cli.constants import ( | ||
FAILED_EXIT_FROM_COMMAND_CODE, | ||
LATEST_RELEASE_NODE_IP_ADDRESS_FOR_TESTING, | ||
PASSED_EXIT_FROM_COMMAND_CODE, | ||
) | ||
from cli.entrypoint import cli | ||
from cli.utils import dict_to_pretty_json | ||
|
||
|
||
def test_get_node_configs(): | ||
""" | ||
Case: get node configurations. | ||
Expect: node public key and address are returned. | ||
""" | ||
runner = CliRunner() | ||
result = runner.invoke(cli, [ | ||
'node', | ||
'get-configs', | ||
'--node-url', | ||
LATEST_RELEASE_NODE_IP_ADDRESS_FOR_TESTING, | ||
]) | ||
|
||
expected_node_configurations = { | ||
'result': { | ||
'configurations': { | ||
'node_address': '11682919ed54658edf965f955a5783e6a653ce3bb411b99c8afe9f6e5840af45171774', | ||
'node_public_key': '03725231d64d1b379a1d855d0e7614684744ba915bd657e398f5a5cefc9ced896d', | ||
}, | ||
}, | ||
} | ||
|
||
assert PASSED_EXIT_FROM_COMMAND_CODE == result.exit_code | ||
assert expected_node_configurations == json.loads(result.output) | ||
|
||
|
||
def test_get_node_configs_without_node_url(mocker, node_configurations): | ||
""" | ||
Case: get node configurations without passing node URL. | ||
Expect: batch identifier is returned from node on localhost. | ||
""" | ||
mock_account_get_balance = mocker.patch('cli.node.service.loop.run_until_complete') | ||
mock_account_get_balance.return_value = node_configurations | ||
|
||
runner = CliRunner() | ||
result = runner.invoke(cli, [ | ||
'node', | ||
'get-configs', | ||
]) | ||
|
||
expected_node_configurations = { | ||
'result': { | ||
'configurations': node_configurations.data, | ||
}, | ||
} | ||
|
||
assert PASSED_EXIT_FROM_COMMAND_CODE == result.exit_code | ||
assert expected_node_configurations == json.loads(result.output) | ||
|
||
|
||
def test_get_node_configs_invalid_node_url(): | ||
""" | ||
Case: get node configurations by passing invalid node URL. | ||
Expect: the following node URL is invalid error message. | ||
""" | ||
invalid_node_url = 'domainwithoutextention' | ||
|
||
runner = CliRunner() | ||
result = runner.invoke(cli, [ | ||
'node', | ||
'get-configs', | ||
'--node-url', | ||
invalid_node_url, | ||
]) | ||
|
||
expected_error = { | ||
'errors': { | ||
'node_url': [ | ||
f'The following node URL `{invalid_node_url}` is invalid.', | ||
], | ||
}, | ||
} | ||
|
||
assert FAILED_EXIT_FROM_COMMAND_CODE == result.exit_code | ||
assert dict_to_pretty_json(expected_error) in result.output | ||
|
||
|
||
def test_get_node_configs_node_url_with_http(): | ||
""" | ||
Case: get node configurations by passing node URL with explicit HTTP protocol. | ||
Expect: the following node URL contains protocol error message. | ||
""" | ||
node_url_with_http_protocol = 'http://masternode.com' | ||
|
||
runner = CliRunner() | ||
result = runner.invoke(cli, [ | ||
'node', | ||
'get-configs', | ||
'--node-url', | ||
node_url_with_http_protocol, | ||
]) | ||
|
||
expected_error = { | ||
'errors': { | ||
'node_url': [ | ||
f'Pass the following node URL `{node_url_with_http_protocol}` without protocol (http, https, etc.).', | ||
], | ||
}, | ||
} | ||
|
||
assert FAILED_EXIT_FROM_COMMAND_CODE == result.exit_code | ||
assert dict_to_pretty_json(expected_error) in result.output | ||
|
||
|
||
def test_get_node_configs_node_url_with_https(): | ||
""" | ||
Case: get node configurations by passing node URL with explicit HTTPS protocol. | ||
Expect: the following node URL contains protocol error message. | ||
""" | ||
node_url_with_https_protocol = 'https://masternode.com' | ||
|
||
runner = CliRunner() | ||
result = runner.invoke(cli, [ | ||
'node', | ||
'get-configs', | ||
'--node-url', | ||
node_url_with_https_protocol, | ||
]) | ||
|
||
expected_error = { | ||
'errors': { | ||
'node_url': [ | ||
f'Pass the following node URL `{node_url_with_https_protocol}` without protocol (http, https, etc.).', | ||
], | ||
}, | ||
} | ||
|
||
assert FAILED_EXIT_FROM_COMMAND_CODE == result.exit_code | ||
assert dict_to_pretty_json(expected_error) in result.output | ||
|
||
|
||
def test_get_node_configs_non_existing_node_url(): | ||
""" | ||
Case: get node configurations by passing non existing node URL. | ||
Expect: check if node running at URL error message. | ||
""" | ||
non_existing_node_url = 'non-existing-node.com' | ||
|
||
runner = CliRunner() | ||
result = runner.invoke(cli, [ | ||
'node', | ||
'get-configs', | ||
'--node-url', | ||
non_existing_node_url, | ||
]) | ||
|
||
expected_error = { | ||
'errors': f'Please check if your node running at http://{non_existing_node_url}:8080.', | ||
} | ||
|
||
assert FAILED_EXIT_FROM_COMMAND_CODE == result.exit_code | ||
assert dict_to_pretty_json(expected_error) in result.output |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anastasiia-bilova, done.