Skip to content

Commit 82fc356

Browse files
authored
[SVLS-8146] add LMI integ tests (#972)
https://datadoghq.atlassian.net/browse/SVLS-8146 ## Overview * Adding integration tests for Lambda Managed Instances, starting with logs and traces. * Note that some of the integ tests fail, either for some or all of the runtimes so they are either skipped or marked as failing. I created Jira bug tickets to track these bugs: * https://datadoghq.atlassian.net/browse/SVLS-8232 * https://datadoghq.atlassian.net/browse/SVLS-8231 * Cleaned up the integration test README.md. * No functional changes to the extension code. ## Testing * Newly added integ tests succeed.
1 parent da6f79e commit 82fc356

22 files changed

Lines changed: 1108 additions & 776 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,7 @@ local_tests/serverless-init/logs.txt
2626
bottlecap/target
2727
bottlecap/proptest-regressions
2828

29+
integration-tests/cdk.context.json
30+
2931
.gitlab/pipeline*
3032
/CLAUDE.md

.gitlab/datasources/test-suites.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ test_suites:
22
- name: base
33
- name: otlp
44
- name: snapstart
5+
- name: lmi

integration-tests/README.md

Lines changed: 22 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -13,89 +13,22 @@ The general flow is:
1313
For simplicity, integration tests are set up to only test against ARM runtimes and 4 runtimes (Python, Node, Java, and Dotnet).
1414

1515

16-
## Test Suites
17-
18-
### Base Tests
19-
20-
The base test suite provides basic functionality tests across all supported Lambda runtimes. These tests verify core extension functionality without additional instrumentation.
21-
22-
**What it tests:**
23-
- Extension can collect and forward logs to Datadog
24-
- Extension generates and sends traces with proper span structure
25-
- Extension detects cold starts correctly
26-
27-
**Test Coverage:**
28-
- Lambda invocation succeeds (200 status code)
29-
- "Hello world!" log message is sent to Datadog
30-
- One trace is sent to Datadog
31-
- `aws.lambda` span exists with correct properties including `cold_start: 'true'`
32-
- `aws.lambda.cold_start` span is created
33-
- `aws.lambda.load` span is created for Python and Node
34-
35-
### OTLP Tests
36-
37-
The OTLP test suite verifies OpenTelemetry Protocol (OTLP) integration with the Datadog Lambda Extension. These tests use Lambda functions instrumented with OpenTelemetry SDKs to ensure telemetry data flows correctly through the extension to Datadog.
38-
39-
**What it tests:**
40-
- Lambda functions instrumented with OpenTelemetry SDKs can invoke successfully
41-
- Traces are properly sent to Datadog via OTLP
42-
- Spans contain correct structure and attributes
43-
44-
**Test Coverage:**
45-
- Lambda invocation succeeds (200 status code)
46-
- At least one trace is sent to Datadog
47-
- Trace contains valid spans with proper structure
48-
49-
## CI/CD Pipeline Structure
50-
5116

52-
### Pipeline Flow
53-
54-
```
55-
┌→ deploy-base → test-base → cleanup-base ┐
56-
publish layer → build lambdas ─────┤ ├→ cleanup-layer
57-
└→ deploy-otlp → test-otlp → cleanup-otlp ┘
58-
```
59-
60-
### Test Suite Lifecycle
61-
62-
Each test suite (base, otlp, etc.) follows this lifecycle:
63-
64-
1. **Deploy**: Deploys only the stacks for that suite
65-
- Pattern: `cdk deploy "integ-${IDENTIFIER}-${TEST_SUITE}"`
66-
- Example: `integ-abc123-base` deploys all base test stacks
67-
68-
2. **Test**: Runs only the tests for that suite
69-
- Command: `jest tests/${TEST_SUITE}.test.ts`
70-
- Example: `jest tests/base.test.ts`
71-
72-
3. **Cleanup**: Removes only the stacks for that suite
73-
- Runs with `when: always` to ensure cleanup on failure
74-
- Pattern: Deletes all stacks matching `integ-${IDENTIFIER}-${TEST_SUITE}`
17+
## Test Suites
18+
### Overview
19+
* Gitlab runs test suites in parallel.
20+
* For each test suite, Gitlab will:
21+
* Deploy the associated stack
22+
* Run the test suite
23+
* Destroy the associated stack
24+
* You can download the test suite run from the Gitlab page.
7525

7626
### Adding a New Test Suite
7727

78-
To add a new test suite to the parallel execution:
79-
8028
1. **Create test file**: `tests/<suite-name>.test.ts`
8129
2. **Create CDK stacks**: `lib/stacks/<suite-name>.ts`
8230
3. **Register stacks**: Add to `bin/app.ts`
83-
4. **Update pipeline**: Add suite name to `.gitlab/templates/pipeline.yaml.tpl`:
84-
```yaml
85-
parallel:
86-
matrix:
87-
- TEST_SUITE: [base, otlp, <suite-name>]
88-
```
89-
90-
## Guidelines
91-
92-
### Naming
93-
* An `identifier` is used to differentiate the different stacks. For local development, the identifier is automatically set using the command `whoami` and parses the user's first name. For gitlab pipelines, the identifier is the git commit short sha.
94-
* Stacks should be named `integ-<identifier>-<stack name>`
95-
* Lambda functions should be named `<stack-id>-<function name>`
96-
97-
### Stacks
98-
* Stacks automatically get destroyed at the end of the gitlab integration tests step. Stack should be setup to not retain resources. A helper function `createLogGroup` exists with `removalPolicy: cdk.RemovalPolicy.DESTROY`.
31+
4. **Update pipeline**: Add suite name to `.gitlab/datasources/test-suites.yaml`:
9932

10033

10134
## Local Development
@@ -140,7 +73,6 @@ This creates `integ-<your-name>-<stack-name>` and automatically:
14073
```bash
14174
# Deploy base test stack
14275
./scripts/local_deploy.sh base
143-
14476
```
14577

14678
#### 3. Run Integration Tests
@@ -153,7 +85,19 @@ npm test
15385

15486
# Run specific test file
15587
npm test -- base.test.ts
156-
15788
```
15889

15990
**Note**: Tests wait several minutes after Lambda invocation to allow telemetry to propagate to Datadog.
91+
92+
93+
## Guidelines
94+
95+
### Naming
96+
* An `identifier` is used to differentiate the different stacks. For local development, the identifier is automatically set using the command `whoami` and parses the user's first name. For gitlab pipelines, the identifier is the git commit short sha.
97+
* Stacks should be named `integ-<identifier>-<stack name>`
98+
* Lambda functions should be named `<stack-id>-<function name>`
99+
100+
### Stacks
101+
* Stacks automatically get destroyed at the end of the gitlab integration tests step.
102+
* Stacks should be setup to not retain resources. A helper function `createLogGroup` exists with `removalPolicy: cdk.RemovalPolicy.DESTROY`.
103+
* Stacks should include the tag `extension_integration_test: true`. This gets added in `app.ts`. This lets us easily run scripts to clean up old stacks in case the cleanup step was missed.

integration-tests/bin/app.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,23 @@ import * as cdk from 'aws-cdk-lib';
44
import {Base} from '../lib/stacks/base';
55
import {Otlp} from '../lib/stacks/otlp';
66
import {Snapstart} from '../lib/stacks/snapstart';
7-
import {getIdentifier} from '../tests/utils/config';
7+
import {LambdaManagedInstancesStack} from '../lib/stacks/lmi';
8+
import {ACCOUNT, getIdentifier, REGION} from '../config';
9+
import {CapacityProviderStack} from "../lib/capacity-provider";
810

911
const app = new cdk.App();
1012

1113
const env = {
12-
account: process.env.CDK_DEFAULT_ACCOUNT || process.env.AWS_ACCOUNT_ID,
13-
region: process.env.CDK_DEFAULT_REGION || process.env.AWS_REGION || 'us-east-1',
14+
account: ACCOUNT,
15+
region: REGION,
1416
};
1517

1618
const identifier = getIdentifier();
1719

20+
// Use the same Lambda Managed Instance Capacity Provider for all LMI functions.
21+
// It is slow to create/destroy the related resources.
22+
new CapacityProviderStack(app, `integ-default-capacity-provider`, {env});
23+
1824
const stacks = [
1925
new Base(app, `integ-${identifier}-base`, {
2026
env,
@@ -25,6 +31,9 @@ const stacks = [
2531
new Snapstart(app, `integ-${identifier}-snapstart`, {
2632
env,
2733
}),
34+
new LambdaManagedInstancesStack(app, `integ-${identifier}-lmi`, {
35+
env,
36+
}),
2837
]
2938

3039
// Tag all stacks so we can easily clean them up
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import * as os from 'os';
22

3+
export const ACCOUNT = process.env.CDK_DEFAULT_ACCOUNT || process.env.AWS_ACCOUNT_ID;
4+
export const REGION = process.env.CDK_DEFAULT_REGION || process.env.AWS_REGION || 'us-east-1';
5+
6+
37
export function getIdentifier(): string {
48
if (process.env.IDENTIFIER) {
59
return process.env.IDENTIFIER;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using Amazon.Lambda.Core;
2+
using System.Collections.Generic;
3+
using System.Threading.Tasks;
4+
5+
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
6+
7+
namespace Function
8+
{
9+
public class Handler
10+
{
11+
public async Task<Dictionary<string, object>> FunctionHandler(Dictionary<string, object> input, ILambdaContext context)
12+
{
13+
context.Logger.LogLine("Hello World!");
14+
return new Dictionary<string, object>
15+
{
16+
{ "statusCode", 200 }
17+
};
18+
}
19+
}
20+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>net8.0</TargetFramework>
4+
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
5+
<AWSProjectType>Lambda</AWSProjectType>
6+
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
7+
<PublishReadyToRun>true</PublishReadyToRun>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Amazon.Lambda.Core" Version="2.2.0" />
12+
<PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="2.4.0" />
13+
</ItemGroup>
14+
</Project>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>example</groupId>
8+
<artifactId>managed-instances-java-lambda</artifactId>
9+
<version>1.0.0</version>
10+
<packaging>jar</packaging>
11+
12+
<name>Managed Instances Java Lambda</name>
13+
14+
<properties>
15+
<maven.compiler.source>21</maven.compiler.source>
16+
<maven.compiler.target>21</maven.compiler.target>
17+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
18+
</properties>
19+
20+
<dependencies>
21+
<dependency>
22+
<groupId>com.amazonaws</groupId>
23+
<artifactId>aws-lambda-java-core</artifactId>
24+
<version>1.2.3</version>
25+
</dependency>
26+
</dependencies>
27+
28+
<build>
29+
<plugins>
30+
<plugin>
31+
<groupId>org.apache.maven.plugins</groupId>
32+
<artifactId>maven-shade-plugin</artifactId>
33+
<version>3.5.0</version>
34+
<executions>
35+
<execution>
36+
<phase>package</phase>
37+
<goals>
38+
<goal>shade</goal>
39+
</goals>
40+
<configuration>
41+
<finalName>function</finalName>
42+
<createDependencyReducedPom>false</createDependencyReducedPom>
43+
</configuration>
44+
</execution>
45+
</executions>
46+
</plugin>
47+
</plugins>
48+
</build>
49+
</project>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package example;
2+
3+
import com.amazonaws.services.lambda.runtime.Context;
4+
import com.amazonaws.services.lambda.runtime.RequestHandler;
5+
import java.util.Map;
6+
7+
public class Handler implements RequestHandler<Map<String, Object>, Map<String, Object>> {
8+
@Override
9+
public Map<String, Object> handleRequest(Map<String, Object> event, Context context) {
10+
context.getLogger().log("Hello World!");
11+
return Map.of("statusCode", 200);
12+
}
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
exports.handler = async (event, context) => {
2+
console.log('Hello World!');
3+
return {
4+
statusCode: 200,
5+
body: JSON.stringify({
6+
message: 'Success from Lambda Managed Instance',
7+
requestId: context.requestId
8+
})
9+
};
10+
};

0 commit comments

Comments
 (0)