Skip to content

Commit

Permalink
Include manifest.json data when adding a file to a request
Browse files Browse the repository at this point in the history
  • Loading branch information
rebkwok committed May 8, 2024
1 parent c5bf94c commit cef709b
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 8 deletions.
22 changes: 14 additions & 8 deletions airlock/business_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,16 +270,19 @@ def get_manifest_data(self):
try:
return json.loads(manifest_path.read_text())
except json.JSONDecodeError:
raise BusinessLogicLayer.FileNotFound(
raise BusinessLogicLayer.ManifestFileError(
"Could not parse manifest.json file: {manifest_path}:\n{exc}"
)

def get_manifest_for_file(self, relpath):
def get_manifest_for_file(self, relpath: UrlPath):
manifest_data = self.get_manifest_data()
# TODO
# Handle keyerror
# Check if key == relpath
return manifest_data["outputs"][relpath]
abspath = str(self.abspath(relpath))
try:
return manifest_data["outputs"][abspath]
except KeyError:
raise BusinessLogicLayer.ManifestFileError(
f"Could not parse data for {abspath} from manifest.json file"
)

def abspath(self, relpath):
"""Get absolute path for file
Expand Down Expand Up @@ -321,7 +324,7 @@ def from_workspace(cls, workspace: Workspace, commit: str):
try:
manifest = workspace.get_manifest_data()
repo = manifest["repo"]
except (BusinessLogicLayer.FileNotFound, KeyError):
except (BusinessLogicLayer.ManifestFileError, KeyError):
raise cls.RepoNotFound(
"Could not parse manifest.json file: {manifest_path}:\n{exc}"
)
Expand Down Expand Up @@ -815,6 +818,9 @@ class RequestPermissionDenied(APIException):
class ApprovalPermissionDenied(APIException):
pass

class ManifestFileError(APIException):
pass

def get_workspace(self, name: str, user: User) -> Workspace:
"""Get a workspace object."""

Expand Down Expand Up @@ -1144,7 +1150,7 @@ def add_file_to_request(
filetype=filetype.name,
)

manifest = workspace.get_manifest_for_file(relpath)
manifest = workspace.get_manifest_for_file(str(relpath))
assert (
manifest["content_hash"] == file_id
), "File hash does not match manifest.json"
Expand Down
73 changes: 73 additions & 0 deletions tests/unit/test_business_logic.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import inspect
import json
from hashlib import file_digest
from io import BytesIO
from pathlib import Path
from unittest.mock import MagicMock, Mock, patch

Expand Down Expand Up @@ -70,6 +72,25 @@ def test_workspace_request_filetype(bll):
assert workspace.request_filetype("foo/bar.txt") is None


def test_workspace_manifest_for_file():
workspace = factories.create_workspace("workspace")
factories.write_workspace_file(workspace, "foo/bar.csv", "c1,c2,c3\n1,2,3\n4,5,6")
file_manifest = workspace.get_manifest_for_file(UrlPath("foo/bar.csv"))
assert file_manifest["row_count"] == 2
assert file_manifest["col_count"] == 3


def test_workspace_manifest_for_file_not_found():
workspace = factories.create_workspace("workspace")
factories.write_workspace_file(workspace, "foo/bar.txt")
manifest_path = workspace.root() / "metadata/manifest.json"
manifest_data = json.loads(manifest_path.read_text())
manifest_data["outputs"] = {}
manifest_path.write_text(json.dumps(manifest_data))
with pytest.raises(BusinessLogicLayer.ManifestFileError):
workspace.get_manifest_for_file(UrlPath("foo/bar.txt"))


def test_request_container(mock_notifications):
release_request = factories.create_release_request("workspace", id="id")
factories.write_request_file(release_request, "group", "bar.html")
Expand All @@ -86,6 +107,58 @@ def test_request_container(mock_notifications):
assert_no_notifications(mock_notifications)


def test_request_file_manifest_data(mock_notifications, bll):
workspace = factories.create_workspace("workspace")
factories.write_workspace_file(workspace, "bar.txt")
user = factories.create_user(workspaces=["workspace"])
release_request = factories.create_release_request(workspace, user=user)

# modify the manifest data to known values for asserts
manifest_path = workspace.root() / "metadata/manifest.json"
manifest_data = json.loads(manifest_path.read_text())
file_manifest = manifest_data["outputs"][str(workspace.root() / "bar.txt")]
file_manifest.update(
{
"job_id": "job-bar",
"size": 10,
"commit": "abcd",
"timestamp": 1715000000,
}
)
manifest_path.write_text(json.dumps(manifest_data))

bll.add_file_to_request(release_request, UrlPath("bar.txt"), user, "group")

request_file = release_request.filegroups["group"].files[UrlPath("bar.txt")]
assert request_file.timestamp == 1715000000
assert request_file.commit == "abcd"
assert request_file.job_id == "job-bar"
assert request_file.size == 10
assert request_file.row_count is None
assert request_file.col_count is None


def test_request_file_manifest_data_content_hash_mismatch(mock_notifications, bll):
workspace = factories.create_workspace("workspace")
factories.write_workspace_file(workspace, "bar.txt")
user = factories.create_user(workspaces=["workspace"])
release_request = factories.create_release_request(workspace, user=user)

# modify the manifest data to known values for asserts
manifest = workspace.root() / "metadata/manifest.json"
manifest_data = json.loads(manifest.read_text())
file_manifest = manifest_data["outputs"][str(workspace.root() / "bar.txt")]
file_manifest.update(
{
"content_hash": file_digest(BytesIO(b"foo"), "sha256").hexdigest(),
}
)
manifest.write_text(json.dumps(manifest_data))

with pytest.raises(AssertionError):
bll.add_file_to_request(release_request, UrlPath("bar.txt"), user, "group")


def test_code_repo_container():
repo = factories.create_repo("workspace")

Expand Down

0 comments on commit cef709b

Please sign in to comment.