Skip to content

Commit 8186526

Browse files
feat: add ldms service
1 parent f273671 commit 8186526

2 files changed

Lines changed: 193 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
"""Integration tests for Lambda Metadata Service – exercises the real HTTP path."""
2+
3+
from __future__ import annotations
4+
5+
import http.server
6+
import json
7+
from collections import namedtuple
8+
9+
import pytest
10+
11+
from aws_lambda_powertools.utilities.metadata import (
12+
LambdaMetadataError,
13+
clear_metadata_cache,
14+
get_lambda_metadata,
15+
)
16+
17+
18+
@pytest.fixture(autouse=True)
19+
def _clear_cache():
20+
clear_metadata_cache()
21+
yield
22+
clear_metadata_cache()
23+
24+
25+
@pytest.fixture
26+
def lambda_context():
27+
context = {
28+
"function_name": "test",
29+
"memory_limit_in_mb": 128,
30+
"invoked_function_arn": "arn:aws:lambda:eu-west-1:123456789012:function:test",
31+
"aws_request_id": "52fdfc07-2182-154f-163f-5f0f9a621d72",
32+
}
33+
return namedtuple("LambdaContext", context.keys())(*context.values())
34+
35+
36+
@pytest.fixture
37+
def lambda_event():
38+
return {"key": "value"}
39+
40+
41+
# ---------------------------------------------------------------------------
42+
# HTTP server fixtures
43+
# ---------------------------------------------------------------------------
44+
45+
46+
def _make_handler(status: int, body: str):
47+
"""Create an HTTP handler that returns a fixed status and body."""
48+
49+
class Handler(http.server.BaseHTTPRequestHandler):
50+
def do_GET(self): # noqa: N802
51+
self.send_response(status)
52+
self.send_header("Content-Type", "application/json")
53+
self.end_headers()
54+
self.wfile.write(body.encode())
55+
56+
def log_message(self, format, *args): # noqa: A002
57+
pass
58+
59+
return Handler
60+
61+
62+
@pytest.fixture
63+
def metadata_server(monkeypatch):
64+
"""Start a local HTTP server returning valid metadata and set env vars."""
65+
body = json.dumps({"AvailabilityZoneID": "use1-az1"})
66+
server = http.server.HTTPServer(("127.0.0.1", 0), _make_handler(200, body))
67+
port = server.server_address[1]
68+
69+
import threading
70+
71+
thread = threading.Thread(target=server.serve_forever, daemon=True)
72+
thread.start()
73+
74+
monkeypatch.setenv("AWS_LAMBDA_INITIALIZATION_TYPE", "on-demand")
75+
monkeypatch.setenv("AWS_LAMBDA_METADATA_API", f"127.0.0.1:{port}")
76+
monkeypatch.setenv("AWS_LAMBDA_METADATA_TOKEN", "test-token")
77+
78+
yield server
79+
server.shutdown()
80+
81+
82+
@pytest.fixture
83+
def error_server(monkeypatch):
84+
"""Start a local HTTP server returning 500 and set env vars."""
85+
server = http.server.HTTPServer(("127.0.0.1", 0), _make_handler(500, "Internal Server Error"))
86+
port = server.server_address[1]
87+
88+
import threading
89+
90+
thread = threading.Thread(target=server.serve_forever, daemon=True)
91+
thread.start()
92+
93+
monkeypatch.setenv("AWS_LAMBDA_INITIALIZATION_TYPE", "on-demand")
94+
monkeypatch.setenv("AWS_LAMBDA_METADATA_API", f"127.0.0.1:{port}")
95+
monkeypatch.setenv("AWS_LAMBDA_METADATA_TOKEN", "test-token")
96+
97+
yield server
98+
server.shutdown()
99+
100+
101+
@pytest.fixture
102+
def invalid_json_server(monkeypatch):
103+
"""Start a local HTTP server returning invalid JSON."""
104+
server = http.server.HTTPServer(("127.0.0.1", 0), _make_handler(200, "not-json"))
105+
port = server.server_address[1]
106+
107+
import threading
108+
109+
thread = threading.Thread(target=server.serve_forever, daemon=True)
110+
thread.start()
111+
112+
monkeypatch.setenv("AWS_LAMBDA_INITIALIZATION_TYPE", "on-demand")
113+
monkeypatch.setenv("AWS_LAMBDA_METADATA_API", f"127.0.0.1:{port}")
114+
monkeypatch.setenv("AWS_LAMBDA_METADATA_TOKEN", "test-token")
115+
116+
yield server
117+
server.shutdown()
118+
119+
120+
# ---------------------------------------------------------------------------
121+
# Tests – happy path
122+
# ---------------------------------------------------------------------------
123+
124+
125+
def test_fetch_metadata_returns_az_id(lambda_context, lambda_event, metadata_server):
126+
# GIVEN a Lambda environment pointing to a local metadata endpoint
127+
def lambda_handler(event, context):
128+
return get_lambda_metadata()
129+
130+
# WHEN the handler is invoked
131+
result = lambda_handler(lambda_event, lambda_context)
132+
133+
# THEN it returns metadata with the availability zone id
134+
assert result.availability_zone_id == "use1-az1"
135+
136+
137+
def test_fetch_metadata_caches_across_invocations(lambda_context, lambda_event, metadata_server):
138+
# GIVEN a Lambda environment pointing to a local metadata endpoint
139+
def lambda_handler(event, context):
140+
return get_lambda_metadata()
141+
142+
# WHEN the handler is invoked twice (warm start)
143+
first = lambda_handler(lambda_event, lambda_context)
144+
second = lambda_handler(lambda_event, lambda_context)
145+
146+
# THEN both return the same data
147+
assert first.availability_zone_id == "use1-az1"
148+
assert second.availability_zone_id == "use1-az1"
149+
150+
151+
# ---------------------------------------------------------------------------
152+
# Tests – error paths
153+
# ---------------------------------------------------------------------------
154+
155+
156+
def test_fetch_metadata_raises_on_http_500(lambda_context, lambda_event, error_server):
157+
# GIVEN a Lambda environment where the endpoint returns 500
158+
def lambda_handler(event, context):
159+
return get_lambda_metadata()
160+
161+
# WHEN the handler is invoked
162+
# THEN it raises LambdaMetadataError with status code 500
163+
with pytest.raises(LambdaMetadataError, match="status 500") as exc_info:
164+
lambda_handler(lambda_event, lambda_context)
165+
166+
assert exc_info.value.status_code == 500
167+
168+
169+
def test_fetch_metadata_raises_on_invalid_json(lambda_context, lambda_event, invalid_json_server):
170+
# GIVEN a Lambda environment where the endpoint returns invalid JSON
171+
def lambda_handler(event, context):
172+
return get_lambda_metadata()
173+
174+
# WHEN the handler is invoked
175+
# THEN it raises LambdaMetadataError about parsing
176+
with pytest.raises(LambdaMetadataError, match="Failed to parse"):
177+
lambda_handler(lambda_event, lambda_context)
178+
179+
180+
def test_fetch_metadata_raises_on_unreachable_endpoint(lambda_context, lambda_event, monkeypatch):
181+
# GIVEN a Lambda environment pointing to an unreachable endpoint
182+
monkeypatch.setenv("AWS_LAMBDA_INITIALIZATION_TYPE", "on-demand")
183+
monkeypatch.setenv("AWS_LAMBDA_METADATA_API", "127.0.0.1:1")
184+
monkeypatch.setenv("AWS_LAMBDA_METADATA_TOKEN", "test-token")
185+
186+
def lambda_handler(event, context):
187+
return get_lambda_metadata(timeout=0.1)
188+
189+
# WHEN the handler is invoked
190+
# THEN it raises LambdaMetadataError about connection failure
191+
with pytest.raises(LambdaMetadataError, match="Failed to fetch"):
192+
lambda_handler(lambda_event, lambda_context)

0 commit comments

Comments
 (0)