diff --git a/onedocker/repository/onedocker_metadata_service.py b/onedocker/repository/onedocker_metadata_service.py new file mode 100644 index 00000000..d4e0a874 --- /dev/null +++ b/onedocker/repository/onedocker_metadata_service.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# 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 Any, Dict + +from fbpcp.service.storage import StorageService +from onedocker.entity.object_metadata import PackageMetadata + + +class OneDockerMetadataService: + def __init__( + self, + storage_svc: StorageService, + ) -> None: + self.storage_svc = storage_svc + + def set_metadata(self, package_path: str, metadata_dict: Dict[Any, Any]) -> None: + raise NotImplementedError + + def get_metadata(self, package_path: str) -> PackageMetadata: + raise NotImplementedError diff --git a/onedocker/repository/onedocker_repository_service.py b/onedocker/repository/onedocker_repository_service.py index 2c18d8d0..7166c37d 100644 --- a/onedocker/repository/onedocker_repository_service.py +++ b/onedocker/repository/onedocker_repository_service.py @@ -4,10 +4,11 @@ # 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 +from typing import Any, Dict, Optional from fbpcp.service.storage import StorageService from onedocker.entity.object_metadata import PackageMetadata +from onedocker.repository.onedocker_metadata_service import OneDockerMetadataService from onedocker.repository.onedocker_package import OneDockerPackageRepository DEFAULT_PROD_VERSION = "latest" @@ -23,6 +24,7 @@ def __init__( self.package_repo = OneDockerPackageRepository( storage_svc, package_repository_path ) + self.metadata_svc = OneDockerMetadataService(storage_svc) def upload( self, @@ -38,6 +40,8 @@ def upload( f"Version {version} already exists. Please specify another version." ) self.package_repo.upload(package_name, version, source) + if metadata: + self._set_metadata(package_name, version, metadata) def download(self, package_name: str, version: str, destination: str) -> None: self.package_repo.download(package_name, version, destination) @@ -46,17 +50,18 @@ def _set_metadata( self, package_name: str, version: str, - metadata: PackageMetadata, + metadata_dict: Dict[Any, Any], ) -> None: - # TODO: T127441856 handle storing metadata - raise NotImplementedError + path = self.package_repo._build_package_path(package_name, version) + self.metadata_svc.set_metadata(path, metadata_dict) def _get_metadata( self, package_name: str, version: str, ) -> PackageMetadata: - raise NotImplementedError + path = self.package_repo._build_package_path(package_name, version) + return self.metadata_svc.get_metadata(path) 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_metadata_service.py b/onedocker/tests/repository/test_onedocker_metadata_service.py new file mode 100644 index 00000000..e0adb57f --- /dev/null +++ b/onedocker/tests/repository/test_onedocker_metadata_service.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import unittest +from unittest.mock import patch + +from onedocker.repository.onedocker_metadata_service import OneDockerMetadataService + + +class TestOneDockerMetadataService(unittest.TestCase): + @patch("onedocker.repository.onedocker_metadata_service.StorageService") + def setUp(self, mockStorageService): + self.repo_service = OneDockerMetadataService(mockStorageService) + + def test_set_metadata(self): + pass + + def test_get_metadata(self): + pass diff --git a/onedocker/tests/repository/test_onedocker_repository_service.py b/onedocker/tests/repository/test_onedocker_repository_service.py index dc1271e6..c620e0d5 100644 --- a/onedocker/tests/repository/test_onedocker_repository_service.py +++ b/onedocker/tests/repository/test_onedocker_repository_service.py @@ -4,6 +4,8 @@ # 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 unittest.mock import MagicMock, patch @@ -18,17 +20,21 @@ class TestOneDockerRepositoryService(unittest.TestCase): TEST_PACKAGE_NAME = TEST_PACKAGE_PATH.split("/")[-1] TEST_PACKAGE_VERSION = "1.0" + @patch("onedocker.repository.onedocker_repository_service.OneDockerMetadataService") @patch( "onedocker.repository.onedocker_repository_service.OneDockerPackageRepository" ) - @patch("fbpcp.service.storage_s3.S3StorageService") - def setUp(self, mockStorageService, mockPackageRepoCall) -> None: + @patch("onedocker.repository.onedocker_repository_service.StorageService") + def setUp(self, mockStorageService, mockPackageRepo, mockMetadataService) -> None: package_repo_path = "/package_repo_path/" self.package_repo = MagicMock() - mockPackageRepoCall.return_value = self.package_repo + self.metadata_svc = MagicMock() + mockPackageRepo.return_value = self.package_repo + mockMetadataService.return_value = self.metadata_svc self.repo_service = OneDockerRepositoryService( mockStorageService, package_repo_path ) + self.storage_svc = mockStorageService def test_onedocker_repo_service_upload(self) -> None: # Arrange @@ -85,3 +91,50 @@ def test_onedocker_repo_service_upload_to_latest(self) -> None: self.package_repo.upload.assert_called_with( self.TEST_PACKAGE_PATH, DEFAULT_PROD_VERSION, source_path ) + + def test_onedocker_repo_service_set_metadata(self) -> None: + # Arrange + metadata_dict = {"checksum": "checksum_data", "not_a_valid_field": "some_data"} + path = "test_metadata_path" + self.package_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.metadata_svc.set_metadata.assert_called_once_with(path, 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.package_repo._build_package_path.return_value = path + self.storage_svc.read.return_value = metadata_json + # Act + self.repo_service._get_metadata( + self.TEST_PACKAGE_NAME, self.TEST_PACKAGE_VERSION + ) + # Assert + self.metadata_svc.get_metadata.assert_called_once_with(path) + # TODO: add result validation after implementing get_metadata + + @patch( + "onedocker.repository.onedocker_repository_service.OneDockerRepositoryService._set_metadata" + ) + def test_onedocker_repo_service_upload_with_metadata(self, setMetadataMock) -> None: + # Arrange + source_path = "test_source_path" + metadata = {"checksum": "checksum_data"} + # Act + self.repo_service.upload( + self.TEST_PACKAGE_NAME, self.TEST_PACKAGE_VERSION, source_path, metadata + ) + + # Assert + setMetadataMock.assert_called_once_with( + self.TEST_PACKAGE_NAME, self.TEST_PACKAGE_VERSION, metadata + ) + self.package_repo.upload.assert_called_with( + self.TEST_PACKAGE_NAME, self.TEST_PACKAGE_VERSION, source_path + )