diff --git a/lambdas/link_fetcher/Pipfile b/lambdas/link_fetcher/Pipfile index 9067a59..f70eed4 100644 --- a/lambdas/link_fetcher/Pipfile +++ b/lambdas/link_fetcher/Pipfile @@ -15,7 +15,6 @@ mangum = "*" [dev-packages] boto3-stubs = {version = "==1.17.10.0", extras = ["sqs", "ssm"]} -freezegun = "==1.0.0" assertpy = "==1.1" pytest = "==7.4.3" responses = "==0.23.1" diff --git a/lambdas/link_fetcher/Pipfile.lock b/lambdas/link_fetcher/Pipfile.lock index b100336..1d157c6 100644 --- a/lambdas/link_fetcher/Pipfile.lock +++ b/lambdas/link_fetcher/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "c21f2b40d849814997f95bad4cebdf047b5d1c0972408e08d3bd446f64b6c208" + "sha256": "4395d4def0145eb4cdc682f157f20556d7af9a51b085c217e7360280660776f3" }, "pipfile-spec": 6, "requires": { @@ -43,11 +43,11 @@ }, "botocore": { "hashes": [ - "sha256:564c2478e50179e0b766e6a87e5e0cdd35e1bc37eb375c1cf15511f5dd13600d", - "sha256:a7b13bbd959bf2d6f38f681676aab408be01974c46802ab997617b51399239f7" + "sha256:78dd7bf8f49616d00073698d7bbaf5a115208fe730b7b7afae4456adddb3552e", + "sha256:e43b97d8cbf19d35ce3a177f144bd97cc370f0a67d0984c7d7cf105ac198748f" ], "markers": "python_version >= '3.8'", - "version": "==1.35.81" + "version": "==1.35.82" }, "certifi": { "hashes": [ @@ -577,11 +577,11 @@ }, "botocore": { "hashes": [ - "sha256:564c2478e50179e0b766e6a87e5e0cdd35e1bc37eb375c1cf15511f5dd13600d", - "sha256:a7b13bbd959bf2d6f38f681676aab408be01974c46802ab997617b51399239f7" + "sha256:78dd7bf8f49616d00073698d7bbaf5a115208fe730b7b7afae4456adddb3552e", + "sha256:e43b97d8cbf19d35ce3a177f144bd97cc370f0a67d0984c7d7cf105ac198748f" ], "markers": "python_version >= '3.8'", - "version": "==1.35.81" + "version": "==1.35.82" }, "certifi": { "hashes": [ @@ -892,15 +892,6 @@ "editable": true, "path": "./../../layers/db" }, - "freezegun": { - "hashes": [ - "sha256:02b35de52f4699a78f6ac4518e4cd3390dddc43b0aeb978335a8f270a2d9668b", - "sha256:1cf08e441f913ff5e59b19cc065a8faa9dd1ddc442eaf0375294f344581a0643" - ], - "index": "pypi", - "markers": "python_version >= '3.5'", - "version": "==1.0.0" - }, "greenlet": { "hashes": [ "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e", diff --git a/lambdas/link_fetcher/app/subscription_endpoint.py b/lambdas/link_fetcher/app/subscription_endpoint.py index 2ed3c20..fd8e0c0 100644 --- a/lambdas/link_fetcher/app/subscription_endpoint.py +++ b/lambdas/link_fetcher/app/subscription_endpoint.py @@ -154,7 +154,10 @@ def process_notification( logger.info(f"Rejected {search_result=} (unacceptable tile)") -def build_app(config: EndpointConfig) -> FastAPI: +def build_app( + config: EndpointConfig, + now_utc: Callable[[], datetime] = lambda: datetime.now(tz=timezone.utc), +) -> FastAPI: """Create FastAPI app""" app = FastAPI() app.add_middleware( @@ -192,11 +195,11 @@ def post_notification( logging.error("Unauthorized") raise HTTPException(status_code=401, detail="Unauthorized") - # process notification process_notification( notification=notification, accepted_tile_ids=accepted_tile_ids, session_maker=session_maker, + now_utc=now_utc, ) return Response(status_code=204) diff --git a/lambdas/link_fetcher/tests/conftest.py b/lambdas/link_fetcher/tests/conftest.py index 0d76758..a2feaad 100644 --- a/lambdas/link_fetcher/tests/conftest.py +++ b/lambdas/link_fetcher/tests/conftest.py @@ -131,7 +131,8 @@ def sqs_client(): @pytest.fixture def mock_sqs_queue(request, sqs_resource, monkeysession, sqs_client): - queue = sqs_resource.create_queue(QueueName=f"mock-queue-{request.node.name}"[:80]) + request_name = hash(request.node.name) + queue = sqs_resource.create_queue(QueueName=f"mock-queue-{request_name}"[:80]) monkeysession.setenv("TO_DOWNLOAD_SQS_QUEUE_URL", queue.url) return queue diff --git a/lambdas/link_fetcher/tests/test_subscription_endpoint.py b/lambdas/link_fetcher/tests/test_subscription_endpoint.py index 0bf5bdc..9760b73 100644 --- a/lambdas/link_fetcher/tests/test_subscription_endpoint.py +++ b/lambdas/link_fetcher/tests/test_subscription_endpoint.py @@ -1,7 +1,8 @@ import json from collections.abc import Iterator -from datetime import datetime +from datetime import datetime, timezone from pathlib import Path +from typing import Callable from unittest.mock import Mock, patch import boto3 @@ -9,7 +10,6 @@ import pytest from db.models.granule import Granule from fastapi import FastAPI -from freezegun import freeze_time from moto import mock_aws from sqlalchemy.orm import Session from starlette.testclient import TestClient @@ -195,16 +195,23 @@ def config(self) -> EndpointConfig: ) @pytest.fixture - def app( - self, config: EndpointConfig, db_connection_secret, mock_sqs_queue + def now_utc(self, request) -> Callable[[], datetime]: + if callable(getattr(request, "param", None)): + return request.param + return lambda: datetime.now(tz=timezone.utc) + + @pytest.fixture + def test_client( + self, + config: EndpointConfig, + db_connection_secret, + mock_sqs_queue, + now_utc, ) -> FastAPI: self.endpoint_config = config self.db_connection_secret = db_connection_secret self.mock_sqs_queue = mock_sqs_queue - return build_app(config) - - @pytest.fixture - def test_client(self, app: FastAPI) -> TestClient: + app = build_app(config, now_utc) return TestClient(app) def test_handles_new_created_event( @@ -227,28 +234,31 @@ def test_handles_new_created_event( assert resp.status_code == 204 mock_process_notification.assert_called_once() + @pytest.mark.parametrize( + "now_utc", + [lambda: datetime.fromisoformat("2024-09-12T14:52:06.118Z")], + indirect=True, + ) def test_handles_new_created_event_is_added( self, test_client: TestClient, db_session: Session, event_s2_created: dict, + now_utc, ): """Test happy path for handling subscription event, mocking DB and SQS This is also distinguished by using a "recent" event notification that works by freezing/rewinding time to acquisition date for the test duration. """ - # we can't inject an older "utc_now" into `process_notification` so we have to - # patch `datetime.now()` with freezegun - with freeze_time(event_s2_created["value"]["PublicationDate"]): - resp = test_client.post( - "/events", - json=event_s2_created, - auth=( - self.endpoint_config.notification_username, - self.endpoint_config.notification_password, - ), - ) + resp = test_client.post( + "/events", + json=event_s2_created, + auth=( + self.endpoint_config.notification_username, + self.endpoint_config.notification_password, + ), + ) # processed successfully but no content resp.raise_for_status()