Skip to content

Commit 8555a72

Browse files
committed
test(metadata): improve MetadataFetcher code coverage to 100%
1 parent b160821 commit 8555a72

1 file changed

Lines changed: 142 additions & 24 deletions

File tree

libraries/tests/AWS.Lambda.Powertools.Metadata.Tests/Internal/MetadataFetcherTests.cs

Lines changed: 142 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,52 +13,170 @@
1313
* permissions and limitations under the License.
1414
*/
1515

16+
using System.Net;
1617
using AWS.Lambda.Powertools.Metadata.Exceptions;
1718
using AWS.Lambda.Powertools.Metadata.Internal;
1819
using FluentAssertions;
1920
using Xunit;
2021

2122
namespace AWS.Lambda.Powertools.Metadata.Tests.Internal;
2223

23-
public class MetadataFetcherTests
24+
public class MetadataFetcherTests : IDisposable
2425
{
26+
public MetadataFetcherTests()
27+
{
28+
Environment.SetEnvironmentVariable("AWS_LAMBDA_METADATA_TOKEN", "test-token");
29+
Environment.SetEnvironmentVariable("AWS_LAMBDA_METADATA_API", "localhost:8080");
30+
}
31+
32+
public void Dispose()
33+
{
34+
Environment.SetEnvironmentVariable("AWS_LAMBDA_METADATA_TOKEN", null);
35+
Environment.SetEnvironmentVariable("AWS_LAMBDA_METADATA_API", null);
36+
}
37+
2538
[Fact]
2639
public void Fetch_ThrowsWhenTokenMissing()
2740
{
28-
// Arrange
2941
Environment.SetEnvironmentVariable("AWS_LAMBDA_METADATA_TOKEN", null);
30-
Environment.SetEnvironmentVariable("AWS_LAMBDA_METADATA_API", "localhost:8080");
3142

32-
try
33-
{
34-
var fetcher = new MetadataFetcher();
35-
var act = () => fetcher.Fetch();
36-
act.Should().Throw<LambdaMetadataException>()
37-
.WithMessage("*AWS_LAMBDA_METADATA_TOKEN*");
38-
}
39-
finally
40-
{
41-
Environment.SetEnvironmentVariable("AWS_LAMBDA_METADATA_API", null);
42-
}
43+
var fetcher = new MetadataFetcher();
44+
var act = () => fetcher.Fetch();
45+
act.Should().Throw<LambdaMetadataException>()
46+
.WithMessage("*AWS_LAMBDA_METADATA_TOKEN*");
4347
}
4448

4549
[Fact]
4650
public void Fetch_ThrowsWhenApiMissing()
4751
{
48-
// Arrange
49-
Environment.SetEnvironmentVariable("AWS_LAMBDA_METADATA_TOKEN", "test-token");
5052
Environment.SetEnvironmentVariable("AWS_LAMBDA_METADATA_API", null);
5153

52-
try
54+
var fetcher = new MetadataFetcher();
55+
var act = () => fetcher.Fetch();
56+
act.Should().Throw<LambdaMetadataException>()
57+
.WithMessage("*AWS_LAMBDA_METADATA_API*");
58+
}
59+
60+
[Fact]
61+
public void Fetch_ReturnsMetadata_WhenSuccessful()
62+
{
63+
var handler = new MockHandler(new HttpResponseMessage(HttpStatusCode.OK)
5364
{
54-
var fetcher = new MetadataFetcher();
55-
var act = () => fetcher.Fetch();
56-
act.Should().Throw<LambdaMetadataException>()
57-
.WithMessage("*AWS_LAMBDA_METADATA_API*");
58-
}
59-
finally
65+
Content = new StringContent("{\"AvailabilityZoneID\":\"use1-az1\"}")
66+
});
67+
var fetcher = new MetadataFetcher(new HttpClient(handler));
68+
69+
var result = fetcher.Fetch();
70+
71+
result.AvailabilityZoneId.Should().Be("use1-az1");
72+
}
73+
74+
[Fact]
75+
public void Fetch_ThrowsWithStatusCode_WhenHttpError()
76+
{
77+
var handler = new MockHandler(new HttpResponseMessage(HttpStatusCode.Forbidden)
6078
{
61-
Environment.SetEnvironmentVariable("AWS_LAMBDA_METADATA_TOKEN", null);
79+
Content = new StringContent("access denied")
80+
});
81+
var fetcher = new MetadataFetcher(new HttpClient(handler));
82+
83+
var act = () => fetcher.Fetch();
84+
85+
act.Should().Throw<LambdaMetadataException>()
86+
.Where(e => e.Message.Contains("403") && e.Message.Contains("access denied"))
87+
.Where(e => e.StatusCode == 403);
88+
}
89+
90+
[Fact]
91+
public void Fetch_WrapsGenericException()
92+
{
93+
var handler = new MockHandler(new InvalidOperationException("connection refused"));
94+
var fetcher = new MetadataFetcher(new HttpClient(handler));
95+
96+
var act = () => fetcher.Fetch();
97+
98+
act.Should().Throw<LambdaMetadataException>()
99+
.WithMessage("*connection refused*")
100+
.WithInnerException<InvalidOperationException>();
101+
}
102+
103+
[Fact]
104+
public void Fetch_ThrowsWhenDeserializationReturnsNull()
105+
{
106+
var handler = new MockHandler(new HttpResponseMessage(HttpStatusCode.OK)
107+
{
108+
Content = new StringContent("null")
109+
});
110+
var fetcher = new MetadataFetcher(new HttpClient(handler));
111+
112+
var act = () => fetcher.Fetch();
113+
114+
act.Should().Throw<LambdaMetadataException>()
115+
.WithMessage("*deserialize*");
116+
}
117+
118+
[Fact]
119+
public void Fetch_SetsAuthorizationHeader()
120+
{
121+
var handler = new MockHandler(new HttpResponseMessage(HttpStatusCode.OK)
122+
{
123+
Content = new StringContent("{\"AvailabilityZoneID\":\"use1-az1\"}")
124+
});
125+
var fetcher = new MetadataFetcher(new HttpClient(handler));
126+
127+
fetcher.Fetch();
128+
129+
handler.LastRequest.Should().NotBeNull();
130+
handler.LastRequest!.Headers.Authorization.Should().NotBeNull();
131+
handler.LastRequest.Headers.Authorization!.Scheme.Should().Be("Bearer");
132+
handler.LastRequest.Headers.Authorization.Parameter.Should().Be("test-token");
133+
}
134+
135+
[Fact]
136+
public void Fetch_UsesCorrectUrl()
137+
{
138+
var handler = new MockHandler(new HttpResponseMessage(HttpStatusCode.OK)
139+
{
140+
Content = new StringContent("{\"AvailabilityZoneID\":\"use1-az1\"}")
141+
});
142+
var fetcher = new MetadataFetcher(new HttpClient(handler));
143+
144+
fetcher.Fetch();
145+
146+
handler.LastRequest!.RequestUri!.ToString()
147+
.Should().Be("http://localhost:8080/2026-01-15/metadata/execution-environment");
148+
}
149+
150+
[Fact]
151+
public void Fetch_RethrowsLambdaMetadataException()
152+
{
153+
var handler = new MockHandler(new LambdaMetadataException("original error"));
154+
var fetcher = new MetadataFetcher(new HttpClient(handler));
155+
156+
var act = () => fetcher.Fetch();
157+
158+
act.Should().Throw<LambdaMetadataException>()
159+
.WithMessage("original error")
160+
.Where(e => e.InnerException == null);
161+
}
162+
163+
private class MockHandler : HttpMessageHandler
164+
{
165+
private readonly HttpResponseMessage? _response;
166+
private readonly Exception? _exception;
167+
public HttpRequestMessage? LastRequest { get; private set; }
168+
169+
public MockHandler(HttpResponseMessage response) => _response = response;
170+
public MockHandler(Exception exception) => _exception = exception;
171+
172+
protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
173+
{
174+
LastRequest = request;
175+
if (_exception is not null) throw _exception;
176+
return _response!;
62177
}
178+
179+
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
180+
=> Task.FromResult(Send(request, cancellationToken));
63181
}
64182
}

0 commit comments

Comments
 (0)