import os import hashlib import pytest from auto_archiver.core import Media, Metadata from auto_archiver.modules.atlos_feeder_db_storage import AtlosFeederDbStorage as AtlosStorage class FakeAPIResponse: """Simulate a response object.""" def __init__(self, data: dict, raise_error: bool = False) -> None: self._data = data self.raise_error = raise_error def json(self) -> dict: return self._data def raise_for_status(self) -> None: if self.raise_error: raise Exception("HTTP error") @pytest.fixture def atlos_storage(setup_module, mocker) -> AtlosStorage: """Fixture for AtlosStorage.""" configs: dict = { "api_token": "abc123", "atlos_url": "https://platform.atlos.org", } mocker.patch("requests.Session") atlos_feeder = setup_module("atlos_feeder_db_storage", configs) mock_session = mocker.MagicMock() # Configure the default response to have no results so that __iter__ terminates mock_session.get.return_value = FakeAPIResponse({"next": None, "results": []}) atlos_feeder.session = mock_session return atlos_feeder @pytest.fixture def media(tmp_path) -> Media: """Fixture for Media.""" content = b"media content" file_path = tmp_path / "media.txt" file_path.write_bytes(content) media = Media(filename=str(file_path)) media.properties = {"something": "Title"} media._key = "key" return media def test_get_cdn_url(atlos_storage: AtlosStorage) -> None: """Test get_cdn_url returns the configured atlos_url.""" media = Media(filename="dummy.mp4") url = atlos_storage.get_cdn_url(media) assert url == atlos_storage.atlos_url def test_upload_no_atlos_id(tmp_path, atlos_storage: AtlosStorage, media: Media, mocker) -> None: """Test upload() returns False when metadata lacks atlos_id.""" metadata = Metadata() # atlos_id not set post_mock = mocker.patch("requests.post") result = atlos_storage.upload(media, metadata) assert result is False post_mock.assert_not_called() def test_upload_already_uploaded(atlos_storage: AtlosStorage, metadata: Metadata, media: Media, mocker) -> None: """Test upload() returns True if media hash already exists.""" content = b"media content" metadata.set("atlos_id", 101) media_hash = hashlib.sha256(content).hexdigest() fake_get_response = {"result": {"artifacts": [{"file_hash_sha256": media_hash}]}} get_mock = mocker.patch.object(atlos_storage, "_get", return_value=fake_get_response) post_mock = mocker.patch.object(atlos_storage, "_post") result = atlos_storage.upload(media, metadata) assert result is True get_mock.assert_called_once() post_mock.assert_not_called() def test_upload_not_uploaded(tmp_path, atlos_storage: AtlosStorage, metadata: Metadata, media: Media, mocker) -> None: """Test upload() uploads media when not already present.""" metadata.set("atlos_id", 202) fake_get_response = {"result": {"artifacts": [{"file_hash_sha256": "different_hash"}]}} get_mock = mocker.patch.object(atlos_storage, "_get", return_value=fake_get_response) fake_post_response = {"result": "uploaded"} post_mock = mocker.patch.object(atlos_storage, "_post", return_value=fake_post_response) result = atlos_storage.upload(media, metadata) assert result is True get_mock.assert_called_once() post_mock.assert_called_once() expected_endpoint = "/api/v2/source_material/upload/202" call_args = post_mock.call_args[0] assert call_args[0] == expected_endpoint call_kwargs = post_mock.call_args[1] expected_params = {"title": media.properties} assert call_kwargs["params"] == expected_params file_tuple = call_kwargs["files"]["file"] assert file_tuple[0] == os.path.basename(media.filename) def test_upload_post_http_error( tmp_path, atlos_storage: AtlosStorage, metadata: Metadata, media: Media, mocker ) -> None: """Test upload() propagates HTTP error during POST.""" metadata.set("atlos_id", 303) fake_get_response = {"result": {"artifacts": []}} mocker.patch.object(atlos_storage, "_get", return_value=fake_get_response) mocker.patch.object(atlos_storage, "_post", side_effect=Exception("HTTP error")) with pytest.raises(Exception, match="HTTP error"): atlos_storage.upload(media, metadata)