diff --git a/onedocker/repository/onedocker_repository_service.py b/onedocker/repository/onedocker_repository_service.py index 3bb91980..acbd57a5 100644 --- a/onedocker/repository/onedocker_repository_service.py +++ b/onedocker/repository/onedocker_repository_service.py @@ -4,7 +4,9 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from typing import Optional +import json +from dataclasses import asdict +from typing import Any, Dict, Optional from fbpcp.service.storage import StorageService from onedocker.entity.object_metadata import PackageMetadata @@ -16,11 +18,15 @@ def __init__( self, storage_svc: StorageService, package_repository_path: str, + metadata_repository_path: str, ) -> None: self.storage_svc = storage_svc self.package_repo = OneDockerPackageRepository( storage_svc, package_repository_path ) + self.metadata_repo = OneDockerPackageRepository( + storage_svc, metadata_repository_path + ) def upload( self, @@ -29,6 +35,8 @@ def upload( source: str, metadata: Optional[dict] = None, ) -> None: + if metadata: + self._set_metadata(package_name, version, metadata) self.package_repo.upload(package_name, version, source) def download(self, package_name: str, version: str, destination: str) -> None: @@ -38,17 +46,22 @@ def _set_metadata( self, package_name: str, version: str, - metadata: PackageMetadata, + metadata_dict: Dict[Any, Any], ) -> None: - # TODO: T127441856 handle storing metadata - raise NotImplementedError + metadata = PackageMetadata(**metadata_dict) + path = self.metadata_repo._build_package_path(package_name, version) + metadata_json = json.dumps(asdict(metadata)) + self.storage_svc.write(path, metadata_json) def _get_metadata( self, package_name: str, version: str, ) -> PackageMetadata: - raise NotImplementedError + path = self.metadata_repo._build_package_path(package_name, version) + metadata_json = self.storage_svc.read(path) + metadata_dict = json.loads(metadata_json) + return PackageMetadata(**metadata_dict) def archive_package(self, package_name: str, version: str) -> None: # TODO: Archive or delete checksum file associated with the archived package if exists. diff --git a/onedocker/tests/repository/test_onedocker_repository_service.py b/onedocker/tests/repository/test_onedocker_repository_service.py index daf0db5d..de1b8b75 100644 --- a/onedocker/tests/repository/test_onedocker_repository_service.py +++ b/onedocker/tests/repository/test_onedocker_repository_service.py @@ -4,7 +4,10 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import json + import unittest +from dataclasses import asdict from unittest.mock import MagicMock, patch from onedocker.repository.onedocker_repository_service import OneDockerRepositoryService @@ -18,14 +21,17 @@ class TestOneDockerRepositoryService(unittest.TestCase): @patch( "onedocker.repository.onedocker_repository_service.OneDockerPackageRepository" ) - @patch("fbpcp.service.storage_s3.S3StorageService") + @patch("onedocker.repository.onedocker_repository_service.StorageService") def setUp(self, mockStorageService, mockPackageRepoCall) -> None: package_repo_path = "/package_repo_path/" + metadata_repo_path = "/metadata_repo_path/" self.package_repo = MagicMock() - mockPackageRepoCall.return_value = self.package_repo + self.metadata_repo = MagicMock() + mockPackageRepoCall.side_effect = [self.package_repo, self.metadata_repo] self.repo_service = OneDockerRepositoryService( - mockStorageService, package_repo_path + mockStorageService, package_repo_path, metadata_repo_path ) + self.storage_svc = mockStorageService def test_onedocker_repo_service_upload(self) -> None: # Arrange @@ -64,3 +70,42 @@ def test_onedocker_repo_service_archive(self) -> None: self.package_repo.archive_package.assert_called_once_with( self.TEST_PACKAGE_PATH, self.TEST_PACKAGE_VERSION ) + + def test_onedocker_repo_service_set_metadata(self) -> None: + # Arrange + metadata_dict = {"checksum": "checksum_data"} + metadata_json = json.dumps(metadata_dict) + path = "test_metadata_path" + self.metadata_repo._build_package_path.return_value = path + # Act + self.repo_service._set_metadata( + self.TEST_PACKAGE_NAME, self.TEST_PACKAGE_VERSION, metadata_dict + ) + # Assert + self.storage_svc.write.assert_called_once_with(path, metadata_json) + + def test_onedocker_repo_service_set_metadata_fail(self) -> None: + # Arrange + metadata_dict = {"checksum": "checksum_data", "not_a_valid_field": "some_data"} + path = "test_metadata_path" + self.metadata_repo._build_package_path.return_value = path + # Act & Assert + with self.assertRaises(TypeError): + self.repo_service._set_metadata( + self.TEST_PACKAGE_NAME, self.TEST_PACKAGE_VERSION, metadata_dict + ) + + def test_onedocker_repo_service_get_metadata(self) -> None: + # Arrange + metadata_dict = {"checksum": "checksum_data"} + metadata_json = json.dumps(metadata_dict) + path = "test_metadata_path" + self.metadata_repo._build_package_path.return_value = path + self.storage_svc.read.return_value = metadata_json + # Act + result = self.repo_service._get_metadata( + self.TEST_PACKAGE_NAME, self.TEST_PACKAGE_VERSION + ) + # Assert + self.storage_svc.read.assert_called_once_with(path) + self.assertEqual(asdict(result), metadata_dict)