Skip to content

Commit e7a15c5

Browse files
lint fixes
1 parent 1f94c19 commit e7a15c5

4 files changed

Lines changed: 101 additions & 59 deletions

File tree

tests/docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
services:
22
moto-server:
33
#used for s3, dynamodb, kinesis, secret manager
4+
# lambda cannot be used, because its 3.11 (older)
45
image: motoserver/moto:latest
56
container_name: moto-server
67
ports:

tests/integration/conftest.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import logging
44
import os
55
from collections.abc import Callable, Generator
6-
from typing import TYPE_CHECKING, Any
6+
from typing import Any
77

88
import httpx
99
import pytest
@@ -37,9 +37,6 @@
3737
from tests.fixtures.builders.model.rule import RulesMapperFactory
3838
from tests.fixtures.builders.repos.person import person_rows_builder
3939

40-
if TYPE_CHECKING:
41-
pass
42-
4340
logger = logging.getLogger(__name__)
4441

4542
AWS_REGION = "eu-west-1"
@@ -52,6 +49,8 @@
5249

5350
MOTO_PORT = 5000
5451

52+
HTTP_SERVER_ERROR = 500
53+
5554

5655
@pytest.fixture(scope="session")
5756
def docker_compose_project_name():
@@ -62,9 +61,9 @@ def docker_compose_project_name():
6261
def aws_credentials():
6362
"""Mocked AWS Credentials for moto."""
6463
os.environ["AWS_ACCESS_KEY_ID"] = "dummy_key"
65-
os.environ["AWS_SECRET_ACCESS_KEY"] = "dummy_secret"
66-
os.environ["AWS_SECURITY_TOKEN"] = "dummy_token"
67-
os.environ["AWS_SESSION_TOKEN"] = "dummy_session_token"
64+
os.environ["AWS_SECRET_ACCESS_KEY"] = "dummy_secret" # noqa: S105
65+
os.environ["AWS_SECURITY_TOKEN"] = "dummy_token" # noqa: S105
66+
os.environ["AWS_SESSION_TOKEN"] = "dummy_session_token" # noqa: S105
6867
os.environ["AWS_DEFAULT_REGION"] = AWS_REGION
6968

7069

@@ -84,24 +83,30 @@ def moto_server(request: pytest.FixtureRequest) -> URL:
8483
def is_responsive(url: URL) -> bool:
8584
try:
8685
response = httpx.get(str(url), timeout=2.0)
87-
return response.status_code < 500
8886
except (httpx.ConnectError, httpx.RemoteProtocolError, httpx.TimeoutException):
8987
return False
88+
else:
89+
# Use the constant instead of the raw number
90+
return response.status_code < HTTP_SERVER_ERROR
9091

9192

9293
@pytest.fixture(scope="session")
9394
def boto3_session() -> Session:
94-
return Session(aws_access_key_id="fake", aws_secret_access_key="fake", aws_session_token="fake", region_name=AWS_REGION)
95+
return Session(
96+
aws_access_key_id="fake", aws_secret_access_key="fake", aws_session_token="fake", region_name=AWS_REGION
97+
)
9598

9699

97100
@pytest.fixture(scope="session")
98101
def dynamodb_client(boto3_session: Session, moto_server: URL) -> BaseClient:
99102
return boto3_session.client("dynamodb", endpoint_url=str(moto_server))
100103

104+
101105
@pytest.fixture(scope="session")
102106
def dynamodb_resource(boto3_session: Session, moto_server: URL) -> ServiceResource:
103107
return boto3_session.resource("dynamodb", endpoint_url=str(moto_server))
104108

109+
105110
def get_log_messages(flask_function: str, logs_client: BaseClient) -> list[str]:
106111
for attempt in stamina.retry_context(on=ClientError, attempts=20, timeout=120):
107112
with attempt:
@@ -115,10 +120,6 @@ def get_log_messages(flask_function: str, logs_client: BaseClient) -> list[str]:
115120
)
116121
return [e["message"] for e in log_events["events"]]
117122

118-
@pytest.fixture(scope="session")
119-
def logs_client(boto3_session: Session, moto_server: URL) -> BaseClient:
120-
return boto3_session.client("logs", endpoint_url=str(moto_server))
121-
122123

123124
@pytest.fixture(scope="session")
124125
def iam_client(boto3_session: Session, moto_server: URL) -> BaseClient:
Lines changed: 73 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import os
2+
import shutil
23
import subprocess
4+
from collections.abc import Callable
35
from pathlib import Path
4-
from typing import Callable
56

67
import pytest
78
from boto3 import Session
@@ -12,19 +13,25 @@
1213

1314

1415
def get_project_root() -> Path:
15-
"""Finds the project root by looking for the 'dist' directory or a git folder."""
16+
"""Find the project root by locating 'dist' or '.git'."""
1617
current = Path(__file__).resolve()
1718
for parent in current.parents:
1819
if (parent / "dist").exists() or (parent / ".git").exists():
1920
return parent
2021
return Path(__file__).resolve().parents[3]
2122

23+
2224
@pytest.fixture(scope="session")
2325
def lambda_zip() -> Path:
26+
"""Build the lambda.zip artifact using `make build`."""
2427
project_root = get_project_root()
2528

26-
build_result = subprocess.run(
27-
["make", "build"],
29+
make_path = shutil.which("make")
30+
if not make_path:
31+
pytest.fail("The 'make' executable was not found in the system PATH.")
32+
33+
build_result = subprocess.run( # noqa: S603
34+
[make_path, "build"],
2835
cwd=project_root,
2936
capture_output=True,
3037
text=True,
@@ -34,61 +41,81 @@ def lambda_zip() -> Path:
3441
if build_result.returncode != 0:
3542
pytest.fail(
3643
f"'make build' failed with code {build_result.returncode}.\n"
37-
f"STDOUT: {build_result.stdout}\n"
38-
f"STDERR: {build_result.stderr}"
44+
f"STDOUT:\n{build_result.stdout}\n"
45+
f"STDERR:\n{build_result.stderr}"
3946
)
4047

41-
zip_path = project_root / "dist/lambda.zip"
48+
zip_path = project_root / "dist" / "lambda.zip"
4249
if not zip_path.exists():
4350
pytest.fail(f"Build succeeded but {zip_path} was not created.")
4451

4552
return zip_path
4653

54+
4755
@pytest.fixture(scope="session")
48-
def lambda_runtime_url(request, lambda_zip):
56+
def lambda_runtime_url(request, lambda_zip): # noqa: ARG001
4957
"""
50-
kick-starts the lambda simulation
58+
Start the lambda simulation using docker compose.
5159
"""
5260
docker_services = request.getfixturevalue("docker_services")
5361
docker_ip = request.getfixturevalue("docker_ip")
5462
project_root = get_project_root()
5563
compose_file = project_root / "tests/docker-compose.yml"
5664

65+
# Activate the profile without using the --profile flag
5766
env = os.environ.copy()
5867
env["COMPOSE_PROFILES"] = "lambda-test"
5968

60-
subprocess.run(
69+
docker_path = shutil.which("docker")
70+
if not docker_path:
71+
pytest.fail("Docker executable not found in PATH")
72+
73+
result = subprocess.run( # noqa: S603
6174
[
62-
"docker", "compose",
63-
"-f", str(compose_file),
64-
"up", "-d", "--build", "--force-recreate",
65-
"lambda-api", "api-gateway-mock",
75+
docker_path,
76+
"compose",
77+
"-f",
78+
str(compose_file),
79+
"up",
80+
"-d",
81+
"--build",
82+
"--force-recreate",
83+
"lambda-api",
84+
"api-gateway-mock",
6685
],
6786
env=env,
68-
check=True,
6987
capture_output=True,
7088
text=True,
89+
check=False,
7190
)
7291

92+
if result.returncode != 0:
93+
pytest.fail(
94+
f"Docker compose failed with code {result.returncode}.\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}"
95+
)
96+
7397
port = docker_services.port_for("lambda-api", 8080)
7498
base_url = URL(f"http://{docker_ip}:{port}")
7599

76100
docker_services.wait_until_responsive(
77-
timeout=30.0, pause=0.5, check=lambda: is_responsive(base_url)
101+
timeout=30.0,
102+
pause=0.5,
103+
check=lambda: is_responsive(base_url),
78104
)
79105

80106
return base_url
81107

82108

83-
84109
@pytest.fixture(scope="session")
85110
def lambda_client(boto3_session: Session, lambda_runtime_url: URL) -> BaseClient:
111+
"""Return a boto3 Lambda client pointing at the simulated lambda runtime."""
86112
return boto3_session.client("lambda", endpoint_url=str(lambda_runtime_url))
87113

114+
88115
@pytest.fixture(scope="session")
89-
def api_gateway_endpoint(request: pytest.FixtureRequest, lambda_runtime_url) -> URL:
116+
def api_gateway_endpoint(request: pytest.FixtureRequest, lambda_runtime_url): # noqa: ARG001
90117
"""
91-
kick-starts the api-gateway lambda simulation
118+
Start and validate the API Gateway mock.
92119
"""
93120
docker_services = request.getfixturevalue("docker_services")
94121
docker_ip = request.getfixturevalue("docker_ip")
@@ -101,26 +128,45 @@ def api_gateway_endpoint(request: pytest.FixtureRequest, lambda_runtime_url) ->
101128
docker_services.wait_until_responsive(
102129
timeout=30.0,
103130
pause=1.0,
104-
check=lambda: is_responsive(health_url)
131+
check=lambda: is_responsive(health_url),
105132
)
133+
106134
return base_url
107135

108136

109137
@pytest.fixture
110138
def lambda_logs(docker_services) -> Callable[[], list[str]]:
111-
"""Returns a callable that fetches the latest lambda-api logs,
112-
allowing tests to inspect runtime output on demand."""
139+
"""Return a callable that fetches the latest lambda-api logs."""
113140

114141
def _get_messages() -> list[str]:
115142
return get_lambda_logs(docker_services)
116143

117144
return _get_messages
118145

119146

120-
def get_lambda_logs(docker_services) -> list[str]:
121-
"""returns logs from lambda-api container"""
147+
def get_lambda_logs(docker_services) -> list[str]: # noqa :ARG001
148+
"""Fetch logs from the lambda-api container."""
149+
raw_docker = shutil.which("docker")
150+
if not raw_docker:
151+
return ["Error: Docker not found"]
122152

123-
result: bytes = docker_services._docker_compose.execute("logs --no-color lambda-api")
124-
raw_lines = result.decode("utf-8").splitlines()
125-
return [line.partition("|")[-1].strip() for line in raw_lines]
153+
docker_path = Path(raw_docker).resolve()
154+
project_root = get_project_root()
155+
compose_file = (project_root / "tests" / "docker-compose.yml").resolve()
156+
157+
result = subprocess.run( # noqa: S603
158+
[
159+
str(docker_path),
160+
"compose",
161+
"-f",
162+
str(compose_file),
163+
"logs",
164+
"--no-color",
165+
"lambda-api",
166+
],
167+
capture_output=True,
168+
text=True,
169+
check=False,
170+
)
126171

172+
return [line.partition("|")[-1].strip() for line in result.stdout.splitlines()]

tests/integration/lambda/test_app_running_as_lambda.py

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
import base64
21
import json
32
import logging
3+
from collections.abc import Callable
44
from http import HTTPStatus
5-
from typing import Callable, List
65

76
import httpx
8-
import stamina
97
from botocore.client import BaseClient
10-
from botocore.exceptions import ClientError
118
from brunns.matchers.data import json_matching as is_json_that
129
from brunns.matchers.response import is_response
1310
from freezegun import freeze_time
@@ -38,7 +35,7 @@ def test_install_and_call_lambda_flask(
3835
persisted_person: NHSNumber,
3936
consumer_to_active_rsv_campaign_mapping: ConsumerMapping, # noqa: ARG001
4037
consumer_id: ConsumerId,
41-
secretsmanager_client: BaseClient,
38+
secretsmanager_client: BaseClient, # noqa :ARG001
4239
):
4340
"""Given lambda installed into localstack, run it via boto3 lambda client"""
4441
# Given
@@ -92,7 +89,7 @@ def test_install_and_call_flask_lambda_over_http(
9289
persisted_person: NHSNumber,
9390
consumer_to_active_rsv_campaign_mapping: ConsumerMapping, # noqa: ARG001
9491
consumer_id: ConsumerId,
95-
secretsmanager_client: BaseClient,
92+
secretsmanager_client: BaseClient, # noqa:ARG001
9693
api_gateway_endpoint: URL,
9794
):
9895
"""Given api-gateway and lambda installed into localstack, run it via http"""
@@ -116,10 +113,9 @@ def test_install_and_call_flask_lambda_with_unknown_nhs_number( # noqa: PLR0913
116113
persisted_person: NHSNumber,
117114
consumer_to_active_rsv_campaign_mapping: ConsumerMapping, # noqa: ARG001
118115
consumer_id: ConsumerId,
119-
logs_client: BaseClient,
120116
api_gateway_endpoint: URL,
121117
secretsmanager_client: BaseClient, # noqa: ARG001
122-
lambda_logs: Callable[[], List[str]]
118+
lambda_logs: Callable[[], list[str]],
123119
):
124120
"""Given lambda installed into localstack, run it via http, with a nonexistent NHS number specified"""
125121
# Given
@@ -147,15 +143,15 @@ def test_install_and_call_flask_lambda_with_unknown_nhs_number( # noqa: PLR0913
147143
severity="error",
148144
code="processing",
149145
diagnostics=f"NHS Number '{nhs_number!s}' was not "
150-
f"recognised by the Eligibility Signposting API",
146+
f"recognised by the Eligibility Signposting API",
151147
details={
152148
"coding": [
153149
{
154150
"system": "https://fhir.nhs.uk/STU3/ValueSet/Spine-ErrorOrWarningCode-1",
155151
"code": "REFERENCE_NOT_FOUND",
156152
"display": "The given NHS number was not found in our datasets. "
157-
"This could be because the number is incorrect or "
158-
"some other reason we cannot process that number.",
153+
"This could be because the number is incorrect or "
154+
"some other reason we cannot process that number.",
159155
}
160156
]
161157
},
@@ -182,8 +178,8 @@ def test_given_nhs_number_in_path_matches_with_nhs_number_in_headers_and_check_i
182178
s3_client: BaseClient,
183179
audit_bucket: BucketName,
184180
api_gateway_endpoint: URL,
185-
lambda_logs: Callable[[], List[str]],
186-
secretsmanager_client: BaseClient,
181+
lambda_logs: Callable[[], list[str]],
182+
secretsmanager_client: BaseClient, # noqa:ARG001
187183
):
188184
# Given
189185
# When
@@ -320,10 +316,10 @@ def test_given_nhs_number_in_path_does_not_match_with_nhs_number_in_headers_resu
320316

321317

322318
def test_given_nhs_number_not_present_in_headers_results_in_valid_for_application_restricted_users(
323-
lambda_client: BaseClient,
324-
secretsmanager_client: BaseClient, # noqa:ARG001
319+
lambda_client: BaseClient, # noqa:ARG001
320+
secretsmanager_client: BaseClient, # noqa:ARG001
325321
persisted_person: NHSNumber,
326-
consumer_to_active_rsv_campaign_mapping: ConsumerMapping,
322+
consumer_to_active_rsv_campaign_mapping: ConsumerMapping, # noqa:ARG001
327323
api_gateway_endpoint: URL,
328324
):
329325
# Given
@@ -622,8 +618,6 @@ def test_token_formatting_in_eligibility_response_and_audit( # noqa: PLR0913
622618
s3_client: BaseClient,
623619
audit_bucket: BucketName,
624620
api_gateway_endpoint: URL,
625-
# noqa:ARG001
626-
logs_client: BaseClient, # noqa:ARG001
627621
):
628622
invoke_url = f"{api_gateway_endpoint}/patient-check/{person_with_all_data}"
629623
response = httpx.get(
@@ -673,7 +667,7 @@ def test_incorrect_token_causes_internal_server_error( # noqa: PLR0913
673667
s3_client: BaseClient,
674668
audit_bucket: BucketName,
675669
api_gateway_endpoint: URL,
676-
lambda_logs: Callable[[], List[str]]
670+
lambda_logs: Callable[[], list[str]],
677671
):
678672
invoke_url = f"{api_gateway_endpoint}/patient-check/{person_with_all_data}"
679673
response = httpx.get(

0 commit comments

Comments
 (0)