Skip to content

Commit

Permalink
[explorer/nodewatch] task: refactor and unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
AnthonyLaw committed Apr 10, 2023
1 parent 9688016 commit 214790a
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 111 deletions.
2 changes: 1 addition & 1 deletion explorer/nodewatch/nodewatch/RoutesFacade.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def custom_filter(descriptor):
role_condition = role == descriptor.roles if exact_match else role == (role & descriptor.roles)

if ssl is not None:
ssl_condition = (descriptor.is_https_enabled == ssl and descriptor.is_wss_enabled == ssl)
ssl_condition = (descriptor.is_https_enabled and descriptor.is_wss_enabled)
return role_condition and ssl_condition

return role_condition
Expand Down
29 changes: 15 additions & 14 deletions explorer/nodewatch/nodewatch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ class Field(Enum):
def str_to_bool(value):
if value.lower() == 'true':
return True
if value.lower() == 'false':
return False
return None


Expand Down Expand Up @@ -105,27 +103,30 @@ def symbol_summary(): # pylint: disable=unused-variable
template_name, context = symbol_routes_facade.html_summary()
return render_template(template_name, **context)

def _get_json_nodes(role, exact_match, ssl, limit, order):
if ssl is not None:
ssl = str_to_bool(ssl)

if limit is not None:
limit = int(limit)

return jsonify(symbol_routes_facade.json_nodes(role=role, exact_match=exact_match, ssl=ssl, limit=limit, order=order))

@app.route('/api/symbol/nodes/api')
def api_symbol_nodes_api(): # pylint: disable=unused-variable
return jsonify(symbol_routes_facade.json_nodes(role=2, exact_match=True))
ssl = request.args.get('ssl', None)
limit = request.args.get('limit', None)
order = request.args.get('order', None)

return _get_json_nodes(2, True, ssl, limit, order)

@app.route('/api/symbol/nodes/peer')
def api_symbol_nodes_peer(): # pylint: disable=unused-variable
return jsonify(symbol_routes_facade.json_nodes(role=1))

@app.route('/api/symbol/nodes')
def api_symbol_nodes(): # pylint: disable=unused-variable
ssl = request.args.get('ssl', None)
limit = request.args.get('limit', None)
order = request.args.get('order', None)

if ssl is not None:
ssl = str_to_bool(ssl)

if limit is not None:
limit = int(limit)

return jsonify(symbol_routes_facade.json_nodes(ssl=ssl, limit=limit, order=order))
return _get_json_nodes(1, False, ssl, limit, order)

@app.route('/api/symbol/nodes/mainPublicKey/<main_public_key>')
def api_symbol_nodes_get_main_public_key(main_public_key): # pylint: disable=unused-variable
Expand Down
22 changes: 22 additions & 0 deletions explorer/nodewatch/tests/resources/symbol_nodes.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,5 +135,27 @@
"publicKey": "5B20F8F228FF0E064DB0DE7951155F6F41EF449D0EC10960067C2BF2DCD61874",
"roles": 3,
"version": 16777988
},
{
"apiNodeInfo": {
"isHealth": true,
"isHttpsEnabled": true,
"isWssEnabled": true,
"restVersion": "2.4.2"
},
"extraData": {
"balance": 3155632.471994,
"finalizedHeight": 1486740,
"height": 1486762
},
"friendlyName": "Allnodes251",
"host": "",
"networkGenerationHashSeed": "57F7DA205008026C776CB6AED843393F04CD458E0AA2D9F1D5F31A402072B2D6",
"networkIdentifier": 104,
"nodePublicKey": "F25FDB3CD1A97DDC71A993D124E9BDD6518699F9F4016C29D341F53208D150D8",
"port": 7900,
"publicKey": "C69B5BDE17EEF7449C6D92856C1D295FE02AA3472651F042FB3FC2F771DAAF7B",
"roles": 2,
"version": 16777988
}
]
37 changes: 27 additions & 10 deletions explorer/nodewatch/tests/test_NetworkRepository.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def test_can_load_symbol_node_descriptors(self):

# Assert: descriptors are sorted by name (desc)
self.assertFalse(repository.is_nem)
self.assertEqual(8, len(repository.node_descriptors))
self.assertEqual(9, len(repository.node_descriptors))
self.assertEqual(1486760, repository.estimate_height()) # median
self.assertEqual(1486740, repository.estimate_finalized_height()) # median (nonzero)
self._assert_node_descriptor(
Expand All @@ -154,6 +154,23 @@ def test_can_load_symbol_node_descriptors(self):
has_api=True) # simulates missing host
self._assert_node_descriptor(
repository.node_descriptors[1],
main_address=SymbolAddress('ND44QLRJQWF756VVP7XLTPDUBGXHT6ZFR7PSDQI'),
main_public_key=PublicKey('C69B5BDE17EEF7449C6D92856C1D295FE02AA3472651F042FB3FC2F771DAAF7B'),
node_public_key=PublicKey('F25FDB3CD1A97DDC71A993D124E9BDD6518699F9F4016C29D341F53208D150D8'),
endpoint='',
name='Allnodes251',
height=1486762,
finalized_height=1486740,
version='1.0.3.4',
balance=3155632.471994,
roles=2,
is_healthy=True,
is_https_enabled=True,
is_wss_enabled=True,
rest_version='2.4.2',
has_api=True)
self._assert_node_descriptor(
repository.node_descriptors[2],
main_address=SymbolAddress('NCFJP3DM65U22JI5XZ2P2TBK5BV5MLKAR7334LQ'),
main_public_key=PublicKey('A05329E4E5F068B323653F393CE0E3E6A1EB5056E122457354BA65158FFD33F4'),
node_public_key=PublicKey('FBEAFCB15D2674ECB8DC1CD2C028C4AC0D463489069FDD415F30BB71EAE69864'),
Expand All @@ -170,7 +187,7 @@ def test_can_load_symbol_node_descriptors(self):
rest_version=None,
has_api=True) # old version mapped to 'failure'
self._assert_node_descriptor(
repository.node_descriptors[2],
repository.node_descriptors[3],
main_address=SymbolAddress('NBPQMC4M2MMX2XOCOC3BCZ7N3ALUTRGLYPPQ56Q'),
main_public_key=PublicKey('2784FBE82D8A46C4082519012970CBB42EC3EC83D5DB93963B71FD6C5DA3B072'),
node_public_key=PublicKey('9CBE17EDFC8B333FE6BD3FF9B4D02914D55A9368F318D4CEF0AB4737BA5BB160'),
Expand All @@ -187,7 +204,7 @@ def test_can_load_symbol_node_descriptors(self):
rest_version=None,
has_api=True) # simulates incomplete extraData
self._assert_node_descriptor(
repository.node_descriptors[3],
repository.node_descriptors[4],
main_address=SymbolAddress('NCPPDLXGYBHNPQAXQ6RTNS3T46A7FNTXDFBD43Y'),
main_public_key=PublicKey('7DFB0D690BFFA4A4979C7466C7B669AE8FBAFD419DAA10DE948604CD9BE65F0B'),
node_public_key=PublicKey('D561824BD4E3053C39A8D5A4AB00583A4D99302C541F046D3A1E6FF023006D7C'),
Expand All @@ -204,7 +221,7 @@ def test_can_load_symbol_node_descriptors(self):
rest_version=None,
has_api=True)
self._assert_node_descriptor(
repository.node_descriptors[4],
repository.node_descriptors[5],
main_address=SymbolAddress('NAEONICSHRZATW7XGIVIDPTNHUMQA7N7XQ4EUPQ'),
main_public_key=PublicKey('B26D01FC006EAC09B740A3C8F12C1055AE24AFD3268F0364C92D51800FC07361'),
node_public_key=None,
Expand All @@ -221,7 +238,7 @@ def test_can_load_symbol_node_descriptors(self):
rest_version=None,
has_api=False)
self._assert_node_descriptor(
repository.node_descriptors[5],
repository.node_descriptors[6],
main_address=SymbolAddress('NDLLVJIUHAAV6F5PG5KYSSQXCZDCPXCY4WFA6TQ'),
main_public_key=PublicKey('71F953D3C3D0B7E70E29EC2DE761DD7339BA815C094B3BEE0917AEBD924B37EB'),
node_public_key=PublicKey('C71C7D5E6981DE5ED27908C6749207E49001A0B0F0DD404D07451636A64BEBEB'),
Expand All @@ -238,7 +255,7 @@ def test_can_load_symbol_node_descriptors(self):
rest_version=None,
has_api=True) # simulates missing extraData
self._assert_node_descriptor(
repository.node_descriptors[6],
repository.node_descriptors[7],
main_address=SymbolAddress('NAU6BZUX5GHI7EDE6DMS6GVHXS4XZFCNVRPT2OQ'),
main_public_key=PublicKey('A54CC798373F42B569AF21845CD0EBE755AB42EA04B3B8E2BE897166F89A971C'),
node_public_key=PublicKey('FE7D3DBE8DDD219E1B20247DEBF150D9411EA5A312989103B037EFBD9D237DE0'),
Expand All @@ -255,7 +272,7 @@ def test_can_load_symbol_node_descriptors(self):
rest_version='2.4.2',
has_api=True)
self._assert_node_descriptor(
repository.node_descriptors[7],
repository.node_descriptors[8],
main_address=SymbolAddress('NAOOI6NZA6TZMIKOGAQCQG7SXBPXVSDOTPLLDZY'),
main_public_key=PublicKey('5B20F8F228FF0E064DB0DE7951155F6F41EF449D0EC10960067C2BF2DCD61874'),
node_public_key=PublicKey('D05BE3101F2916AA34839DDC1199BE45092103A9B66172FA3D05911DC041AADA'),
Expand All @@ -278,7 +295,7 @@ def test_can_format_node_descriptor_as_json(self):
repository.load_node_descriptors('tests/resources/symbol_nodes.json')

# Act:
json_object = repository.node_descriptors[4].to_json()
json_object = repository.node_descriptors[5].to_json()

# Assert:
self.assertEqual({
Expand All @@ -303,7 +320,7 @@ def test_can_format_node_descriptor_with_node_public_key_as_json(self):
repository.load_node_descriptors('tests/resources/symbol_nodes.json')

# Act:
json_object = repository.node_descriptors[3].to_json()
json_object = repository.node_descriptors[4].to_json()

# Assert:
self.assertEqual({
Expand All @@ -328,7 +345,7 @@ def test_can_format_node_descriptor_with_api_node_info_as_json(self):
repository.load_node_descriptors('tests/resources/symbol_nodes.json')

# Act:
json_object = repository.node_descriptors[6].to_json()
json_object = repository.node_descriptors[7].to_json()

# Assert:
self.assertEqual({
Expand Down
46 changes: 28 additions & 18 deletions explorer/nodewatch/tests/test_RoutesFacade.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def test_can_reload_all(self):
self.assertEqual(True, result)
self.assertEqual(facade.last_reload_time, facade.last_refresh_time)

self.assertEqual(8, len(facade.repository.node_descriptors))
self.assertEqual(9, len(facade.repository.node_descriptors))
self.assertEqual(4, len(facade.repository.harvester_descriptors))
self.assertEqual(4, len(facade.repository.voter_descriptors))

Expand All @@ -243,7 +243,7 @@ def test_can_skip_reload_when_noop(self):
self.assertEqual([True, False, False], [result1, result2, result3])
self.assertEqual(facade.last_reload_time, facade.last_refresh_time)

self.assertEqual(8, len(facade.repository.node_descriptors))
self.assertEqual(9, len(facade.repository.node_descriptors))
self.assertEqual(4, len(facade.repository.harvester_descriptors))
self.assertEqual(4, len(facade.repository.voter_descriptors))

Expand Down Expand Up @@ -293,9 +293,19 @@ def test_can_render_nodes_html(self):
self.assertEqual(4, len(context))
self.assertEqual('Symbol Nodes', context['title'])
self.assertEqual(
['Allnodes250', 'Apple', 'Shin-Kuma-Node', 'ibone74', 'jaguar', 'symbol.ooo maxUnlockedAccounts:100', 'xym pool', 'yasmine farm'],
[
'Allnodes250',
'Allnodes251',
'Apple',
'Shin-Kuma-Node',
'ibone74',
'jaguar',
'symbol.ooo maxUnlockedAccounts:100',
'xym pool',
'yasmine farm'
],
_get_names(context['descriptors']))
self.assertEqual([104] * 8, _get_network_bytes(context['descriptors']))
self.assertEqual([104] * 9, _get_network_bytes(context['descriptors']))
self.assertIsNotNone(context['version_to_css_class'])
self.assertEqual('<symbol_explorer>', context['explorer_endpoint'])

Expand Down Expand Up @@ -381,12 +391,12 @@ def test_can_generate_nodes_json_filtered(self):
node_descriptors = facade.json_nodes(role=2)

# Assert: spot check names and roles
self.assertEqual(7, len(node_descriptors))
self.assertEqual(8, len(node_descriptors))
self.assertEqual(
['Allnodes250', 'Apple', 'Shin-Kuma-Node', 'ibone74', 'symbol.ooo maxUnlockedAccounts:100', 'xym pool', 'yasmine farm'],
['Allnodes250', 'Allnodes251', 'Apple', 'Shin-Kuma-Node', 'ibone74', 'symbol.ooo maxUnlockedAccounts:100', 'xym pool', 'yasmine farm'],
list(map(lambda descriptor: descriptor['name'], node_descriptors)))
self.assertEqual(
[2, 7, 3, 3, 3, 3, 3],
[2, 2, 7, 3, 3, 3, 3, 3],
list(map(lambda descriptor: descriptor['roles'], node_descriptors)))

def test_can_generate_nodes_json_filtered_exact_match(self):
Expand All @@ -398,12 +408,12 @@ def test_can_generate_nodes_json_filtered_exact_match(self):
node_descriptors = facade.json_nodes(role=2, exact_match=True)

# Assert: spot check names and roles
self.assertEqual(1, len(node_descriptors))
self.assertEqual(2, len(node_descriptors))
self.assertEqual(
['Allnodes250'],
['Allnodes250', 'Allnodes251'],
list(map(lambda descriptor: descriptor['name'], node_descriptors)))
self.assertEqual(
[2],
[2, 2],
list(map(lambda descriptor: descriptor['roles'], node_descriptors)))

def test_can_generate_nodes_json_filtered_ssl(self):
Expand All @@ -415,12 +425,12 @@ def test_can_generate_nodes_json_filtered_ssl(self):
node_descriptors = facade.json_nodes(ssl=True)

# Assert: spot check names and roles
self.assertEqual(1, len(node_descriptors))
self.assertEqual(2, len(node_descriptors))
self.assertEqual(
['xym pool'],
['Allnodes251', 'xym pool'],
list(map(lambda descriptor: descriptor['name'], node_descriptors)))
self.assertEqual(
[3],
[2, 3],
list(map(lambda descriptor: descriptor['roles'], node_descriptors)))

def test_can_generate_nodes_json_filtered_order_random_limit_2(self):
Expand All @@ -432,7 +442,7 @@ def test_can_generate_nodes_json_filtered_order_random_limit_2(self):
node_descriptors = facade.json_nodes(limit=2, order='random')

# returns all nodes
all_node_descriptors = facade.json_nodes(role=1)
all_node_descriptors = facade.json_nodes()

full_node_names = list(map(lambda descriptor: descriptor['name'], all_node_descriptors))
random_node_names = list(map(lambda descriptor: descriptor['name'], node_descriptors))
Expand All @@ -450,7 +460,7 @@ def test_can_generate_node_json_given_main_public_key(self):
# Act: select a node match with main public key
node_descriptors = facade.json_node(
filter_field='mainPublicKey',
public_key="A0AA48B6417BDB1845EB55FB0B1E13255EA8BD0D8FA29AD2D8A906E220571F21"
public_key='A0AA48B6417BDB1845EB55FB0B1E13255EA8BD0D8FA29AD2D8A906E220571F21'
)
expected_node = {
'mainPublicKey': 'A0AA48B6417BDB1845EB55FB0B1E13255EA8BD0D8FA29AD2D8A906E220571F21',
Expand Down Expand Up @@ -480,7 +490,7 @@ def test_can_generate_node_json_given_node_public_key(self):
# Act: select a node match with node public key
node_descriptors = facade.json_node(
filter_field='nodePublicKey',
public_key="D05BE3101F2916AA34839DDC1199BE45092103A9B66172FA3D05911DC041AADA"
public_key='D05BE3101F2916AA34839DDC1199BE45092103A9B66172FA3D05911DC041AADA'
)
expected_node = {
'mainPublicKey': '5B20F8F228FF0E064DB0DE7951155F6F41EF449D0EC10960067C2BF2DCD61874',
Expand All @@ -507,8 +517,8 @@ def test_can_generate_node_json_given_public_key_not_found(self):
facade.reload_all(Path('tests/resources'), True)

# Act:
main_public_key_descriptors = facade.json_node(filter_field='mainPublicKey', public_key="invalidKey")
node_public_key_descriptors = facade.json_node(filter_field='nodePublicKey', public_key="invalidKey")
main_public_key_descriptors = facade.json_node(filter_field='mainPublicKey', public_key='invalidKey')
node_public_key_descriptors = facade.json_node(filter_field='nodePublicKey', public_key='invalidKey')

# Assert:
self.assertIsNone(main_public_key_descriptors)
Expand Down
Loading

0 comments on commit 214790a

Please sign in to comment.