diff --git a/powertools-e2e-tests/README.md b/powertools-e2e-tests/README.md index ea1546025..42fe9191b 100644 --- a/powertools-e2e-tests/README.md +++ b/powertools-e2e-tests/README.md @@ -1,10 +1,13 @@ ## End-to-end tests This module is internal and meant to be used for end-to-end (E2E) testing of Lambda Powertools for Java. -__Prerequisites__: an AWS account is needed as well as a local environment able to reach this account +__Prerequisites__: +- An AWS account is needed as well as a local environment able to reach this account ([credentials](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/credentials.html)). +- [Java 11+](https://docs.aws.amazon.com/corretto/latest/corretto-11-ug/downloads-list.html) +- [Docker](https://docs.docker.com/engine/install/) -To execute the E2E tests, use the following command: `mvn clean verify -Pe2e` +To execute the E2E tests, use the following command: `export JAVA_VERSION=11 && mvn clean verify -Pe2e` ### Under the hood This module leverages the following components: diff --git a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/Infrastructure.java b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/Infrastructure.java index 2afd6a30a..a1d17369e 100644 --- a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/Infrastructure.java +++ b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/Infrastructure.java @@ -33,13 +33,22 @@ import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; import static java.util.Collections.singletonList; +/** + * This class is in charge of bootstrapping the infrastructure for the tests. + *
+ * Tests are actually run on AWS, so we need to provision Lambda functions, DynamoDB table (for Idempotency), + * CloudWatch log groups, ... + *
+ * It uses the Cloud Development Kit (CDK) to define required resources. The CDK stack is then synthesized to retrieve + * the CloudFormation templates and the assets (function jars). Assets are uploaded to S3 (with the SDK `PutObjectRequest`) + * and the CloudFormation stack is created (with the SDK `createStack`) + */ public class Infrastructure { private static final Logger LOG = LoggerFactory.getLogger(Infrastructure.class); @@ -92,6 +101,10 @@ private Infrastructure(Builder builder) { .build(); } + /** + * Use the CloudFormation SDK to create the stack + * @return the name of the function deployed part of the stack + */ public String deploy() { uploadAssets(); LOG.info("Deploying '" + stackName + "' on account " + account); @@ -111,6 +124,9 @@ public String deploy() { return functionName; } + /** + * Destroy the CloudFormation stack + */ public void destroy() { LOG.info("Deleting '" + stackName + "' on account " + account); cfn.deleteStack(DeleteStackRequest.builder().stackName(stackName).build()); @@ -193,6 +209,10 @@ public Builder timeoutInSeconds(long timeoutInSeconds) { } } + /** + * Build the CDK Stack containing the required resources (Lambda function, LogGroup, DDB Table) + * @return the CDK stack + */ private Stack createStackWithLambda() { Stack stack = new Stack(app, stackName); List packagingInstruction = Arrays.asList( @@ -261,12 +281,18 @@ private Stack createStackWithLambda() { return stack; } + /** + * cdk synth to retrieve the CloudFormation template and assets directory + */ private void synthesize() { CloudAssembly synth = app.synth(); cfnTemplate = synth.getStackByName(stack.getStackName()).getTemplate(); cfnAssetDirectory = synth.getDirectory(); } + /** + * Upload assets (mainly lambda function jars) to S3 + */ private void uploadAssets() { Map assets = findAssets(); assets.forEach((objectKey, asset) -> { @@ -283,6 +309,10 @@ private void uploadAssets() { }); } + /** + * Reading the cdk assets.json file to retrieve the list of assets to push to S3 + * @return a map of assets + */ private Map findAssets() { Map assets = new HashMap<>(); try { diff --git a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/logging/InvocationLogs.java b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/logging/InvocationLogs.java index bad4c4bcb..1ae1cfad7 100644 --- a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/logging/InvocationLogs.java +++ b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/logging/InvocationLogs.java @@ -5,9 +5,12 @@ import java.util.Base64; import java.util.stream.IntStream; +/** + * Logs for a specific Lambda invocation + */ public class InvocationLogs { - private String[] logs; - private String[] functionLogs; + private final String[] logs; + private final String[] functionLogs; public InvocationLogs(String base64Logs, String requestId) { String rawLogs = new String(Base64.getDecoder().decode(base64Logs), StandardCharsets.UTF_8); diff --git a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/metrics/MetricsFetcher.java b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/metrics/MetricsFetcher.java index da44e4206..eb3cd63a4 100644 --- a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/metrics/MetricsFetcher.java +++ b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/metrics/MetricsFetcher.java @@ -20,6 +20,10 @@ import java.util.concurrent.Callable; import static java.time.Duration.ofSeconds; + +/** + * Class in charge of retrieving the actual metrics of a Lambda execution on CloudWatch + */ public class MetricsFetcher { private static final Logger LOG = LoggerFactory.getLogger(MetricsFetcher.class); @@ -30,6 +34,17 @@ public class MetricsFetcher { .region(region) .build(); + /** + * Retrieve the metric values from start to end. Different parameters are required (see {@link CloudWatchClient#getMetricData} for more info). + * Use a retry mechanism as metrics may not be available instantaneously after a function runs. + * @param start + * @param end + * @param period + * @param namespace + * @param metricName + * @param dimensions + * @return + */ public List fetchMetrics(Instant start, Instant end, int period, String namespace, String metricName, Map dimensions) { List dimensionsList = new ArrayList<>(); if (dimensions != null) diff --git a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/tracing/TraceFetcher.java b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/tracing/TraceFetcher.java index 4433876a1..b26dbd0fe 100644 --- a/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/tracing/TraceFetcher.java +++ b/powertools-e2e-tests/src/test/java/software/amazon/lambda/powertools/testutils/tracing/TraceFetcher.java @@ -26,6 +26,9 @@ import static java.time.Duration.ofSeconds; +/** + * Class in charge of retrieving the actual traces of a Lambda execution on X-Ray + */ public class TraceFetcher { private static final ObjectMapper MAPPER = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); @@ -36,6 +39,12 @@ public class TraceFetcher { private final String filterExpression; private final List excludedSegments; + /** + * @param start beginning of the time slot to search in + * @param end end of the time slot to search in + * @param filterExpression eventual filter for the search + * @param excludedSegments list of segment to exclude from the search + */ public TraceFetcher(Instant start, Instant end, String filterExpression, List excludedSegments) { this.start = start; this.end = end; @@ -47,6 +56,12 @@ public static Builder builder() { return new Builder(); } + /** + * Retrieve the traces corresponding to a specific function during a specific time slot. + * Use a retry mechanism as traces may not be available instantaneously after a function runs. + * + * @return traces + */ public Trace fetchTrace() { Callable callable = () -> { List traceIds = getTraceIds(); @@ -67,6 +82,11 @@ public Trace fetchTrace() { return status.getResult(); } + /** + * Retrieve traces from trace ids. + * @param traceIds + * @return + */ private Trace getTrace(List traceIds) { BatchGetTracesResponse tracesResponse = xray.batchGetTraces(BatchGetTracesRequest.builder() .traceIds(traceIds) @@ -110,6 +130,10 @@ private void getNestedSubSegments(List subsegments, Trace traceRes, }); } + /** + * Use the X-Ray SDK to retrieve the trace ids corresponding to a specific function during a specific time slot + * @return a list of trace ids + */ private List getTraceIds() { GetTraceSummariesResponse traceSummaries = xray.getTraceSummaries(GetTraceSummariesRequest.builder() .startTime(start)