diff --git a/README.md b/README.md index a7101cb..f3bcfae 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,50 @@ var lambdaConstruct = new LambdaFunctionConstruct(this, "MyLambda", new LambdaFu }); ``` +### Lambda with Custom Memory and Timeout + +```csharp +var lambdaConstruct = new LambdaFunctionConstruct(this, "MyLambda", new LambdaFunctionConstructProps +{ + FunctionName = "my-function", + FunctionSuffix = "prod", + AssetPath = "./lambda-deployment.zip", + RoleName = "my-function-role", + PolicyName = "my-function-policy", + MemorySize = 2048, // Custom memory allocation (default: 1024 MB) + TimeoutInSeconds = 30, // Custom timeout (default: 6 seconds) + EnvironmentVariables = new Dictionary + { + { "ENVIRONMENT", "production" } + } +}); +``` + +### Lambda with Function URL for Direct HTTP Access + +```csharp +var lambdaConstruct = new LambdaFunctionConstruct(this, "MyLambda", new LambdaFunctionConstructProps +{ + FunctionName = "my-api", + FunctionSuffix = "prod", + AssetPath = "./lambda-deployment.zip", + RoleName = "my-api-role", + PolicyName = "my-api-policy", + GenerateUrl = true, // Enable Function URL for direct HTTP access + MemorySize = 512, // Optimized for lightweight API + TimeoutInSeconds = 15, // API timeout + EnvironmentVariables = new Dictionary + { + { "ENVIRONMENT", "production" }, + { "CORS_ORIGINS", "*" } + } +}); + +// Access the function URL domain +string functionUrlDomain = lambdaConstruct.LiveAliasFunctionUrlDomain; +Console.WriteLine($"Function URL: https://{functionUrlDomain}"); +``` + ## Features ### 🚀 LambdaFunctionConstruct @@ -111,6 +155,8 @@ The main construct that creates a complete Lambda function setup with: - **CloudWatch Logs**: Explicit log group with configurable retention (default: 2 weeks) - **OpenTelemetry**: Optional AWS OTEL Collector layer integration - **SnapStart**: Optional AWS Lambda SnapStart for improved cold start performance +- **Function URLs**: Optional direct HTTP access without API Gateway +- **Configurable Resources**: Customizable memory allocation and timeout settings - **Versioning**: Automatic version creation with "live" alias - **Multi-target Permissions**: Applies permissions to function, version, and alias @@ -276,6 +322,9 @@ table.AttachStreamLambda(streamProcessor.Function); | `AssetPath` | `string` | Path to Lambda deployment package | Required | | `RoleName` | `string` | IAM role name | Required | | `PolicyName` | `string` | IAM policy name | Required | +| `MemorySize` | `double` | Memory allocation in MB | `1024` | +| `TimeoutInSeconds` | `double` | Function timeout in seconds | `6` | +| `GenerateUrl` | `bool` | Enable Function URL for direct HTTP access | `false` | | `PolicyStatements` | `PolicyStatement[]` | Custom IAM policy statements | `[]` | | `EnvironmentVariables` | `IDictionary` | Environment variables | `{}` | | `IncludeOtelLayer` | `bool` | Enable OpenTelemetry layer | `true` | @@ -325,6 +374,9 @@ public void MyStack_ShouldCreateApiFunction() var props = CdkTestHelper.CreatePropsBuilder("./my-lambda.zip") .WithFunctionName("my-api") .WithFunctionSuffix("prod") + .WithMemorySize(2048) + .WithTimeoutInSeconds(30) + .WithGenerateUrl() .WithDynamoDbAccess("users-table") .WithApiGatewayPermission("arn:aws:execute-api:us-east-1:123456789012:abcdef123/prod/GET/users") .WithEnvironmentVariable("TABLE_NAME", "users-table") @@ -646,6 +698,11 @@ var staticAssetPath = CdkTestHelper.GetTestAssetPath("TestAssets/my-site"); | `ShouldHaveLogGroup(functionName, retentionDays)` | Verify log group configuration | | `ShouldHaveSnapStart()` | Verify SnapStart is enabled | | `ShouldNotHaveSnapStart()` | Verify SnapStart is disabled | +| `ShouldHaveMemorySize(memorySize)` | Verify Lambda memory allocation | +| `ShouldHaveTimeout(timeoutInSeconds)` | Verify Lambda timeout configuration | +| `ShouldHaveFunctionUrl(authType)` | Verify Function URL exists with specified auth | +| `ShouldNotHaveFunctionUrl()` | Verify no Function URL is configured | +| `ShouldHaveFunctionUrlOutput(stackName, constructId)` | Verify Function URL CloudFormation output | #### Static Site Assertions @@ -693,6 +750,9 @@ var staticAssetPath = CdkTestHelper.GetTestAssetPath("TestAssets/my-site"); | `WithCustomPolicy(policyStatement)` | Add custom IAM policy statement | | `WithCustomPermission(permission)` | Add custom Lambda permission | | `WithSnapStart(bool)` | Enable/disable Lambda SnapStart | +| `WithMemorySize(memorySize)` | Set custom memory allocation | +| `WithTimeoutInSeconds(timeout)` | Set custom timeout | +| `WithGenerateUrl(bool)` | Enable/disable Function URL | #### Static Site Props Builder diff --git a/src/LayeredCraft.Cdk.Constructs/LambdaFunctionConstruct.cs b/src/LayeredCraft.Cdk.Constructs/LambdaFunctionConstruct.cs index 91cb617..2f57adb 100644 --- a/src/LayeredCraft.Cdk.Constructs/LambdaFunctionConstruct.cs +++ b/src/LayeredCraft.Cdk.Constructs/LambdaFunctionConstruct.cs @@ -3,12 +3,22 @@ using Amazon.CDK.AWS.Lambda; using Amazon.CDK.AWS.Logs; using Constructs; +using LayeredCraft.Cdk.Constructs.Extensions; using LayeredCraft.Cdk.Constructs.Models; namespace LayeredCraft.Cdk.Constructs; public class LambdaFunctionConstruct : Construct { + /// + /// The domain of the function URL if GenerateUrl is enabled, null otherwise. + /// + public readonly string? LiveAliasFunctionUrlDomain; + + /// + /// The underlying Lambda function for advanced configuration. + /// + public readonly Function LambdaFunction; public LambdaFunctionConstruct(Construct scope, string id, ILambdaFunctionConstructProps props) : base(scope, id) { var region = Stack.Of(this).Region; @@ -59,15 +69,15 @@ public LambdaFunctionConstruct(Construct scope, string id, ILambdaFunctionConstr RemovalPolicy = RemovalPolicy.DESTROY }); - var lambda = new Function(this, $"{id}-function", new FunctionProps + LambdaFunction = new Function(this, $"{id}-function", new FunctionProps { FunctionName = $"{props.FunctionName}-{props.FunctionSuffix}", Runtime = Runtime.PROVIDED_AL2023, Handler = "bootstrap", Code = Code.FromAsset(props.AssetPath), Role = role, - MemorySize = 1024, - Timeout = Duration.Seconds(6), + MemorySize = props.MemorySize, + Timeout = Duration.Seconds(props.TimeoutInSeconds), Environment = props.EnvironmentVariables, LogGroup = logGroup, Tracing = props.IncludeOtelLayer ? Tracing.ACTIVE : Tracing.DISABLED, @@ -78,16 +88,16 @@ public LambdaFunctionConstruct(Construct scope, string id, ILambdaFunctionConstr }); if (props.IncludeOtelLayer) { - lambda.AddLayers(LayerVersion.FromLayerVersionArn(this, "OTELLambdaLayer", + LambdaFunction.AddLayers(LayerVersion.FromLayerVersionArn(this, "OTELLambdaLayer", $"arn:aws:lambda:{region}:901920570463:layer:aws-otel-collector-amd64-ver-0-102-1:1")); } // ✅ Create a new version on every deployment - var currentVersion = lambda.CurrentVersion; + var currentVersion = LambdaFunction.CurrentVersion; if (props.EnableSnapStart) { - var cfnFunction = (CfnFunction)lambda.Node.DefaultChild!; + var cfnFunction = (CfnFunction)LambdaFunction.Node.DefaultChild!; cfnFunction.AddPropertyOverride("SnapStart", new Dictionary { ["ApplyOn"] = "PublishedVersions" @@ -99,13 +109,34 @@ public LambdaFunctionConstruct(Construct scope, string id, ILambdaFunctionConstr AliasName = "live", Version = currentVersion, }); + AddPermissionsToAllTargets( baseId: $"{id}-permission", - function: lambda, - version: lambda.CurrentVersion, + function: LambdaFunction, + version: LambdaFunction.CurrentVersion, alias: alias, permissions: props.Permissions ); + + if (props.GenerateUrl) + { + var functionUrl = alias.AddFunctionUrl(new FunctionUrlProps + { + AuthType = FunctionUrlAuthType.NONE + }); + + LiveAliasFunctionUrlDomain = Fn.Select(2, Fn.Split("/", functionUrl.Url)); + + _ = new CfnOutput(this, $"{id}-url-output", new CfnOutputProps + { + ExportName = Stack.Of(this).CreateExportName(id, "url-output"), + Value = functionUrl.Url + }); + } + else + { + LiveAliasFunctionUrlDomain = null; + } } private void AddPermissionsToAllTargets(string baseId, IFunction function, IVersion version, IAlias? alias, List permissions) diff --git a/src/LayeredCraft.Cdk.Constructs/Models/LambdaFunctionConstructProps.cs b/src/LayeredCraft.Cdk.Constructs/Models/LambdaFunctionConstructProps.cs index f5cff17..3114e63 100644 --- a/src/LayeredCraft.Cdk.Constructs/Models/LambdaFunctionConstructProps.cs +++ b/src/LayeredCraft.Cdk.Constructs/Models/LambdaFunctionConstructProps.cs @@ -9,11 +9,14 @@ public interface ILambdaFunctionConstructProps string AssetPath { get; set; } string RoleName { get; set; } string PolicyName { get; set; } + double MemorySize { get; set; } + double TimeoutInSeconds { get; set; } PolicyStatement[] PolicyStatements { get; set; } IDictionary EnvironmentVariables { get; set; } bool IncludeOtelLayer { get; set; } List Permissions { get; set; } bool EnableSnapStart { get; set; } + bool GenerateUrl { get; set; } } public sealed record LambdaFunctionConstructProps : ILambdaFunctionConstructProps { @@ -22,9 +25,12 @@ public sealed record LambdaFunctionConstructProps : ILambdaFunctionConstructProp public required string AssetPath { get; set; } public required string RoleName { get; set; } public required string PolicyName { get; set; } + public double MemorySize { get; set; } = 1024; + public double TimeoutInSeconds { get; set; } = 6; public PolicyStatement[] PolicyStatements { get; set; } = []; public IDictionary EnvironmentVariables { get; set; } = new Dictionary(); public bool IncludeOtelLayer { get; set; } = true; public List Permissions { get; set; } = []; public bool EnableSnapStart { get; set; } = false; + public bool GenerateUrl { get; set; } = false; } \ No newline at end of file diff --git a/src/LayeredCraft.Cdk.Constructs/Testing/LambdaFunctionConstructAssertions.cs b/src/LayeredCraft.Cdk.Constructs/Testing/LambdaFunctionConstructAssertions.cs index 4a3a308..6895d89 100644 --- a/src/LayeredCraft.Cdk.Constructs/Testing/LambdaFunctionConstructAssertions.cs +++ b/src/LayeredCraft.Cdk.Constructs/Testing/LambdaFunctionConstructAssertions.cs @@ -172,4 +172,73 @@ public static void ShouldNotHaveSnapStart(this Template template) { "SnapStart", Match.AnyValue() } }))); } + + /// + /// Asserts that the template contains a Lambda function with the specified memory size. + /// + /// The CDK template to assert against + /// Expected memory size in MB + public static void ShouldHaveMemorySize(this Template template, int memorySize) + { + template.HasResourceProperties("AWS::Lambda::Function", Match.ObjectLike(new Dictionary + { + { "MemorySize", memorySize } + })); + } + + /// + /// Asserts that the template contains a Lambda function with the specified timeout. + /// + /// The CDK template to assert against + /// Expected timeout in seconds + public static void ShouldHaveTimeout(this Template template, int timeoutInSeconds) + { + template.HasResourceProperties("AWS::Lambda::Function", Match.ObjectLike(new Dictionary + { + { "Timeout", timeoutInSeconds } + })); + } + + /// + /// Asserts that the template contains a Lambda function URL with the specified configuration. + /// + /// The CDK template to assert against + /// Expected authentication type (default: NONE) + public static void ShouldHaveFunctionUrl(this Template template, string authType = "NONE") + { + template.HasResourceProperties("AWS::Lambda::Url", Match.ObjectLike(new Dictionary + { + { "AuthType", authType } + })); + } + + /// + /// Asserts that the template does not contain any Lambda function URLs. + /// + /// The CDK template to assert against + public static void ShouldNotHaveFunctionUrl(this Template template) + { + template.ResourceCountIs("AWS::Lambda::Url", 0); + } + + /// + /// Asserts that the template contains a CloudFormation output for the function URL. + /// + /// The CDK template to assert against + /// The stack name used for export naming + /// The construct ID used for export naming + public static void ShouldHaveFunctionUrlOutput(this Template template, string stackName, string constructId) + { + var outputs = template.FindOutputs("*", new Dictionary + { + { "Export", Match.ObjectLike(new Dictionary + { + { "Name", $"{stackName}-{constructId}-url-output" } + }) } + }); + + if (outputs.Count != 1) + throw new Exception($"Expected 1 function URL output but found {outputs.Count}"); + } + } \ No newline at end of file diff --git a/src/LayeredCraft.Cdk.Constructs/Testing/LambdaFunctionConstructPropsBuilder.cs b/src/LayeredCraft.Cdk.Constructs/Testing/LambdaFunctionConstructPropsBuilder.cs index 1264a41..1fe2d32 100644 --- a/src/LayeredCraft.Cdk.Constructs/Testing/LambdaFunctionConstructPropsBuilder.cs +++ b/src/LayeredCraft.Cdk.Constructs/Testing/LambdaFunctionConstructPropsBuilder.cs @@ -14,11 +14,14 @@ public class LambdaFunctionConstructPropsBuilder private string _assetPath = "./test-lambda.zip"; private string _roleName = "test-role"; private string _policyName = "test-policy"; + private double _memorySize = 1024; + private double _timeoutInSeconds = 6; private readonly List _policyStatements = new(); private readonly Dictionary _environmentVariables = new(); private bool _includeOtelLayer = true; private readonly List _permissions = new(); private bool _enableSnapStart = false; + private bool _generateUrl = false; /// /// Sets the function name. @@ -219,6 +222,39 @@ public LambdaFunctionConstructPropsBuilder WithSnapStart(bool enabled = true) return this; } + /// + /// Sets the memory size for the Lambda function. + /// + /// The memory size in MB + /// The builder instance for method chaining + public LambdaFunctionConstructPropsBuilder WithMemorySize(double memorySize) + { + _memorySize = memorySize; + return this; + } + + /// + /// Sets the timeout for the Lambda function. + /// + /// The timeout in seconds + /// The builder instance for method chaining + public LambdaFunctionConstructPropsBuilder WithTimeoutInSeconds(double timeoutInSeconds) + { + _timeoutInSeconds = timeoutInSeconds; + return this; + } + + /// + /// Enables or disables function URL generation for direct HTTP access. + /// + /// Whether to generate a function URL + /// The builder instance for method chaining + public LambdaFunctionConstructPropsBuilder WithGenerateUrl(bool generateUrl = true) + { + _generateUrl = generateUrl; + return this; + } + /// /// Builds the LambdaFunctionConstructProps instance. /// @@ -232,11 +268,14 @@ public LambdaFunctionConstructProps Build() AssetPath = _assetPath, RoleName = _roleName, PolicyName = _policyName, + MemorySize = _memorySize, + TimeoutInSeconds = _timeoutInSeconds, PolicyStatements = [.. _policyStatements], EnvironmentVariables = _environmentVariables, IncludeOtelLayer = _includeOtelLayer, Permissions = _permissions, - EnableSnapStart = _enableSnapStart + EnableSnapStart = _enableSnapStart, + GenerateUrl = _generateUrl }; } } \ No newline at end of file diff --git a/test/LayeredCraft.Cdk.Constructs.Tests/LambdaFunctionConstructTests.cs b/test/LayeredCraft.Cdk.Constructs.Tests/LambdaFunctionConstructTests.cs index 2502a54..f931433 100644 --- a/test/LayeredCraft.Cdk.Constructs.Tests/LambdaFunctionConstructTests.cs +++ b/test/LayeredCraft.Cdk.Constructs.Tests/LambdaFunctionConstructTests.cs @@ -4,6 +4,7 @@ using LayeredCraft.Cdk.Constructs; using LayeredCraft.Cdk.Constructs.Models; using LayeredCraft.Cdk.Constructs.Tests.TestKit.Attributes; +using LayeredCraft.Cdk.Constructs.Tests.TestKit.Extensions; using LayeredCraft.Cdk.Constructs.Testing; namespace LayeredCraft.Cdk.Constructs.Tests; @@ -30,8 +31,8 @@ public void Construct_ShouldCreateLambdaFunction(LambdaFunctionConstructProps pr { "FunctionName", $"{props.FunctionName}-{props.FunctionSuffix}" }, { "Runtime", "provided.al2023" }, { "Handler", "bootstrap" }, - { "MemorySize", 1024 }, - { "Timeout", 6 } + { "MemorySize", props.MemorySize }, + { "Timeout", props.TimeoutInSeconds } })); } @@ -219,7 +220,7 @@ public void Construct_ShouldCreateVersionAndAlias(LambdaFunctionConstructProps p } [Theory] - [LambdaFunctionConstructAutoData] + [LambdaFunctionConstructAutoData(generateUrl: false)] public void Construct_ShouldAddPermissionsToAllTargets(LambdaFunctionConstructProps props) { var app = new App(); @@ -237,7 +238,7 @@ public void Construct_ShouldAddPermissionsToAllTargets(LambdaFunctionConstructPr } [Theory] - [LambdaFunctionConstructAutoData(includePermissions: false)] + [LambdaFunctionConstructAutoData(includePermissions: false, generateUrl: false)] public void Construct_ShouldHandleEmptyPermissionsList(LambdaFunctionConstructProps props) { var app = new App(); @@ -309,4 +310,210 @@ public void Construct_ShouldEnableSnapStartWhenConfigured(LambdaFunctionConstruc // Verify that SnapStart is enabled for published versions template.ShouldHaveSnapStart(); } + + [Fact] + public void Construct_ShouldUseConfigurableMemorySize() + { + // Arrange + var app = new App(); + var stack = new Stack(app, "test-stack", new StackProps + { + Env = new Amazon.CDK.Environment { Account = "123456789012", Region = "us-east-1" } + }); + + var props = CdkTestHelper.CreatePropsBuilder(AssetPathExtensions.GetTestLambdaZipPath()) + .WithMemorySize(2048) + .Build(); + + // Act + _ = new LambdaFunctionConstruct(stack, "test-construct", props); + var template = Template.FromStack(stack); + + // Assert - Using new assertion helper + template.ShouldHaveMemorySize(2048); + } + + [Fact] + public void Construct_ShouldUseConfigurableTimeout() + { + // Arrange + var app = new App(); + var stack = new Stack(app, "test-stack", new StackProps + { + Env = new Amazon.CDK.Environment { Account = "123456789012", Region = "us-east-1" } + }); + + var props = CdkTestHelper.CreatePropsBuilder(AssetPathExtensions.GetTestLambdaZipPath()) + .WithTimeoutInSeconds(30) + .Build(); + + // Act + _ = new LambdaFunctionConstruct(stack, "test-construct", props); + var template = Template.FromStack(stack); + + // Assert - Using new assertion helper + template.ShouldHaveTimeout(30); + } + + [Fact] + public void Construct_ShouldGenerateFunctionUrl_WhenEnabled() + { + // Arrange + var app = new App(); + var stack = new Stack(app, "test-stack", new StackProps + { + Env = new Amazon.CDK.Environment { Account = "123456789012", Region = "us-east-1" } + }); + + var props = CdkTestHelper.CreatePropsBuilder(AssetPathExtensions.GetTestLambdaZipPath()) + .WithGenerateUrl(true) + .Build(); + + // Act + var construct = new LambdaFunctionConstruct(stack, "test-construct", props); + var template = Template.FromStack(stack); + + // Assert - Using new assertion helpers + template.ShouldHaveFunctionUrl(); + template.ShouldHaveFunctionUrlOutput("test-stack", "test-construct"); + construct.LiveAliasFunctionUrlDomain.Should().NotBeNull(); + } + + [Fact] + public void Construct_ShouldNotGenerateFunctionUrl_WhenDisabled() + { + // Arrange + var app = new App(); + var stack = new Stack(app, "test-stack", new StackProps + { + Env = new Amazon.CDK.Environment { Account = "123456789012", Region = "us-east-1" } + }); + + var props = CdkTestHelper.CreatePropsBuilder(AssetPathExtensions.GetTestLambdaZipPath()) + .WithGenerateUrl(false) + .Build(); + + // Act + var construct = new LambdaFunctionConstruct(stack, "test-construct", props); + var template = Template.FromStack(stack); + + // Assert - Using new assertion helper + template.ShouldNotHaveFunctionUrl(); + construct.LiveAliasFunctionUrlDomain.Should().BeNull(); + } + + [Fact] + public void Construct_ShouldExposePublicProperties() + { + // Arrange + var app = new App(); + var stack = new Stack(app, "test-stack", new StackProps + { + Env = new Amazon.CDK.Environment { Account = "123456789012", Region = "us-east-1" } + }); + + var props = CdkTestHelper.CreatePropsBuilder(AssetPathExtensions.GetTestLambdaZipPath()) + .WithGenerateUrl() + .Build(); + + // Act + var construct = new LambdaFunctionConstruct(stack, "test-construct", props); + + // Assert + construct.LambdaFunction.Should().NotBeNull(); + // Function name will be a CDK token during construction, so check the props instead + props.FunctionName.Should().Be("test-function"); + props.FunctionSuffix.Should().Be("test"); + construct.LiveAliasFunctionUrlDomain.Should().NotBeNull(); + } + + [Fact] + public void Construct_ShouldMaintainBackwardCompatibility() + { + // Arrange + var app = new App(); + var stack = new Stack(app, "test-stack", new StackProps + { + Env = new Amazon.CDK.Environment { Account = "123456789012", Region = "us-east-1" } + }); + + // Create props the old way without new properties + var props = new LambdaFunctionConstructProps + { + FunctionName = "legacy-function", + FunctionSuffix = "test", + AssetPath = AssetPathExtensions.GetTestLambdaZipPath(), + RoleName = "legacy-role", + PolicyName = "legacy-policy" + // Not setting MemorySize, TimeoutInSeconds, or GenerateUrl - should use defaults + }; + + // Act + var construct = new LambdaFunctionConstruct(stack, "test-construct", props); + var template = Template.FromStack(stack); + + // Assert - should use default values + template.HasResourceProperties("AWS::Lambda::Function", Match.ObjectLike(new Dictionary + { + { "MemorySize", 1024 }, // Default + { "Timeout", 6 } // Default + })); + + template.ResourceCountIs("AWS::Lambda::Url", 0); // No URL by default + construct.LiveAliasFunctionUrlDomain.Should().BeNull(); + } + + [Fact] + public void PropsBuilder_ShouldConfigureMemorySize() + { + // Act + var props = CdkTestHelper.CreatePropsBuilder(AssetPathExtensions.GetTestLambdaZipPath()) + .WithMemorySize(512) + .Build(); + + // Assert + props.MemorySize.Should().Be(512); + } + + [Fact] + public void PropsBuilder_ShouldConfigureTimeout() + { + // Act + var props = CdkTestHelper.CreatePropsBuilder(AssetPathExtensions.GetTestLambdaZipPath()) + .WithTimeoutInSeconds(15) + .Build(); + + // Assert + props.TimeoutInSeconds.Should().Be(15); + } + + [Fact] + public void PropsBuilder_ShouldConfigureFunctionUrl() + { + // Act + var propsEnabled = CdkTestHelper.CreatePropsBuilder(AssetPathExtensions.GetTestLambdaZipPath()) + .WithGenerateUrl() + .Build(); + + var propsDisabled = CdkTestHelper.CreatePropsBuilder(AssetPathExtensions.GetTestLambdaZipPath()) + .WithGenerateUrl(false) + .Build(); + + // Assert + propsEnabled.GenerateUrl.Should().BeTrue(); + propsDisabled.GenerateUrl.Should().BeFalse(); + } + + [Fact] + public void PropsBuilder_ShouldHaveCorrectDefaults() + { + // Act + var props = CdkTestHelper.CreatePropsBuilder(AssetPathExtensions.GetTestLambdaZipPath()) + .Build(); + + // Assert + props.MemorySize.Should().Be(1024); + props.TimeoutInSeconds.Should().Be(6); + props.GenerateUrl.Should().BeFalse(); + } } \ No newline at end of file diff --git a/test/LayeredCraft.Cdk.Constructs.Tests/TestKit/Attributes/LambdaFunctionConstructAutoDataAttribute.cs b/test/LayeredCraft.Cdk.Constructs.Tests/TestKit/Attributes/LambdaFunctionConstructAutoDataAttribute.cs index 8a5641a..4538782 100644 --- a/test/LayeredCraft.Cdk.Constructs.Tests/TestKit/Attributes/LambdaFunctionConstructAutoDataAttribute.cs +++ b/test/LayeredCraft.Cdk.Constructs.Tests/TestKit/Attributes/LambdaFunctionConstructAutoDataAttribute.cs @@ -3,13 +3,13 @@ namespace LayeredCraft.Cdk.Constructs.Tests.TestKit.Attributes; -public class LambdaFunctionConstructAutoDataAttribute(bool includeOtelLayer = true, bool includePermissions = true) : AutoDataAttribute(() => CreateFixture(includeOtelLayer, includePermissions)) +public class LambdaFunctionConstructAutoDataAttribute(bool includeOtelLayer = true, bool includePermissions = true, bool generateUrl = false) : AutoDataAttribute(() => CreateFixture(includeOtelLayer, includePermissions, generateUrl)) { - private static IFixture CreateFixture(bool includeOtelLayer, bool includePermissions) + private static IFixture CreateFixture(bool includeOtelLayer, bool includePermissions, bool generateUrl) { return BaseFixtureFactory.CreateFixture(fixture => { - fixture.Customize(new LambdaFunctionConstructCustomization(includeOtelLayer, includePermissions)); + fixture.Customize(new LambdaFunctionConstructCustomization(includeOtelLayer, includePermissions, generateUrl)); }); } } \ No newline at end of file diff --git a/test/LayeredCraft.Cdk.Constructs.Tests/TestKit/Customizations/LambdaFunctionConstructCustomization.cs b/test/LayeredCraft.Cdk.Constructs.Tests/TestKit/Customizations/LambdaFunctionConstructCustomization.cs index 0bc303a..4c9ad9f 100644 --- a/test/LayeredCraft.Cdk.Constructs.Tests/TestKit/Customizations/LambdaFunctionConstructCustomization.cs +++ b/test/LayeredCraft.Cdk.Constructs.Tests/TestKit/Customizations/LambdaFunctionConstructCustomization.cs @@ -3,7 +3,7 @@ namespace LayeredCraft.Cdk.Constructs.Tests.TestKit.Customizations; -public class LambdaFunctionConstructCustomization(bool includeOtelLayer = true, bool includePermissions = true) +public class LambdaFunctionConstructCustomization(bool includeOtelLayer = true, bool includePermissions = true, bool generateUrl = false) : ICustomization { public void Customize(IFixture fixture) @@ -36,6 +36,7 @@ public void Customize(IFixture fixture) .With(props => props.Permissions, includePermissions ? [fixture.Create()] : []) - .With(props => props.EnableSnapStart, false)); + .With(props => props.EnableSnapStart, false) + .With(props => props.GenerateUrl, generateUrl)); } } \ No newline at end of file