import pytest from datetime import datetime from auto_archiver.core import Metadata from auto_archiver.modules.atlos_feeder_db_storage import AtlosFeederDbStorage as AtlosDb 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_db(setup_module, mocker) -> AtlosDb: """Fixture for AtlosDb.""" configs: dict = { "api_token": "abc123", "atlos_url": "https://platform.atlos.org", } mocker.patch("requests.Session") atlos_feeder = setup_module("atlos_feeder_db_storage", configs) fake_session = mocker.MagicMock() # Configure the default response to have no results so that __iter__ terminates fake_session.get.return_value = FakeAPIResponse({"next": None, "results": []}) atlos_feeder.session = fake_session return atlos_feeder def test_failed_no_atlos_id(atlos_db, metadata, mocker): """Test failed() skips posting when no atlos_id present.""" post_mock = mocker.patch("requests.post") atlos_db.failed(metadata, "failure reason") post_mock.assert_not_called() def test_failed_with_atlos_id(atlos_db, metadata, mocker): """Test failed() posts failure when atlos_id is present.""" metadata.set("atlos_id", 42) fake_resp = FakeAPIResponse({}, raise_error=False) post_mock = mocker.patch.object(atlos_db, "_post", return_value=fake_resp) atlos_db.failed(metadata, "failure reason") expected_endpoint = "/api/v2/source_material/metadata/42/auto_archiver" expected_json = {"metadata": {"processed": True, "status": "error", "error": "failure reason"}} post_mock.assert_called_once_with(expected_endpoint, json=expected_json) def test_failed_http_error(atlos_db, metadata, mocker): """Test failed() raises exception on HTTP error.""" metadata.set("atlos_id", 42) # Patch _post to raise an exception instead of returning a fake response. mocker.patch.object(atlos_db, "_post", side_effect=Exception("HTTP error")) with pytest.raises(Exception, match="HTTP error"): atlos_db.failed(metadata, "failure reason") def test_fetch_returns_false(atlos_db): """Test fetch() always returns False.""" item = Metadata() assert atlos_db.fetch(item) is False def test_done_no_atlos_id(atlos_db, mocker): """Test done() skips posting when no atlos_id present.""" item = Metadata().set_url("http://example.com") post_mock = mocker.patch("requests.post") atlos_db.done(item) post_mock.assert_not_called() def test_done_with_atlos_id(atlos_db, metadata, mocker): """Test done() posts success when atlos_id is present.""" metadata.set("atlos_id", 99) now = datetime.now() metadata.set("timestamp", now) fake_resp = FakeAPIResponse({}, raise_error=False) post_mock = mocker.patch.object(atlos_db, "_post", return_value=fake_resp) atlos_db.done(metadata) expected_endpoint = "/api/v2/source_material/metadata/99/auto_archiver" expected_results = metadata.metadata.copy() expected_results["timestamp"] = now.isoformat() expected_json = { "metadata": { "processed": True, "status": "success", "results": expected_results, } } post_mock.assert_called_once_with(expected_endpoint, json=expected_json) def test_done_http_error(atlos_db, metadata, mocker): """Test done() raises an exception on HTTP error.""" metadata.set("atlos_id", 123) # Patch _post to raise an exception. mocker.patch.object(atlos_db, "_post", side_effect=Exception("HTTP error")) with pytest.raises(Exception, match="HTTP error"): atlos_db.done(metadata)