Skip to content

Commit

Permalink
Implement getting node configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
dmytrostriletskyi committed Apr 22, 2019
1 parent 3ed2d50 commit add326a
Show file tree
Hide file tree
Showing 10 changed files with 302 additions and 0 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* [Configuration file](#configuration-file)
* [Service](#service)
* [Account](#account)
* [Node](#node)
* [Development](#development)
* [Requirements](#development-requirements)
* [Docker](#docker)
Expand Down Expand Up @@ -133,6 +134,22 @@ $ 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. |

```bash
$ remme node get-configurations --node-url=node-genesis-testnet.remme.io
{
"node_address": "1168296ecf036e857f42129b58303bcf1e03723764a1702cbe98529802aad8514ee3cf",
"node_public_key": "03738df3f4ac3621ba8e89413d3ff4ad036c3a0a4dbb164b695885aab6aab614ad"
}
```

## Development

<h3 id="development-requirements">Requirements</h4>
Expand Down
1 change: 1 addition & 0 deletions cli/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@
CLI_CONFIG_FILE_NAME = 'remme-core-cli'

NODE_IP_ADDRESS_FOR_TESTING = '159.89.104.9'
LATEST_RELEASE_NODE_IP_ADDRESS_FOR_TESTING = '165.22.75.163'
PRIVATE_KEY_FOR_TESTING = 'b03e31d2f310305eab249133b53b5fb3270090fc1692c9b022b81c6b9bb6029b'
2 changes: 2 additions & 0 deletions cli/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import click

from cli.account.cli import account_commands
from cli.node.cli import node_commands


@click.group()
Expand All @@ -17,3 +18,4 @@ def cli():


cli.add_command(account_commands)
cli.add_command(node_commands)
Empty file added cli/node/__init__.py
Empty file.
59 changes: 59 additions & 0 deletions cli/node/cli.py
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.node.forms import GetNodeConfigurationsForm
from cli.node.service import Node
from cli.constants import (
FAILED_EXIT_FROM_COMMAND_CODE,
NODE_URL_ARGUMENT_HELP_MESSAGE,
)
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-configurations')
def transfer_tokens(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_configurations()

if errors is not None:
print_errors(errors=errors)
sys.exit(FAILED_EXIT_FROM_COMMAND_CODE)

print_result(result=result)
37 changes: 37 additions & 0 deletions cli/node/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
Provide forms for command line interface's node commands.
"""
import re

from marshmallow import (
Schema,
ValidationError,
fields,
validates,
)

from cli.constants import DOMAIN_NAME_REGEXP


class GetNodeConfigurationsForm(Schema):
"""
Get node configurations.
"""

node_url = fields.String(allow_none=True, required=False)

@validates('node_url')
def validate_node_url(self, node_url):
"""
Validate node URL.
If node URL is localhost, it means client didn't passed any URL, so nothing to validate.
"""
if node_url == 'localhost':
return

if 'http' in node_url or 'https' in node_url:
raise ValidationError(f'Pass the following node URL `{node_url}` without protocol (http, https, etc.).')

if re.match(pattern=DOMAIN_NAME_REGEXP, string=node_url) is None:
raise ValidationError(f'The following node URL `{node_url}` is invalid.')
15 changes: 15 additions & 0 deletions cli/node/interfaces.py
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_configurations(self):
"""
Get node configurations.
"""
pass
37 changes: 37 additions & 0 deletions cli/node/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
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.
"""

def __init__(self, service):
"""
Constructor.
Arguments:
service: object to interact with Remme core API.
"""
self.service = service

def get_configurations(self):
"""
Get node configurations.
"""
# configurations = loop.run_until_complete(self.service.node_management.get_node_config())

from remme.models.general.methods import RemmeMethods
configurations = loop.run_until_complete(self.service._remme_api.send_request(method=RemmeMethods.NODE_CONFIG))

return configurations, None
Empty file added tests/node/__init__.py
Empty file.
134 changes: 134 additions & 0 deletions tests/node/test_get_configurations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
"""
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_configurations():
"""
Case: get node configurations.
Expect: node public key and address are returned.
"""
runner = CliRunner()
result = runner.invoke(cli, [
'node',
'get-configurations',
'--node-url',
LATEST_RELEASE_NODE_IP_ADDRESS_FOR_TESTING,
])

expected_node_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_configurations_without_node_url(mocker):
"""
Case: get node configurations without passing node URL.
Expect: batch identifier is returned from node on localhost.
"""
expected_node_configurations = {
'node_address': None,
'node_public_key': None,
}

mock_account_transfer_tokens = mocker.patch('cli.node.service.Node.get_configurations')
mock_account_transfer_tokens.return_value = expected_node_configurations, None

runner = CliRunner()
result = runner.invoke(cli, [
'node',
'get-configurations',
])

assert PASSED_EXIT_FROM_COMMAND_CODE == result.exit_code
assert expected_node_configurations == json.loads(result.output)


def test_get_node_configurations_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-configurations',
'--node-url',
invalid_node_url,
])

expected_error = {
'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_configurations_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-configurations',
'--node-url',
node_url_with_http_protocol,
])

expected_error = {
'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_configurations_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-configurations',
'--node-url',
node_url_with_https_protocol,
])

expected_error = {
'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

0 comments on commit add326a

Please sign in to comment.