Skip to content

Commit

Permalink
feat(core): raise proper errors when Renku metadata is corrupt (#3393)
Browse files Browse the repository at this point in the history
  • Loading branch information
Panaetius committed Apr 28, 2023
1 parent 32d6e55 commit bb0a39a
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 2 deletions.
14 changes: 13 additions & 1 deletion renku/core/errors.py
Expand Up @@ -708,7 +708,19 @@ class NotebookSessionImageNotExistError(RenkuException):


class MetadataMergeError(RenkuException):
"""Raise when merging of metadata failed."""
"""Raised when merging of metadata failed."""


class MetadataCorruptError(RenkuException):
"""Raised when metadata is corrupt and couldn't be loaded."""

def __init__(self, path: Union[str, Path]) -> None:
message = f"Metadata file '{path}' couldn't be loaded because it is corrupted."
with open(path) as f:
content = f.read()
if all(pattern in content for pattern in ["<<<<<<<", "=======", ">>>>>>>"]):
message += "\nThis is likely due to an unresolved git merge conflict in the file."
super().__init__(message)


class MinimumVersionError(RenkuException):
Expand Down
5 changes: 4 additions & 1 deletion renku/infrastructure/database.py
Expand Up @@ -833,7 +833,10 @@ def load(self, filename: str, absolute: bool = False):
with self.zstd_decompressor.stream_reader(file) as zfile:
data = json.load(zfile)
else:
data = json.load(file)
try:
data = json.load(file)
except json.JSONDecodeError:
raise errors.MetadataCorruptError(path)
return data


Expand Down
15 changes: 15 additions & 0 deletions renku/ui/service/errors.py
Expand Up @@ -301,6 +301,21 @@ def __init__(self, exception=None):
super().__init__(exception=exception)


class UserProjectMetadataCorruptError(ServiceError):
"""The metadata in the project os corrupt and couldn't be loaded."""

code = SVC_ERROR_USER + 120
userMessage = "The Renku metadata in the project is corrupt and couldn't be loaded: {error_message}"
devMessage = "Couldn't parse project metadata due to a JSON parsing error: {error_message}"

def __init__(self, exception=None, error_message=ERROR_NOT_AVAILABLE):
super().__init__(
userMessage=self.userMessage.format(error_message=error_message),
devMessage=self.devMessage.format(error_message=error_message),
exception=exception,
)


class UserDatasetsMultipleImagesError(ServiceError):
"""Multiple images dataset have the same priority."""

Expand Down
4 changes: 4 additions & 0 deletions renku/ui/service/views/error_handlers.py
Expand Up @@ -33,6 +33,7 @@
GitCommandError,
GitError,
InvalidTemplateError,
MetadataCorruptError,
MigrationError,
MigrationRequired,
MinimumVersionError,
Expand Down Expand Up @@ -73,6 +74,7 @@
UserNonRenkuProjectError,
UserOutdatedProjectError,
UserProjectCreationError,
UserProjectMetadataCorruptError,
UserProjectTemplateReferenceError,
UserRepoBranchInvalidError,
UserRepoNoAccessError,
Expand Down Expand Up @@ -146,6 +148,8 @@ def decorated_function(*args, **kwargs):
"""Represents decorated function."""
try:
return f(*args, **kwargs)
except MetadataCorruptError as e:
raise UserProjectMetadataCorruptError(e, str(e))
except MigrationRequired as e:
raise UserOutdatedProjectError(e)
except UninitializedProject as e:
Expand Down
25 changes: 25 additions & 0 deletions tests/core/metadata/test_database.py
Expand Up @@ -21,6 +21,7 @@
from persistent.list import PersistentList
from persistent.mapping import PersistentMapping

from renku.core import errors
from renku.domain_model.entity import Entity
from renku.domain_model.provenance.activity import Activity, Usage
from renku.domain_model.workflow.plan import Plan
Expand Down Expand Up @@ -414,3 +415,27 @@ def test_database_immutable_object(database):

assert isinstance(usage_1, Usage)
assert usage_1 is usage_2


@pytest.mark.parametrize(
"content,error_message",
[
("{'a':<' ' b}", ".*file' couldn't be loaded because it is corrupted.$"),
(
"{'name': \n<<<<<<< HEAD:file\n'a'\n=======\n'b'\n>>>>>>> abcdefg:file\n}",
".*file' couldn't be loaded because it is corrupted.\n"
"This is likely due to an unresolved git merge conflict in the file.$",
),
],
)
def test_database_corrupt_metadata(tmpdir, content, error_message):
"""Test raising correct error for corrupt metadata."""
from renku.infrastructure.database import Storage

storage = Storage(tmpdir)

with open(storage.path / "file", "w") as f:
f.write(content)

with pytest.raises(expected_exception=errors.MetadataCorruptError, match=error_message):
storage.load("file")

0 comments on commit bb0a39a

Please sign in to comment.