Skip to content

Commit

Permalink
Add tests + PR requests
Browse files Browse the repository at this point in the history
  • Loading branch information
ramirezfranciscof committed Oct 4, 2021
1 parent f19f1e8 commit c2c64b1
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 7 deletions.
4 changes: 4 additions & 0 deletions aiida/backends/general/migrations/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ def uuid(self) -> Optional[str]:
"""
return None

@property
def key_format(self) -> Optional[str]:
return None

def initialise(self, **kwargs) -> None:
raise NotImplementedError()

Expand Down
12 changes: 11 additions & 1 deletion aiida/repository/backend/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ class AbstractRepositoryBackend(metaclass=abc.ABCMeta):
def uuid(self) -> Optional[str]:
"""Return the unique identifier of the repository."""

@property
@abc.abstractmethod
def key_format(self) -> Optional[str]:
"""Return the format for the keys of the repository.
Important for when migrating between backends (e.g. archive -> main), as if they are not equal then it is
necessary to re-compute all the `Node.repository_metadata` before importing (otherwise they will not match
with the repository).
"""

@abc.abstractmethod
def initialise(self, **kwargs) -> None:
"""Initialise the repository if it hasn't already been initialised.
Expand Down Expand Up @@ -104,7 +114,7 @@ def has_object(self, key: str) -> bool:

@abc.abstractmethod
def list_objects(self) -> Iterable[str]:
"""Return iterable that yeilds all available objects by key.
"""Return iterable that yields all available objects by key.
:return: An iterable for all the available object keys.
"""
Expand Down
4 changes: 4 additions & 0 deletions aiida/repository/backend/disk_object_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ def uuid(self) -> Optional[str]:
return None
return self.container.container_id

@property
def key_format(self) -> Optional[str]:
return self.container.hash_type

def initialise(self, **kwargs) -> None:
"""Initialise the repository if it hasn't already been initialised.
Expand Down
4 changes: 4 additions & 0 deletions aiida/repository/backend/sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ def uuid(self) -> Optional[str]:
"""
return None

@property
def key_format(self) -> Optional[str]:
return 'uuid4'

def initialise(self, **kwargs) -> None:
"""Initialise the repository if it hasn't already been initialised.
Expand Down
48 changes: 42 additions & 6 deletions tests/repository/backend/test_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@
class RepositoryBackend(AbstractRepositoryBackend):
"""Concrete implementation of ``AbstractRepositoryBackend``."""

def has_object(self, key):
return True

@property
def uuid(self) -> Optional[str]:
return None

@property
def key_format(self) -> Optional[str]:
return None

def initialise(self, **kwargs) -> None:
return

Expand All @@ -33,11 +34,14 @@ def is_initialised(self) -> bool:
def _put_object_from_filelike(self, handle: BinaryIO) -> str:
pass

def delete_objects(self, keys: List[str]) -> None:
pass
# pylint useless-super-delegation needs to be disabled here because it refuses to
# recognize that this is an abstract method and thus has to be overriden. See the
# following issue: https://github.com/PyCQA/pylint/issues/1594
def delete_objects(self, keys: List[str]) -> None: # pylint: disable=useless-super-delegation
super().delete_objects(keys)

def has_objects(self, keys: List[str]) -> List[bool]:
pass
return [True]

def list_objects(self) -> Iterable[str]:
pass
Expand Down Expand Up @@ -93,3 +97,35 @@ def test_put_object_from_file(repository, generate_directory):

repository.put_object_from_file(directory / 'file_a')
repository.put_object_from_file(str(directory / 'file_a'))


def test_passes_to_batch(repository, monkeypatch):
"""Checks that the single object operations call the batch operations"""

def mock_batch_operation(self, keys):
raise NotImplementedError('this method was intentionally not implemented')

monkeypatch.setattr(RepositoryBackend, 'has_objects', mock_batch_operation)
with pytest.raises(NotImplementedError) as execinfo:
repository.has_object('object_key')
assert str(execinfo.value) == 'this method was intentionally not implemented'

monkeypatch.undo()

monkeypatch.setattr(RepositoryBackend, 'delete_objects', mock_batch_operation)
with pytest.raises(NotImplementedError) as execinfo:
repository.delete_object('object_key')
assert str(execinfo.value) == 'this method was intentionally not implemented'


def test_delete_objects_test(repository, monkeypatch):
"""Checks that the super of delete_objects will check for existence of the files"""

def has_objects_mock(self, keys): # pylint: disable=unused-argument
return [False for key in keys]

monkeypatch.setattr(RepositoryBackend, 'has_objects', has_objects_mock)
with pytest.raises(FileNotFoundError) as execinfo:
repository.delete_objects(['object_key'])
assert 'exist' in str(execinfo.value)
assert 'object_key' in str(execinfo.value)
22 changes: 22 additions & 0 deletions tests/repository/backend/test_disk_object_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,25 @@ def test_get_object_hash(repository, generate_directory):
key = repository.put_object_from_filelike(handle)

assert repository.get_object_hash(key) == 'ed7002b439e9ac845f22357d822bac1444730fbdb6016d3ec9432297b9ec9f73'


def test_list_objects(repository, generate_directory):
"""Test the ``Repository.delete_object`` method."""
repository.initialise()
keylist = list()

directory = generate_directory({'file_a': b'content a'})
with open(directory / 'file_a', 'rb') as handle:
keylist.append(repository.put_object_from_filelike(handle))

directory = generate_directory({'file_b': b'content b'})
with open(directory / 'file_b', 'rb') as handle:
keylist.append(repository.put_object_from_filelike(handle))

assert sorted(list(repository.list_objects())) == sorted(keylist)


def test_key_format(repository):
"""Test the ``key_format`` property."""
repository.initialise()
assert repository.key_format == repository.container.hash_type
22 changes: 22 additions & 0 deletions tests/repository/backend/test_sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,25 @@ def test_get_object_hash(repository, generate_directory):
key = repository.put_object_from_filelike(handle)

assert repository.get_object_hash(key) == 'ed7002b439e9ac845f22357d822bac1444730fbdb6016d3ec9432297b9ec9f73'


def test_list_objects(repository, generate_directory):
"""Test the ``Repository.delete_object`` method."""
repository.initialise()
keylist = list()

directory = generate_directory({'file_a': b'content a'})
with open(directory / 'file_a', 'rb') as handle:
keylist.append(repository.put_object_from_filelike(handle))

directory = generate_directory({'file_b': b'content b'})
with open(directory / 'file_b', 'rb') as handle:
keylist.append(repository.put_object_from_filelike(handle))

assert sorted(list(repository.list_objects())) == sorted(keylist)


def test_key_format(repository):
"""Test the ``key_format`` property."""
repository.initialise()
assert repository.key_format == 'uuid4'

0 comments on commit c2c64b1

Please sign in to comment.