Skip to content

Commit 845ae2a

Browse files
author
Fabiana Severin
committed
Add end-to-end integration tests
1 parent cfefd3b commit 845ae2a

8 files changed

Lines changed: 443 additions & 0 deletions

File tree

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# this workflow verifies that the integration test Lambda function builds successfully.
2+
# it does NOT deploy or run the tests (that requires AWS credentials and is done in
3+
# run-integration-test.yml).
4+
5+
name: Build integration tests
6+
7+
on:
8+
push:
9+
branches: [ main ]
10+
paths:
11+
- 'aws-lambda-java-log4j2/**'
12+
- 'aws-lambda-java-core/**'
13+
- 'lambda-integration-tests/**'
14+
pull_request:
15+
branches: [ '*' ]
16+
paths:
17+
- 'aws-lambda-java-log4j2/**'
18+
- 'aws-lambda-java-core/**'
19+
- 'lambda-integration-tests/**'
20+
- '.github/workflows/build-integration-test.yml'
21+
22+
permissions:
23+
contents: read
24+
25+
jobs:
26+
build:
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@v6
30+
31+
- name: Set up JDK
32+
uses: actions/setup-java@v5
33+
with:
34+
java-version: |
35+
8
36+
21
37+
distribution: corretto
38+
cache: maven
39+
40+
- name: Install core with Maven
41+
run: |
42+
export JAVA_HOME=$JAVA_HOME_8_X64
43+
mvn -B install --file aws-lambda-java-core/pom.xml
44+
45+
- name: Install log4j2 with Maven
46+
run: |
47+
export JAVA_HOME=$JAVA_HOME_8_X64
48+
mvn -B install --file aws-lambda-java-log4j2/pom.xml
49+
50+
# build the integration test function
51+
# this verifies that the function compiles and packages correctly.
52+
# the tests will run in run-integration-test.yml which deploys to AWS.
53+
- name: Package integration test function
54+
run: |
55+
export JAVA_HOME=$JAVA_HOME_21_X64
56+
mvn -B package --file lambda-integration-tests/log4j2-test-function/pom.xml
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# this workflow deploys a Lambda function that uses aws-lambda-java-log4j2,
2+
# invokes it, and verifies that logs arrive in CloudWatch.
3+
4+
name: Run integration tests
5+
6+
permissions:
7+
id-token: write
8+
contents: read
9+
10+
on:
11+
workflow_dispatch:
12+
push:
13+
branches: [ main ]
14+
paths:
15+
- 'aws-lambda-java-log4j2/**'
16+
- 'aws-lambda-java-core/**'
17+
- 'lambda-integration-tests/**'
18+
19+
jobs:
20+
run-integration-tests:
21+
# Only run on the main repo, not forks
22+
if: ${{ github.repository_owner == 'aws' }}
23+
runs-on: ubuntu-latest
24+
concurrency:
25+
group: integration-test
26+
cancel-in-progress: false
27+
steps:
28+
- uses: actions/checkout@v6
29+
30+
- name: Set up JDK
31+
uses: actions/setup-java@v5
32+
with:
33+
java-version: |
34+
8
35+
21
36+
distribution: corretto
37+
cache: maven
38+
39+
- name: Install SAM CLI
40+
uses: aws-actions/setup-sam@v2
41+
with:
42+
use-installer: true
43+
44+
- name: Configure AWS credentials
45+
uses: aws-actions/configure-aws-credentials@v6.0.0
46+
with:
47+
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
48+
role-session-name: ${{ secrets.ROLE_SESSION_NAME }}
49+
aws-region: ${{ secrets.AWS_REGION }}
50+
51+
- name: Install core with Maven
52+
run: |
53+
export JAVA_HOME=$JAVA_HOME_8_X64
54+
mvn -B install --file aws-lambda-java-core/pom.xml
55+
56+
- name: Install log4j2 with Maven
57+
run: |
58+
export JAVA_HOME=$JAVA_HOME_8_X64
59+
mvn -B install --file aws-lambda-java-log4j2/pom.xml
60+
61+
- name: Build SAM stack
62+
run: |
63+
export JAVA_HOME=$JAVA_HOME_21_X64
64+
cd lambda-integration-tests && sam build
65+
66+
- name: Validate SAM stack
67+
run: cd lambda-integration-tests && sam validate --lint
68+
69+
- name: Deploy stack
70+
id: deploy_stack
71+
env:
72+
AWS_REGION: ${{ secrets.AWS_REGION }}
73+
run: |
74+
cd lambda-integration-tests
75+
stackName="aws-lambda-java-log4j2-integ-test-$GITHUB_RUN_ID"
76+
echo "STACK_NAME=$stackName" >> "$GITHUB_OUTPUT"
77+
echo "Stack name = $stackName"
78+
sam deploy \
79+
--stack-name "${stackName}" \
80+
--parameter-overrides "ParameterKey=LambdaRole,ParameterValue=${{ secrets.AWS_LAMBDA_ROLE }}" \
81+
--no-confirm-changeset \
82+
--no-progressbar \
83+
--resolve-s3 \
84+
--capabilities CAPABILITY_IAM \
85+
2>&1 | tee /tmp/sam-deploy.log | tail -n 20
86+
LOG4J2_TEST_FUNCTION=$(sam list stack-outputs --stack-name "${stackName}" --output json | jq -r '.[] | select(.OutputKey=="Log4j2TestFunction") | .OutputValue')
87+
echo "LOG4J2_TEST_FUNCTION=$LOG4J2_TEST_FUNCTION" >> "$GITHUB_OUTPUT"
88+
echo "Function name: $LOG4J2_TEST_FUNCTION"
89+
90+
- name: Run integration test
91+
env:
92+
LOG4J2_TEST_FUNCTION: ${{ steps.deploy_stack.outputs.LOG4J2_TEST_FUNCTION }}
93+
AWS_REGION: ${{ secrets.AWS_REGION }}
94+
run: ./lambda-integration-tests/run-tests.sh
95+
96+
- name: Cleanup
97+
if: always() && steps.deploy_stack.outputs.STACK_NAME
98+
env:
99+
AWS_REGION: ${{ secrets.AWS_REGION }}
100+
STACK_NAME: ${{ steps.deploy_stack.outputs.STACK_NAME }}
101+
run: |
102+
sam delete --stack-name "${STACK_NAME}" --no-prompts --region "${AWS_REGION}"
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>com.amazonaws</groupId>
7+
<artifactId>log4j2-integration-test-function</artifactId>
8+
<version>1.0.0</version>
9+
<packaging>jar</packaging>
10+
11+
<name>Log4j2 Integration Test Function</name>
12+
<description>
13+
Lambda function used to verify that aws-lambda-java-log4j2 correctly emits logs to CloudWatch.
14+
</description>
15+
16+
<properties>
17+
<maven.compiler.source>21</maven.compiler.source>
18+
<maven.compiler.target>21</maven.compiler.target>
19+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
20+
<log4j.version>2.25.4</log4j.version>
21+
</properties>
22+
23+
<dependencies>
24+
<dependency>
25+
<groupId>com.amazonaws</groupId>
26+
<artifactId>aws-lambda-java-core</artifactId>
27+
<version>1.4.0</version>
28+
</dependency>
29+
<dependency>
30+
<groupId>com.amazonaws</groupId>
31+
<artifactId>aws-lambda-java-log4j2</artifactId>
32+
<version>1.6.4</version>
33+
</dependency>
34+
<dependency>
35+
<groupId>org.apache.logging.log4j</groupId>
36+
<artifactId>log4j-core</artifactId>
37+
<version>${log4j.version}</version>
38+
</dependency>
39+
<dependency>
40+
<groupId>org.apache.logging.log4j</groupId>
41+
<artifactId>log4j-api</artifactId>
42+
<version>${log4j.version}</version>
43+
</dependency>
44+
</dependencies>
45+
46+
<build>
47+
<plugins>
48+
<plugin>
49+
<groupId>org.apache.maven.plugins</groupId>
50+
<artifactId>maven-shade-plugin</artifactId>
51+
<version>3.6.1</version>
52+
<executions>
53+
<execution>
54+
<phase>package</phase>
55+
<goals>
56+
<goal>shade</goal>
57+
</goals>
58+
<configuration>
59+
<transformers>
60+
<transformer
61+
implementation="com.github.edwgiz.mavenShadePlugin.log4j2CacheTransformer.PluginsCacheFileTransformer">
62+
</transformer>
63+
</transformers>
64+
</configuration>
65+
</execution>
66+
</executions>
67+
<dependencies>
68+
<dependency>
69+
<groupId>com.github.edwgiz</groupId>
70+
<artifactId>maven-shade-plugin.log4j2-cachefile-transformer</artifactId>
71+
<version>2.8.1</version>
72+
</dependency>
73+
</dependencies>
74+
</plugin>
75+
</plugins>
76+
</build>
77+
</project>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package integ;
2+
3+
import com.amazonaws.services.lambda.runtime.Context;
4+
import com.amazonaws.services.lambda.runtime.RequestHandler;
5+
import org.apache.logging.log4j.LogManager;
6+
import org.apache.logging.log4j.Logger;
7+
8+
import java.util.Map;
9+
10+
/**
11+
* integration test handler that logs a marker string using Log4j2 with the LambdaAppender.
12+
* the test verifies that the marker appears in CloudWatch Logs, confirming end-to-end
13+
* log delivery through the aws-lambda-java-log4j2 library.
14+
*/
15+
public class Log4j2TestHandler implements RequestHandler<Map<String, String>, String> {
16+
17+
private static final Logger logger = LogManager.getLogger(Log4j2TestHandler.class);
18+
19+
@Override
20+
public String handleRequest(Map<String, String> event, Context context) {
21+
String marker = event.getOrDefault("marker", "NO_MARKER_PROVIDED");
22+
23+
logger.info("INTEG_TEST_MARKER: {}", marker);
24+
logger.debug("Debug level message with marker: {}", marker);
25+
logger.warn("Warning level message with marker: {}", marker);
26+
logger.error("Error level message with marker: {}", marker);
27+
28+
return "OK:" + marker;
29+
}
30+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Configuration status="WARN">
3+
<Appenders>
4+
<Lambda name="Lambda" format="${env:AWS_LAMBDA_LOG_FORMAT:-TEXT}">
5+
<LambdaTextFormat>
6+
<PatternLayout>
7+
<pattern>%d{yyyy-MM-dd HH:mm:ss} %X{AWSRequestId} %-5p %c{1}:%L - %m%n</pattern>
8+
</PatternLayout>
9+
</LambdaTextFormat>
10+
</Lambda>
11+
</Appenders>
12+
<Loggers>
13+
<Root level="DEBUG">
14+
<AppenderRef ref="Lambda" />
15+
</Root>
16+
</Loggers>
17+
</Configuration>
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# integration test script for aws-lambda-java-log4j2.
2+
# invokes the deployed lambda function and verifies logs appear in CloudWatch.
3+
4+
set -euo pipefail
5+
6+
FUNCTION_NAME="${LOG4J2_TEST_FUNCTION:?LOG4J2_TEST_FUNCTION env var is required}"
7+
REGION="${AWS_REGION:?AWS_REGION env var is required}"
8+
MARKER="integ-test-$(date +%s)-${RANDOM}"
9+
10+
echo "=== Log4j2 Integration Test ==="
11+
echo "Function: ${FUNCTION_NAME}"
12+
echo "Region: ${REGION}"
13+
echo "Marker: ${MARKER}"
14+
echo ""
15+
16+
# invoke the lambda function
17+
echo ">>> Invoking Lambda function..."
18+
INVOKE_OUTPUT=$(aws lambda invoke \
19+
--function-name "${FUNCTION_NAME}" \
20+
--region "${REGION}" \
21+
--payload "{\"marker\": \"${MARKER}\"}" \
22+
--cli-binary-format raw-in-base64-out \
23+
--output json \
24+
/tmp/integ-test-response.json) || {
25+
echo "FAIL: aws lambda invoke command failed with exit code $?"
26+
echo "Output: ${INVOKE_OUTPUT:-<empty>}"
27+
exit 1
28+
}
29+
30+
echo "Invoke output: ${INVOKE_OUTPUT}"
31+
RESPONSE=$(cat /tmp/integ-test-response.json)
32+
echo "Response payload: ${RESPONSE}"
33+
34+
# check for lambda execution errors
35+
FUNCTION_ERROR=$(echo "${INVOKE_OUTPUT}" | jq -r '.FunctionError // empty')
36+
if [ -n "${FUNCTION_ERROR}" ]; then
37+
echo "FAIL: Lambda function returned an execution error (FunctionError: ${FUNCTION_ERROR})"
38+
echo "Error response: ${RESPONSE}"
39+
exit 1
40+
fi
41+
42+
# verify the function executed successfully
43+
if echo "${RESPONSE}" | grep -q "OK:${MARKER}"; then
44+
echo ">>> Function invocation successful."
45+
else
46+
echo "FAIL: Unexpected response from Lambda function."
47+
echo "Expected response containing: OK:${MARKER}"
48+
echo "Got: ${RESPONSE}"
49+
exit 1
50+
fi
51+
52+
# query CloudWatch logs for the marker
53+
LOG_GROUP="/aws/lambda/${FUNCTION_NAME}"
54+
echo ""
55+
echo ">>> Querying CloudWatch Logs group: ${LOG_GROUP}"
56+
57+
MAX_ATTEMPTS=5
58+
WAIT_SECONDS=10
59+
FOUND=false
60+
61+
for attempt in $(seq 1 $MAX_ATTEMPTS); do
62+
echo ">>> Attempt ${attempt}/${MAX_ATTEMPTS}: waiting ${WAIT_SECONDS}s for log propagation..."
63+
sleep "${WAIT_SECONDS}"
64+
65+
LOGS_OUTPUT=$(aws logs filter-log-events \
66+
--log-group-name "${LOG_GROUP}" \
67+
--region "${REGION}" \
68+
--filter-pattern "\"INTEG_TEST_MARKER\" \"${MARKER}\"" \
69+
--start-time $(($(date +%s) * 1000 - 120000)) \
70+
--output json 2>&1)
71+
72+
if echo "${LOGS_OUTPUT}" | grep -q "INTEG_TEST_MARKER: ${MARKER}"; then
73+
FOUND=true
74+
break
75+
fi
76+
77+
echo " Marker not found yet."
78+
WAIT_SECONDS=$((WAIT_SECONDS * 2))
79+
done
80+
81+
# verify the marker was found
82+
if [ "${FOUND}" = true ]; then
83+
echo ""
84+
echo "=== PASS: Log4j2 integration test succeeded ==="
85+
echo "The marker '${MARKER}' was found in CloudWatch Logs (attempt ${attempt})."
86+
echo "This confirms that the LambdaAppender plugin was discovered by Log4j2"
87+
echo "and logs are being delivered to CloudWatch correctly."
88+
else
89+
echo ""
90+
echo "=== FAIL: Log4j2 integration test failed ==="
91+
echo "The marker '${MARKER}' was NOT found in CloudWatch Logs after ${MAX_ATTEMPTS} attempts."
92+
echo "This indicates that the LambdaAppender was not discovered by Log4j2,"
93+
echo "likely due to a missing Log4j2Plugins.dat in the packaged JAR."
94+
echo ""
95+
echo "Dumping all recent log events for debugging:"
96+
aws logs filter-log-events \
97+
--log-group-name "${LOG_GROUP}" \
98+
--region "${REGION}" \
99+
--start-time $(($(date +%s) * 1000 - 120000)) \
100+
--limit 50 \
101+
--output text 2>&1 || true
102+
exit 1
103+
fi

0 commit comments

Comments
 (0)