diff --git a/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/README.md b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/README.md index d4ce87efd..7b83c82da 100644 --- a/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/README.md +++ b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/README.md @@ -42,7 +42,7 @@ Conformance/ ## Coverage -All nine suites are implemented (one handler project per requirement id): +All ten suites are implemented (one handler project per requirement id): | Suite | Ids | Handlers | |-------|-----|----------| @@ -55,6 +55,7 @@ All nine suites are implemented (one handler project per requirement id): | `wait_for_callback` | 7-1 .. 7-15 | 15 | | `parallel` | 8-1 .. 8-22 (8-15 n/a) | 21 | | `map` | 9-1 .. 9-18 (9-14 n/a) | 17 | +| `static_typing` | 12-1 .. 12-2 | 2 | A few requirement ids have no .NET handler because the SDK intentionally lacks the feature they exercise (e.g. per-item / whole-result serdes slots in `map`); diff --git a/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/scripts/build_examples.sh b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/scripts/build_examples.sh index 4ce59e368..6707491ab 100755 --- a/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/scripts/build_examples.sh +++ b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/scripts/build_examples.sh @@ -10,7 +10,7 @@ # ./build_examples.sh [operation...] # # Operations (default: every suite directory found next to the templates): -# step wait callback child invoke parallel map wait_for_callback wait_for_condition +# step wait callback child invoke parallel map static_typing wait_for_callback wait_for_condition # # Examples: # ./build_examples.sh step diff --git a/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/static_typing/ParallelEarlyStart/Function.cs b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/static_typing/ParallelEarlyStart/Function.cs new file mode 100644 index 000000000..56f3fa9c4 --- /dev/null +++ b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/static_typing/ParallelEarlyStart/Function.cs @@ -0,0 +1,44 @@ +// 12-2: Parallel branch starts before registration is sealed +using Amazon.Lambda.Core; +using Amazon.Lambda.DurableExecution; +using Amazon.Lambda.RuntimeSupport; +using Amazon.Lambda.Serialization.SystemTextJson; + +namespace ParallelEarlyStart; + +public class Function +{ + public static async Task Main(string[] args) + { + var handler = new Function(); + var serializer = new DefaultLambdaJsonSerializer(); + using var handlerWrapper = HandlerWrapper.GetHandlerWrapper(handler.Handler, serializer); + using var bootstrap = new LambdaBootstrap(handlerWrapper); + await bootstrap.RunAsync(); + } + + public Task Handler( + DurableExecutionInvocationInput input, ILambdaContext context) + => DurableFunction.WrapAsync>(Workflow, input, context); + + private async Task> Workflow(object? input, IDurableContext context) + { + string firstResult; + IParallelBranch second; + + await using (var parallel = context.CreateParallel( + name: "early-start", + config: new ParallelConfig { MaxConcurrency = 1 })) + { + IParallelBranch first = parallel.BranchAsync( + "first", (_, _) => Task.FromResult("ready")); + firstResult = await first; + + second = parallel.BranchAsync( + "second", (_, _) => Task.FromResult(firstResult + "-second")); + await parallel.CompleteAsync(); + } + + return new List { firstResult, await second }; + } +} diff --git a/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/static_typing/ParallelEarlyStart/ParallelEarlyStart.csproj b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/static_typing/ParallelEarlyStart/ParallelEarlyStart.csproj new file mode 100644 index 000000000..4b354e178 --- /dev/null +++ b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/static_typing/ParallelEarlyStart/ParallelEarlyStart.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + Exe + true + bootstrap + enable + enable + + + + + + + + + + diff --git a/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/static_typing/ParallelTypedBranches/Function.cs b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/static_typing/ParallelTypedBranches/Function.cs new file mode 100644 index 000000000..c4cc4b768 --- /dev/null +++ b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/static_typing/ParallelTypedBranches/Function.cs @@ -0,0 +1,52 @@ +// 12-1: Parallel with independently typed heterogeneous branch handles +using Amazon.Lambda.Core; +using Amazon.Lambda.DurableExecution; +using Amazon.Lambda.RuntimeSupport; +using Amazon.Lambda.Serialization.SystemTextJson; + +namespace ParallelTypedBranches; + +public class Function +{ + public static async Task Main(string[] args) + { + var handler = new Function(); + var serializer = new DefaultLambdaJsonSerializer(); + using var handlerWrapper = HandlerWrapper.GetHandlerWrapper(handler.Handler, serializer); + using var bootstrap = new LambdaBootstrap(handlerWrapper); + await bootstrap.RunAsync(); + } + + public Task Handler( + DurableExecutionInvocationInput input, ILambdaContext context) + => DurableFunction.WrapAsync>(Workflow, input, context); + + private async Task> Workflow(object? input, IDurableContext context) + { + IParallelBranch inventory; + IParallelBranch payment; + IParallelBranch> quote; + + await using (var parallel = context.CreateParallel( + name: "typed-branches", + config: new ParallelConfig { MaxConcurrency = 1 })) + { + inventory = parallel.BranchAsync( + "inventory", (_, _) => Task.FromResult("reserved")); + payment = parallel.BranchAsync( + "payment", (_, _) => Task.FromResult(200)); + quote = parallel.BranchAsync( + "quote", (_, _) => Task.FromResult(new Dictionary + { + ["currency"] = "USD" + })); + + await parallel.CompleteAsync(); + } + + string inventoryResult = await inventory; + int paymentResult = await payment; + Dictionary quoteResult = await quote; + return new List { inventoryResult, paymentResult, quoteResult }; + } +} diff --git a/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/static_typing/ParallelTypedBranches/ParallelTypedBranches.csproj b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/static_typing/ParallelTypedBranches/ParallelTypedBranches.csproj new file mode 100644 index 000000000..4b354e178 --- /dev/null +++ b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/static_typing/ParallelTypedBranches/ParallelTypedBranches.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + Exe + true + bootstrap + enable + enable + + + + + + + + + + diff --git a/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/template_static_typing.yaml b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/template_static_typing.yaml new file mode 100644 index 000000000..599898e05 --- /dev/null +++ b/Libraries/test/Amazon.Lambda.DurableExecution.IntegrationTests/Conformance/template_static_typing.yaml @@ -0,0 +1,68 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Durable Execution Conformance Test Examples - .NET (Static Typing) +Globals: + Function: + Runtime: dotnet8 + Timeout: 60 + MemorySize: 512 + +Resources: + DurableFunctionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: lambda.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole + Policies: + - PolicyName: DurableExecutionPolicy + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - lambda:CheckpointDurableExecution + - lambda:GetDurableExecutionState + Resource: '*' + + ParallelTypedBranches: + Type: AWS::Serverless::Function + TestingMetadata: + TestDescription: ["12-1"] + Metadata: + BuildMethod: makefile + Properties: + CodeUri: publish/ParallelTypedBranches/ + Handler: bootstrap + Description: Parallel with independently typed heterogeneous branch handles + Role: + Fn::GetAtt: + - DurableFunctionRole + - Arn + DurableConfig: + RetentionPeriodInDays: 7 + ExecutionTimeout: 300 + + ParallelEarlyStart: + Type: AWS::Serverless::Function + TestingMetadata: + TestDescription: ["12-2"] + Metadata: + BuildMethod: makefile + Properties: + CodeUri: publish/ParallelEarlyStart/ + Handler: bootstrap + Description: Parallel branch completes before later branches are registered + Role: + Fn::GetAtt: + - DurableFunctionRole + - Arn + DurableConfig: + RetentionPeriodInDays: 7 + ExecutionTimeout: 300