2018-11-04 19:23:11 +00:00
|
|
|
"""
|
|
|
|
This file is part of nucypher.
|
|
|
|
|
|
|
|
nucypher is free software: you can redistribute it and/or modify
|
2019-03-05 02:50:11 +00:00
|
|
|
it under the terms of the GNU Affero General Public License as published by
|
2018-11-04 19:23:11 +00:00
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
nucypher is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2019-03-05 02:50:11 +00:00
|
|
|
GNU Affero General Public License for more details.
|
2018-11-04 19:23:11 +00:00
|
|
|
|
2019-03-05 02:50:11 +00:00
|
|
|
You should have received a copy of the GNU Affero General Public License
|
2018-11-04 19:23:11 +00:00
|
|
|
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
"""
|
2018-11-16 22:01:40 +00:00
|
|
|
|
2021-01-03 00:52:18 +00:00
|
|
|
import tempfile
|
2018-10-10 02:01:09 +00:00
|
|
|
|
2021-07-29 10:03:31 +00:00
|
|
|
import pytest
|
|
|
|
|
2021-11-30 05:08:49 +00:00
|
|
|
from nucypher_core import NodeMetadata
|
2021-10-14 21:18:08 +00:00
|
|
|
|
2018-10-10 02:01:09 +00:00
|
|
|
from nucypher.characters.lawful import Ursula
|
2021-01-22 19:23:01 +00:00
|
|
|
from nucypher.config.constants import TEMPORARY_DOMAIN
|
2021-07-29 10:03:31 +00:00
|
|
|
from nucypher.config.storages import ForgetfulNodeStorage, TemporaryFileBasedNodeStorage
|
2020-09-21 11:10:32 +00:00
|
|
|
from nucypher.network.nodes import Learner
|
2021-01-25 15:13:55 +00:00
|
|
|
from nucypher.utilities.networking import LOOPBACK_ADDRESS
|
2020-05-13 18:24:36 +00:00
|
|
|
from tests.utils.ursula import MOCK_URSULA_STARTING_PORT
|
2018-10-10 02:01:09 +00:00
|
|
|
|
2020-09-21 11:10:32 +00:00
|
|
|
ADDITIONAL_NODES_TO_LEARN_ABOUT = 10
|
2021-01-03 00:52:18 +00:00
|
|
|
MOCK_URSULA_DB_FILEPATH = tempfile.mkdtemp()
|
2020-09-21 11:10:32 +00:00
|
|
|
|
2018-10-10 02:01:09 +00:00
|
|
|
|
2018-11-16 22:01:40 +00:00
|
|
|
class BaseTestNodeStorageBackends:
|
2018-10-10 02:01:09 +00:00
|
|
|
|
2018-11-16 22:01:40 +00:00
|
|
|
@pytest.fixture(scope='class')
|
|
|
|
def light_ursula(temp_dir_path):
|
2021-01-25 15:13:55 +00:00
|
|
|
node = Ursula(rest_host=LOOPBACK_ADDRESS,
|
2018-12-03 02:47:14 +00:00
|
|
|
rest_port=MOCK_URSULA_STARTING_PORT,
|
|
|
|
db_filepath=MOCK_URSULA_DB_FILEPATH,
|
2021-01-22 19:23:01 +00:00
|
|
|
federated_only=True,
|
|
|
|
domain=TEMPORARY_DOMAIN)
|
2018-12-03 02:47:14 +00:00
|
|
|
yield node
|
2018-10-10 02:01:09 +00:00
|
|
|
|
2018-11-16 22:01:40 +00:00
|
|
|
character_class = Ursula
|
|
|
|
federated_only = True
|
|
|
|
storage_backend = NotImplemented
|
2018-10-10 05:45:30 +00:00
|
|
|
|
2018-11-20 04:29:01 +00:00
|
|
|
def _read_and_write_metadata(self, ursula, node_storage):
|
2018-10-10 05:45:30 +00:00
|
|
|
# Write Node
|
2018-11-20 04:29:01 +00:00
|
|
|
node_storage.store_node_metadata(node=ursula)
|
2018-10-10 05:45:30 +00:00
|
|
|
|
|
|
|
# Read Node
|
2021-06-21 23:19:26 +00:00
|
|
|
node_from_storage = node_storage.get(stamp=ursula.stamp,
|
2018-10-10 05:45:30 +00:00
|
|
|
federated_only=True)
|
|
|
|
assert ursula == node_from_storage, "Node storage {} failed".format(node_storage)
|
|
|
|
|
|
|
|
# Save more nodes
|
|
|
|
all_known_nodes = set()
|
2020-09-21 11:10:32 +00:00
|
|
|
for port in range(MOCK_URSULA_STARTING_PORT, MOCK_URSULA_STARTING_PORT + ADDITIONAL_NODES_TO_LEARN_ABOUT):
|
2021-01-25 15:13:55 +00:00
|
|
|
node = Ursula(rest_host=LOOPBACK_ADDRESS,
|
2021-01-22 19:23:01 +00:00
|
|
|
db_filepath=MOCK_URSULA_DB_FILEPATH,
|
|
|
|
rest_port=port,
|
|
|
|
federated_only=True,
|
|
|
|
domain=TEMPORARY_DOMAIN)
|
2018-11-20 04:29:01 +00:00
|
|
|
node_storage.store_node_metadata(node=node)
|
2018-10-10 05:45:30 +00:00
|
|
|
all_known_nodes.add(node)
|
|
|
|
|
|
|
|
# Read all nodes from storage
|
|
|
|
all_stored_nodes = node_storage.all(federated_only=True)
|
|
|
|
all_known_nodes.add(ursula)
|
2020-09-21 11:10:32 +00:00
|
|
|
assert len(all_known_nodes) == len(all_stored_nodes) == 1 + ADDITIONAL_NODES_TO_LEARN_ABOUT
|
2020-04-15 07:17:11 +00:00
|
|
|
|
2020-04-21 19:44:55 +00:00
|
|
|
known_checksums = sorted(n.checksum_address for n in all_known_nodes)
|
|
|
|
stored_checksums = sorted(n.checksum_address for n in all_stored_nodes)
|
2020-04-15 07:17:11 +00:00
|
|
|
|
|
|
|
assert known_checksums == stored_checksums
|
2018-10-10 05:45:30 +00:00
|
|
|
|
|
|
|
# Read random nodes
|
|
|
|
for i in range(3):
|
|
|
|
random_node = all_known_nodes.pop()
|
2021-06-21 23:19:26 +00:00
|
|
|
random_node_from_storage = node_storage.get(stamp=random_node.stamp, federated_only=True)
|
2019-06-04 15:46:26 +00:00
|
|
|
assert random_node.checksum_address == random_node_from_storage.checksum_address
|
2018-10-10 05:45:30 +00:00
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
#
|
2019-02-14 08:23:48 +00:00
|
|
|
# Storage Backend Tests
|
2018-10-10 05:45:30 +00:00
|
|
|
#
|
2018-10-10 02:01:09 +00:00
|
|
|
|
2018-11-16 22:01:40 +00:00
|
|
|
def test_read_and_write_to_storage(self, light_ursula):
|
2018-11-20 04:29:01 +00:00
|
|
|
assert self._read_and_write_metadata(ursula=light_ursula, node_storage=self.storage_backend)
|
2020-09-21 11:10:32 +00:00
|
|
|
self.storage_backend.clear()
|
2018-10-10 02:01:09 +00:00
|
|
|
|
2018-11-16 22:01:40 +00:00
|
|
|
|
|
|
|
class TestInMemoryNodeStorage(BaseTestNodeStorageBackends):
|
2018-11-20 04:29:01 +00:00
|
|
|
storage_backend = ForgetfulNodeStorage(character_class=BaseTestNodeStorageBackends.character_class,
|
|
|
|
federated_only=BaseTestNodeStorageBackends.federated_only)
|
2018-11-16 22:01:40 +00:00
|
|
|
storage_backend.initialize()
|
|
|
|
|
|
|
|
|
|
|
|
class TestTemporaryFileBasedNodeStorage(BaseTestNodeStorageBackends):
|
|
|
|
storage_backend = TemporaryFileBasedNodeStorage(character_class=BaseTestNodeStorageBackends.character_class,
|
|
|
|
federated_only=BaseTestNodeStorageBackends.federated_only)
|
|
|
|
storage_backend.initialize()
|
2020-09-21 11:10:32 +00:00
|
|
|
|
|
|
|
def test_invalid_metadata(self, light_ursula):
|
|
|
|
self._read_and_write_metadata(ursula=light_ursula, node_storage=self.storage_backend)
|
2021-05-12 12:38:43 +00:00
|
|
|
some_node, another_node, *other = list(self.storage_backend.metadata_dir.iterdir())
|
2020-09-21 11:10:32 +00:00
|
|
|
|
|
|
|
# Let's break the metadata (but not the version)
|
2021-05-11 17:55:13 +00:00
|
|
|
metadata_path = self.storage_backend.metadata_dir / some_node
|
2020-09-21 11:10:32 +00:00
|
|
|
with open(metadata_path, 'wb') as file:
|
2021-10-14 21:18:08 +00:00
|
|
|
file.write(NodeMetadata._header() + b'invalid')
|
2020-09-21 11:10:32 +00:00
|
|
|
|
|
|
|
with pytest.raises(TemporaryFileBasedNodeStorage.InvalidNodeMetadata):
|
2021-07-29 10:03:31 +00:00
|
|
|
self.storage_backend.get(stamp=some_node.name[:-5],
|
2020-09-21 11:10:32 +00:00
|
|
|
federated_only=True,
|
|
|
|
certificate_only=False)
|
|
|
|
|
|
|
|
# Let's break the metadata, by putting a completely wrong version
|
2021-05-11 17:55:13 +00:00
|
|
|
metadata_path = self.storage_backend.metadata_dir / another_node
|
2020-09-21 11:10:32 +00:00
|
|
|
with open(metadata_path, 'wb') as file:
|
2021-10-14 21:18:08 +00:00
|
|
|
full_header = NodeMetadata._header()
|
|
|
|
file.write(full_header[:-1]) # Not even a valid header
|
2020-09-21 11:10:32 +00:00
|
|
|
|
|
|
|
with pytest.raises(TemporaryFileBasedNodeStorage.InvalidNodeMetadata):
|
2021-07-29 10:03:31 +00:00
|
|
|
self.storage_backend.get(stamp=another_node.name[:-5],
|
2020-09-21 11:10:32 +00:00
|
|
|
federated_only=True,
|
|
|
|
certificate_only=False)
|
|
|
|
|
|
|
|
# Since there are 2 broken metadata files, we should get 2 nodes less when reading all
|
|
|
|
restored_nodes = self.storage_backend.all(federated_only=True, certificates_only=False)
|
|
|
|
total_nodes = 1 + ADDITIONAL_NODES_TO_LEARN_ABOUT
|
|
|
|
assert total_nodes - 2 == len(restored_nodes)
|