2018-11-04 19:23:11 +00:00
|
|
|
|
2022-03-24 20:17:34 +00:00
|
|
|
|
|
|
|
|
2020-08-31 17:10:43 +00:00
|
|
|
import random
|
2022-03-22 20:06:54 +00:00
|
|
|
import socket
|
|
|
|
import time
|
|
|
|
from pathlib import Path
|
2020-01-12 21:57:09 +00:00
|
|
|
|
2019-02-15 01:32:11 +00:00
|
|
|
import requests
|
2019-11-10 10:57:40 +00:00
|
|
|
from flask import Response
|
2021-12-25 20:56:36 +00:00
|
|
|
from nucypher_core import MetadataRequest, FleetStateChecksum
|
2021-10-11 23:42:03 +00:00
|
|
|
|
2020-05-13 03:23:33 +00:00
|
|
|
from nucypher.characters.lawful import Ursula
|
|
|
|
from nucypher.network.middleware import NucypherMiddlewareClient, RestMiddleware
|
2020-05-13 18:24:36 +00:00
|
|
|
from tests.utils.ursula import MOCK_KNOWN_URSULAS_CACHE
|
2020-05-13 03:23:33 +00:00
|
|
|
|
2019-02-05 04:21:50 +00:00
|
|
|
|
2020-08-24 14:08:05 +00:00
|
|
|
class BadTestUrsulas(RuntimeError):
|
|
|
|
crash_right_now = True
|
|
|
|
|
|
|
|
|
2019-11-10 10:57:40 +00:00
|
|
|
class _TestMiddlewareClient(NucypherMiddlewareClient):
|
2019-02-15 15:48:27 +00:00
|
|
|
timeout = None
|
|
|
|
|
2019-02-05 04:21:50 +00:00
|
|
|
@staticmethod
|
|
|
|
def response_cleaner(response):
|
|
|
|
response.content = response.data
|
|
|
|
return response
|
2019-02-05 03:32:18 +00:00
|
|
|
|
2018-09-13 19:26:25 +00:00
|
|
|
def _get_mock_client_by_ursula(self, ursula):
|
2019-06-17 08:41:10 +00:00
|
|
|
port = ursula.rest_interface.port
|
2018-09-13 19:26:25 +00:00
|
|
|
return self._get_mock_client_by_port(port)
|
|
|
|
|
|
|
|
def _get_mock_client_by_url(self, url):
|
|
|
|
port = int(url.split(":")[1])
|
|
|
|
return self._get_mock_client_by_port(port)
|
|
|
|
|
2019-02-05 23:53:48 +00:00
|
|
|
def _get_mock_client_by_port(self, port):
|
|
|
|
ursula = self._get_ursula_by_port(port)
|
|
|
|
rest_app = ursula.rest_app
|
|
|
|
rest_app.testing = True
|
|
|
|
mock_client = rest_app.test_client()
|
|
|
|
return mock_client
|
|
|
|
|
2018-10-23 16:49:43 +00:00
|
|
|
def _get_ursula_by_port(self, port):
|
2020-07-24 23:00:19 +00:00
|
|
|
mkuc = MOCK_KNOWN_URSULAS_CACHE
|
2018-09-13 19:26:25 +00:00
|
|
|
try:
|
2020-07-24 23:00:19 +00:00
|
|
|
return mkuc[port]
|
2018-09-13 19:26:25 +00:00
|
|
|
except KeyError:
|
2020-08-24 14:08:05 +00:00
|
|
|
raise BadTestUrsulas(
|
2018-09-13 19:26:25 +00:00
|
|
|
"Can't find an Ursula with port {} - did you spin up the right test ursulas?".format(port))
|
2018-10-23 16:49:43 +00:00
|
|
|
|
2020-07-10 05:26:10 +00:00
|
|
|
def parse_node_or_host_and_port(self, node=None, host=None, port=None):
|
2019-02-05 04:21:17 +00:00
|
|
|
if node:
|
|
|
|
if any((host, port)):
|
|
|
|
raise ValueError("Don't pass host and port if you are passing the node.")
|
2019-02-05 23:54:13 +00:00
|
|
|
mock_client = self._get_mock_client_by_ursula(node)
|
2019-02-05 04:21:17 +00:00
|
|
|
elif all((host, port)):
|
|
|
|
node = self._get_ursula_by_port(port)
|
2019-02-05 23:54:13 +00:00
|
|
|
mock_client = self._get_mock_client_by_port(port)
|
2019-02-05 04:21:17 +00:00
|
|
|
else:
|
|
|
|
raise ValueError("You need to pass either the node or a host and port.")
|
2022-03-22 20:06:54 +00:00
|
|
|
host, port = node.rest_interface.host, node.rest_interface.port
|
|
|
|
return host, port, mock_client
|
2019-02-05 04:21:17 +00:00
|
|
|
|
|
|
|
def invoke_method(self, method, url, *args, **kwargs):
|
2019-02-06 05:28:37 +00:00
|
|
|
_cert_location = kwargs.pop("verify") # TODO: Is this something that can be meaningfully tested?
|
2019-02-05 04:21:17 +00:00
|
|
|
kwargs.pop("timeout", None) # Just get rid of timeout; not needed for the test client.
|
2019-02-06 05:28:37 +00:00
|
|
|
response = super().invoke_method(method, url, *args, **kwargs)
|
2019-02-05 04:21:17 +00:00
|
|
|
return response
|
|
|
|
|
2019-02-05 23:54:26 +00:00
|
|
|
def clean_params(self, request_kwargs):
|
|
|
|
request_kwargs["query_string"] = request_kwargs.pop("params", {})
|
|
|
|
|
2022-03-22 20:06:54 +00:00
|
|
|
def get_certificate(self, port, *args, **kwargs):
|
|
|
|
ursula = self._get_ursula_by_port(port)
|
|
|
|
return ursula.certificate, Path()
|
|
|
|
|
2019-02-05 03:46:06 +00:00
|
|
|
|
|
|
|
class MockRestMiddleware(RestMiddleware):
|
|
|
|
_ursulas = None
|
|
|
|
|
2019-12-13 02:23:50 +00:00
|
|
|
_client_class = _TestMiddlewareClient
|
2019-02-05 03:46:06 +00:00
|
|
|
|
|
|
|
class NotEnoughMockUrsulas(Ursula.NotEnoughUrsulas):
|
|
|
|
pass
|
|
|
|
|
2018-09-13 19:26:25 +00:00
|
|
|
|
2019-11-10 10:57:40 +00:00
|
|
|
class MockRestMiddlewareForLargeFleetTests(MockRestMiddleware):
|
|
|
|
"""
|
|
|
|
A MockRestMiddleware with workaround necessary to test the conditions that arise with thousands of nodes.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def get_nodes_via_rest(self,
|
|
|
|
node,
|
2021-10-11 23:42:03 +00:00
|
|
|
fleet_state_checksum,
|
|
|
|
announce_nodes=None):
|
|
|
|
response_bytes = node.bytestring_of_known_nodes()
|
|
|
|
r = Response(response_bytes)
|
2019-11-10 10:57:40 +00:00
|
|
|
r.content = r.data
|
|
|
|
return r
|
|
|
|
|
|
|
|
|
2020-05-13 02:29:29 +00:00
|
|
|
class SluggishLargeFleetMiddleware(MockRestMiddlewareForLargeFleetTests):
|
|
|
|
"""
|
|
|
|
Similar to above, but with added delay to simulate network latency.
|
|
|
|
"""
|
2020-05-16 00:07:18 +00:00
|
|
|
def put_treasure_map_on_node(self, node, *args, **kwargs):
|
2020-08-31 17:10:43 +00:00
|
|
|
time.sleep(random.randrange(5, 15) / 100)
|
2020-05-16 00:07:18 +00:00
|
|
|
result = super().put_treasure_map_on_node(node=node, *args, **kwargs)
|
2020-08-31 17:10:43 +00:00
|
|
|
time.sleep(random.randrange(5, 15) / 100)
|
2020-05-16 00:07:18 +00:00
|
|
|
return result
|
2020-05-13 02:29:29 +00:00
|
|
|
|
|
|
|
|
2019-02-15 01:32:11 +00:00
|
|
|
class _MiddlewareClientWithConnectionProblems(_TestMiddlewareClient):
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.ports_that_are_down = set()
|
|
|
|
self.certs_are_broken = False
|
|
|
|
|
|
|
|
def _get_ursula_by_port(self, port):
|
|
|
|
if port in self.ports_that_are_down:
|
|
|
|
raise ConnectionRefusedError
|
|
|
|
else:
|
|
|
|
return super()._get_ursula_by_port(port)
|
|
|
|
|
|
|
|
def get(self, *args, **kwargs):
|
|
|
|
if kwargs.get("path") == "public_information":
|
|
|
|
if self.certs_are_broken:
|
|
|
|
raise requests.exceptions.SSLError
|
|
|
|
port = kwargs.get("port")
|
|
|
|
if port in self.ports_that_are_down:
|
|
|
|
raise socket.gaierror
|
|
|
|
|
|
|
|
real_get = super(_TestMiddlewareClient, self).__getattr__("get")
|
|
|
|
return real_get(*args, **kwargs)
|
|
|
|
|
|
|
|
|
2019-02-14 19:44:38 +00:00
|
|
|
class NodeIsDownMiddleware(MockRestMiddleware):
|
|
|
|
"""
|
|
|
|
Modified middleware to emulate one node being down amongst many.
|
|
|
|
"""
|
2019-11-10 10:57:40 +00:00
|
|
|
|
2019-02-15 01:32:11 +00:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.client = _MiddlewareClientWithConnectionProblems()
|
2019-02-14 19:44:38 +00:00
|
|
|
|
2019-02-15 01:32:11 +00:00
|
|
|
def node_is_down(self, node):
|
2019-06-17 08:41:10 +00:00
|
|
|
self.client.ports_that_are_down.add(node.rest_interface.port)
|
2019-02-15 01:32:11 +00:00
|
|
|
|
|
|
|
def node_is_up(self, node):
|
2019-06-17 08:41:10 +00:00
|
|
|
self.client.ports_that_are_down.remove(node.rest_interface.port)
|
2019-02-14 19:44:38 +00:00
|
|
|
|
2019-09-26 22:55:16 +00:00
|
|
|
def all_nodes_up(self):
|
|
|
|
self.client.ports_that_are_down = set()
|
|
|
|
|
|
|
|
def all_nodes_down(self):
|
|
|
|
self.client.ports_that_are_down = set(MOCK_KNOWN_URSULAS_CACHE)
|
|
|
|
|
|
|
|
|
2018-09-13 19:26:25 +00:00
|
|
|
class EvilMiddleWare(MockRestMiddleware):
|
|
|
|
"""
|
|
|
|
Middleware for assholes.
|
|
|
|
"""
|
2018-10-23 16:45:43 +00:00
|
|
|
|
2021-10-11 23:42:03 +00:00
|
|
|
def propagate_shitty_interface_id(self, ursula, shitty_metadata):
|
2018-09-13 19:26:25 +00:00
|
|
|
"""
|
|
|
|
Try to get Ursula to propagate a malicious (or otherwise shitty) interface ID.
|
|
|
|
"""
|
2021-12-25 20:56:36 +00:00
|
|
|
fleet_state_checksum = FleetStateChecksum(this_node=None, other_nodes=[])
|
2021-10-11 23:42:03 +00:00
|
|
|
request = MetadataRequest(fleet_state_checksum=fleet_state_checksum, announce_nodes=[shitty_metadata])
|
2020-10-13 19:22:15 +00:00
|
|
|
response = self.client.post(node_or_sprout=ursula,
|
2019-02-06 04:25:47 +00:00
|
|
|
path="node_metadata",
|
2021-10-11 23:42:03 +00:00
|
|
|
data=bytes(request)
|
2018-11-29 22:26:54 +00:00
|
|
|
)
|
2018-09-23 04:04:40 +00:00
|
|
|
return response
|
2020-03-24 22:14:24 +00:00
|
|
|
|
|
|
|
def upload_arbitrary_data(self, node, path, data):
|
|
|
|
response = self.client.post(node_or_sprout=node,
|
|
|
|
path=path,
|
|
|
|
data=data)
|
2020-05-13 03:21:15 +00:00
|
|
|
return response
|