Skip to content

Commit fa9bf88

Browse files
authored
Nullable Custom Resource ResponseURL (#455)
1 parent 072f1ed commit fa9bf88

File tree

4 files changed

+62
-21
lines changed

4 files changed

+62
-21
lines changed

.github/releases/v0.9.0-beta4.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Enhancements
22

33
- CloudFormationStackEvent objects are now serializable.
4+
- ResponseURL is now an optional argument to custom resource requests, to allow for easier testing.
5+
- The lambda output for Custom Resources is now the full response that would've been sent to CloudFormation, rather than just the output data.
46

57
# Bug Fixes
68

src/CustomResource/CustomResourceLambdaHost.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ namespace Lambdajection.CustomResource
1515
{
1616
/// <inheritdoc />
1717
public sealed class CustomResourceLambdaHost<TLambda, TLambdaParameter, TLambdaOutput, TLambdaStartup, TLambdaConfigurator, TLambdaConfigFactory>
18-
: LambdaHostBase<TLambda, CustomResourceRequest<TLambdaParameter>, TLambdaOutput, TLambdaStartup, TLambdaConfigurator, TLambdaConfigFactory>
18+
: LambdaHostBase<TLambda, CustomResourceRequest<TLambdaParameter>, CustomResourceResponse<TLambdaOutput>, TLambdaStartup, TLambdaConfigurator, TLambdaConfigFactory>
1919
where TLambda : class, ICustomResourceProvider<TLambdaParameter, TLambdaOutput>
2020
where TLambdaParameter : class
2121
where TLambdaOutput : class, ICustomResourceOutputData
@@ -35,13 +35,13 @@ public CustomResourceLambdaHost()
3535
/// Initializes a new instance of the <see cref="CustomResourceLambdaHost{TLambda, TLambdaParameter, TLambdaOutput, TLambdaStartup, TLambdaConfigurator, TLambdaConfigFactory}" /> class.
3636
/// </summary>
3737
/// <param name="build">The builder action to run on the lambda.</param>
38-
internal CustomResourceLambdaHost(Action<LambdaHostBase<TLambda, CustomResourceRequest<TLambdaParameter>, TLambdaOutput, TLambdaStartup, TLambdaConfigurator, TLambdaConfigFactory>> build)
38+
internal CustomResourceLambdaHost(Action<LambdaHostBase<TLambda, CustomResourceRequest<TLambdaParameter>, CustomResourceResponse<TLambdaOutput>, TLambdaStartup, TLambdaConfigurator, TLambdaConfigFactory>> build)
3939
: base(build)
4040
{
4141
}
4242

4343
/// <inheritdoc />
44-
public override async Task<TLambdaOutput> InvokeLambda(
44+
public override async Task<CustomResourceResponse<TLambdaOutput>> InvokeLambda(
4545
Stream inputStream,
4646
CancellationToken cancellationToken = default
4747
)
@@ -92,14 +92,17 @@ public override async Task<TLambdaOutput> InvokeLambda(
9292
};
9393
}
9494

95-
await httpClient.PutJson(
96-
requestUri: input.ResponseURL,
97-
payload: response,
98-
contentType: null,
99-
cancellationToken: cancellationToken
100-
);
95+
if (input.ResponseURL != null)
96+
{
97+
await httpClient.PutJson(
98+
requestUri: input.ResponseURL,
99+
payload: response,
100+
contentType: null,
101+
cancellationToken: cancellationToken
102+
);
103+
}
101104

102-
return response.Data!;
105+
return response;
103106
}
104107

105108
[MethodImpl(MethodImplOptions.AggressiveInlining)]

src/CustomResource/CustomResourceRequest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class CustomResourceRequest
2424
/// has been created/updated/deleted.
2525
/// </summary>
2626
/// <value>The response URL.</value>
27-
public virtual Uri ResponseURL { get; set; } = new Uri("http://localhost");
27+
public virtual Uri? ResponseURL { get; set; }
2828

2929
/// <summary>
3030
/// Gets or sets the Id of the CloudFormation stack that the

tests/Unit/CustomResource/CustomResourceLambdaHostTests.cs

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ [Substitute] IHttpClient httpClient
196196
await host.InvokeLambda(inputStream, cancellationToken);
197197

198198
await httpClient.Received().PutJson(
199-
Is(request.ResponseURL),
199+
Is(request.ResponseURL!),
200200
Is<CustomResourceResponse<TestCustomResourceOutputData>>(response =>
201201
response.Status == CustomResourceResponseStatus.Success &&
202202
response.Data == data
@@ -234,7 +234,7 @@ [Substitute] IHttpClient httpClient
234234
await host.InvokeLambda(inputStream, cancellationToken);
235235

236236
await httpClient.Received().PutJson(
237-
Is(request.ResponseURL),
237+
Is(request.ResponseURL!),
238238
Is<CustomResourceResponse<TestCustomResourceOutputData>>(response =>
239239
response.Status == CustomResourceResponseStatus.Success &&
240240
response.StackId == stackId
@@ -272,7 +272,7 @@ [Substitute] IHttpClient httpClient
272272
await host.InvokeLambda(inputStream, cancellationToken);
273273

274274
await httpClient.Received().PutJson(
275-
Is(request.ResponseURL),
275+
Is(request.ResponseURL!),
276276
Is<CustomResourceResponse<TestCustomResourceOutputData>>(response =>
277277
response.Status == CustomResourceResponseStatus.Success &&
278278
response.RequestId == requestId
@@ -310,7 +310,7 @@ [Substitute] IHttpClient httpClient
310310
await host.InvokeLambda(inputStream, cancellationToken);
311311

312312
await httpClient.Received().PutJson(
313-
Is(request.ResponseURL),
313+
Is(request.ResponseURL!),
314314
Is<CustomResourceResponse<TestCustomResourceOutputData>>(response =>
315315
response.Status == CustomResourceResponseStatus.Success &&
316316
response.LogicalResourceId == logicalResourceId
@@ -350,7 +350,7 @@ [Substitute] IHttpClient httpClient
350350
await host.InvokeLambda(inputStream, cancellationToken);
351351

352352
await httpClient.Received().PutJson(
353-
Is(request.ResponseURL),
353+
Is(request.ResponseURL!),
354354
Is<CustomResourceResponse<TestCustomResourceOutputData>>(response =>
355355
response.Status == CustomResourceResponseStatus.Success &&
356356
response.PhysicalResourceId == physicalResourceId
@@ -360,6 +360,42 @@ await httpClient.Received().PutJson(
360360
);
361361
}
362362

363+
[Test, Auto]
364+
public async Task ShouldNotRespondSuccessIfResponseURLIsNull(
365+
ServiceCollection serviceCollection,
366+
string stackId,
367+
JsonSerializer serializer,
368+
CustomResourceRequest<object> request,
369+
[Substitute] TestCustomResourceLambda lambda,
370+
[Substitute] IHttpClient httpClient
371+
)
372+
{
373+
serviceCollection.AddSingleton(httpClient);
374+
request.ResponseURL = null;
375+
376+
var serviceProvider = serviceCollection.BuildServiceProvider();
377+
var cancellationToken = new CancellationToken(false);
378+
var host = new TestCustomResourceLambdaHost(lambdaHost =>
379+
{
380+
lambdaHost.Lambda = lambda;
381+
lambdaHost.Scope = serviceProvider.CreateScope();
382+
lambdaHost.Serializer = serializer;
383+
});
384+
385+
request.RequestType = CustomResourceRequestType.Create;
386+
request.StackId = stackId;
387+
388+
using var inputStream = await StreamUtils.CreateJsonStream(request);
389+
await host.InvokeLambda(inputStream, cancellationToken);
390+
391+
await httpClient.DidNotReceiveWithAnyArgs().PutJson(
392+
default!,
393+
default(CustomResourceResponse<TestCustomResourceOutputData>)!,
394+
default!,
395+
default!
396+
);
397+
}
398+
363399
[Test, Auto]
364400
public async Task ShouldRespondFailureWithReason(
365401
string reason,
@@ -393,7 +429,7 @@ [Substitute] IHttpClient httpClient
393429
await host.InvokeLambda(inputStream, cancellationToken);
394430

395431
await httpClient.Received().PutJson(
396-
Is(request.ResponseURL),
432+
Is(request.ResponseURL!),
397433
Is<CustomResourceResponse<TestCustomResourceOutputData>>(response =>
398434
response.Status == CustomResourceResponseStatus.Failed &&
399435
response.Reason == reason
@@ -506,7 +542,7 @@ [Substitute] IHttpClient httpClient
506542
await host.InvokeLambda(inputStream, cancellationToken);
507543

508544
await httpClient.Received().PutJson(
509-
Is(request.ResponseURL),
545+
Is(request.ResponseURL!),
510546
Is<CustomResourceResponse<TestCustomResourceOutputData>>(response =>
511547
response.Status == CustomResourceResponseStatus.Failed &&
512548
response.RequestId == requestId
@@ -549,7 +585,7 @@ [Substitute] IHttpClient httpClient
549585
await host.InvokeLambda(inputStream, cancellationToken);
550586

551587
await httpClient.Received().PutJson(
552-
Is(request.ResponseURL),
588+
Is(request.ResponseURL!),
553589
Is<CustomResourceResponse<TestCustomResourceOutputData>>(response =>
554590
response.Status == CustomResourceResponseStatus.Failed &&
555591
response.StackId == stackId
@@ -592,7 +628,7 @@ [Substitute] IHttpClient httpClient
592628
await host.InvokeLambda(inputStream, cancellationToken);
593629

594630
await httpClient.Received().PutJson(
595-
Is(request.ResponseURL),
631+
Is(request.ResponseURL!),
596632
Is<CustomResourceResponse<TestCustomResourceOutputData>>(response =>
597633
response.Status == CustomResourceResponseStatus.Failed &&
598634
response.LogicalResourceId == logicalResourceId
@@ -635,7 +671,7 @@ [Substitute] IHttpClient httpClient
635671
await host.InvokeLambda(inputStream, cancellationToken);
636672

637673
await httpClient.Received().PutJson(
638-
Is(request.ResponseURL),
674+
Is(request.ResponseURL!),
639675
Is<CustomResourceResponse<TestCustomResourceOutputData>>(response =>
640676
response.Status == CustomResourceResponseStatus.Failed &&
641677
response.PhysicalResourceId == physicalResourceId

0 commit comments

Comments
 (0)