Skip to content

Commit 581af89

Browse files
authored
[SVLS-8054] add integration testing (#946)
## Overview Setup integration tests for the lambda extension. These integration tests will run on every PR. ### Details This PR includes: * CDK stacks for deploying lambda integration tests. This is for the lambda, and any related resources, we want to test against. * Integration tests, setup with Jest. These invoke lambda functions, wait, then get Datadog telemetry data to test/verify against. * Gitlab Integration Test Step (info below). * `README.md` for how to run tests locally. Note: * For simplicity, this is setup to just test against the ARM variant (not AMD). This also doesn't include FIPS or AppSec builds. I think this should be a reasonable starting point for our integration tests and we can evaluate adding additional configuration support as needed. ### Gitlab Integration Test Step The integration tests step in Gitlab will: 1. Publish the lambda extension. 2. Deploy CDK stacks, using the newly published lambda extension. 3. Run a test suite. 4. Destroy the CDK stacks. 5. Delete the lambda extension. ### Executing the integration tests The integration tests will automatically run on every PR. Developers can also run the integration tests locally by running `npm run test`. Full information is included in `README.md`. ### Example Integration Tests I added a 2 basic tests, one for node and one for python. These lambda function logs 'Hello World' and are setup with the extension and tracer library. The integration test gets the logs and traces from Datadog. It confirms that we have a log with the message 'Hello World!'. It also confirms we have spans with names `aws.lambda.cold_start`, `aws.lambda.load` and `aws.lambda`. Note that this isn't actually working correct for python for `aws.lambda.load` and `aws.lambda.cold_start`. Those spans are created, but with a different traceId so they aren't getting linked to `aws.lambda`. I will follow up and investigate. I plan on having a follow up PR with other runtimes. ## Testing This PR triggered the integration tests, can see the [corresponding gitlab pipeline](https://gitlab.ddbuild.io/DataDog/datadog-lambda-extension/-/pipelines/84401218) with the newly added step 'integration-tests'. (Or see the 'dd-gitlab/integration-test' in the checks for this PR) The results from the integration test can be obtained by going to [integration step](https://gitlab.ddbuild.io/DataDog/datadog-lambda-extension/-/jobs/1262527100) and downloading the artifacts. Screenshot attached below. <img width="1786" height="1177" alt="Screenshot 2025-12-01 at 9 14 03 AM" src="https://github.com/user-attachments/assets/d1e1313c-b986-44d8-ad65-ab6341d0b909" />
1 parent 34a45d0 commit 581af89

27 files changed

Lines changed: 8158 additions & 1 deletion

.dockerignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
/bottlecap/target/
1+
bottlecap/target/
2+
integration-tests/

.gitlab/Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ RUN apt-get update && apt-get install -y --fix-missing --no-install-recommends \
44
curl gcc gnupg g++ make cmake unzip openssl g++ uuid-runtime libclang-dev \
55
clang llvm-dev
66

7+
# Install Node.js 20 from NodeSource
8+
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
9+
apt-get install -y nodejs
10+
711
# Install AWS CLI
812
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
913
RUN unzip awscliv2.zip && ./aws/install

.gitlab/scripts/get_secrets.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,24 @@ export DD_API_KEY=$(aws ssm get-parameter \
3737
--query "Parameter.Value" \
3838
--out text)
3939

40+
printf "Getting DD API KEY Secret ARN...\n"
41+
42+
export DATADOG_API_SECRET_ARN=$(aws ssm get-parameter \
43+
--region us-east-1 \
44+
--name ci.datadog-lambda-extension.dd-api-key-secret-arn \
45+
--with-decryption \
46+
--query "Parameter.Value" \
47+
--out text)
48+
49+
printf "Getting DD APP KEY...\n"
50+
51+
export DD_APP_KEY=$(aws ssm get-parameter \
52+
--region us-east-1 \
53+
--name ci.datadog-lambda-extension.dd-app-key \
54+
--with-decryption \
55+
--query "Parameter.Value" \
56+
--out text)
57+
4058
printf "Assuming role...\n"
4159

4260
export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s" \

.gitlab/templates/pipeline.yaml.tpl

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ stages:
22
- test
33
- compile
44
- build
5+
- integration-tests
56
- self-monitoring
67
- sign
78
- publish
@@ -322,3 +323,152 @@ signed layer bundle:
322323
- rm -rf datadog_extension-signed-bundle-${CI_JOB_ID}
323324
- mkdir -p datadog_extension-signed-bundle-${CI_JOB_ID}
324325
- cp .layers/datadog_extension-*.zip datadog_extension-signed-bundle-${CI_JOB_ID}
326+
327+
# Integration Tests - Publish arm64 layer with integration test prefix
328+
publish integration layer (arm64):
329+
stage: integration-tests
330+
tags: ["arch:amd64"]
331+
image: ${CI_DOCKER_TARGET_IMAGE}:${CI_DOCKER_TARGET_VERSION}
332+
rules:
333+
- when: on_success
334+
needs:
335+
- layer (arm64)
336+
dependencies:
337+
- layer (arm64)
338+
variables:
339+
LAYER_NAME_BASE_SUFFIX: ""
340+
ARCHITECTURE: arm64
341+
LAYER_FILE: datadog_extension-arm64.zip
342+
REGION: us-east-1
343+
ADD_LAYER_VERSION_PERMISSIONS: "0"
344+
AUTOMATICALLY_BUMP_VERSION: "1"
345+
{{ with $environment := (ds "environments").environments.sandbox }}
346+
before_script:
347+
- EXTERNAL_ID_NAME={{ $environment.external_id }} ROLE_TO_ASSUME={{ $environment.role_to_assume }} AWS_ACCOUNT={{ $environment.account }} source .gitlab/scripts/get_secrets.sh
348+
- export PIPELINE_LAYER_SUFFIX="ARM-${CI_COMMIT_SHORT_SHA}"
349+
- echo "Publishing layer with suffix - ${PIPELINE_LAYER_SUFFIX}"
350+
script:
351+
- .gitlab/scripts/publish_layers.sh
352+
- LAYER_ARN=$(aws lambda list-layer-versions --layer-name "Datadog-Extension-ARM-${CI_COMMIT_SHORT_SHA}" --query 'LayerVersions[0].LayerVersionArn' --output text --region us-east-1)
353+
- echo "Published layer ARN - ${LAYER_ARN}"
354+
{{ end }}
355+
356+
# Integration Tests - Deploy CDK stacks with commit hash prefix
357+
integration-deploy:
358+
stage: integration-tests
359+
tags: ["arch:amd64"]
360+
image: ${CI_DOCKER_TARGET_IMAGE}:${CI_DOCKER_TARGET_VERSION}
361+
rules:
362+
- when: on_success
363+
needs:
364+
- publish integration layer (arm64)
365+
variables:
366+
IDENTIFIER: ${CI_COMMIT_SHORT_SHA}
367+
AWS_DEFAULT_REGION: us-east-1
368+
{{ with $environment := (ds "environments").environments.sandbox }}
369+
before_script:
370+
- EXTERNAL_ID_NAME={{ $environment.external_id }} ROLE_TO_ASSUME={{ $environment.role_to_assume }} AWS_ACCOUNT={{ $environment.account }} source .gitlab/scripts/get_secrets.sh
371+
- curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
372+
- apt-get install -y nodejs
373+
- cd integration-tests
374+
- npm ci
375+
{{ end }}
376+
script:
377+
- echo "Deploying CDK stacks with identifier ${IDENTIFIER}..."
378+
- export EXTENSION_LAYER_ARN=$(aws lambda list-layer-versions --layer-name "Datadog-Extension-ARM-${CI_COMMIT_SHORT_SHA}" --query 'LayerVersions[0].LayerVersionArn' --output text --region us-east-1)
379+
- echo "Using integration test layer - ${EXTENSION_LAYER_ARN}"
380+
- export CDK_DEFAULT_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
381+
- export CDK_DEFAULT_REGION=us-east-1
382+
- npm run build
383+
- npx cdk deploy "integ-$IDENTIFIER-*" --require-approval never
384+
385+
# Integration Tests - Run Jest test suite
386+
integration-test:
387+
stage: integration-tests
388+
tags: ["arch:amd64"]
389+
image: ${CI_DOCKER_TARGET_IMAGE}:${CI_DOCKER_TARGET_VERSION}
390+
rules:
391+
- when: on_success
392+
needs:
393+
- integration-deploy
394+
variables:
395+
IDENTIFIER: ${CI_COMMIT_SHORT_SHA}
396+
DD_SITE: datadoghq.com
397+
{{ with $environment := (ds "environments").environments.sandbox }}
398+
before_script:
399+
- EXTERNAL_ID_NAME={{ $environment.external_id }} ROLE_TO_ASSUME={{ $environment.role_to_assume }} AWS_ACCOUNT={{ $environment.account }} source .gitlab/scripts/get_secrets.sh
400+
- curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
401+
- apt-get install -y nodejs
402+
- cd integration-tests
403+
- npm ci
404+
script:
405+
- echo "Running integration tests with identifier ${IDENTIFIER}..."
406+
- npm run test:ci
407+
{{ end }}
408+
artifacts:
409+
when: always
410+
paths:
411+
- integration-tests/test-results/
412+
reports:
413+
junit: integration-tests/test-results/junit.xml
414+
expire_in: 30 days
415+
416+
# Integration Tests - Cleanup stacks
417+
integration-cleanup-stacks:
418+
stage: integration-tests
419+
tags: ["arch:amd64"]
420+
image: ${CI_DOCKER_TARGET_IMAGE}:${CI_DOCKER_TARGET_VERSION}
421+
when: always
422+
rules:
423+
- when: always
424+
needs:
425+
- integration-test
426+
variables:
427+
IDENTIFIER: ${CI_COMMIT_SHORT_SHA}
428+
{{ with $environment := (ds "environments").environments.sandbox }}
429+
before_script:
430+
- EXTERNAL_ID_NAME={{ $environment.external_id }} ROLE_TO_ASSUME={{ $environment.role_to_assume }} AWS_ACCOUNT={{ $environment.account }} source .gitlab/scripts/get_secrets.sh
431+
- curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
432+
- apt-get install -y nodejs
433+
- cd integration-tests
434+
{{ end }}
435+
script:
436+
- echo "Destroying CDK stacks with identifier ${IDENTIFIER}..."
437+
- npx cdk destroy "integ-$IDENTIFIER-*" --force || echo "Failed to destroy some stacks, but continuing..."
438+
439+
# Integration Tests - Cleanup layer
440+
integration-cleanup-layer:
441+
stage: integration-tests
442+
tags: ["arch:amd64"]
443+
image: ${CI_DOCKER_TARGET_IMAGE}:${CI_DOCKER_TARGET_VERSION}
444+
when: always
445+
rules:
446+
- when: always
447+
needs:
448+
- integration-cleanup-stacks
449+
variables:
450+
IDENTIFIER: ${CI_COMMIT_SHORT_SHA}
451+
{{ with $environment := (ds "environments").environments.sandbox }}
452+
before_script:
453+
- EXTERNAL_ID_NAME={{ $environment.external_id }} ROLE_TO_ASSUME={{ $environment.role_to_assume }} AWS_ACCOUNT={{ $environment.account }} source .gitlab/scripts/get_secrets.sh
454+
{{ end }}
455+
script:
456+
- echo "Deleting integration test layer with identifier ${IDENTIFIER}..."
457+
- |
458+
LAYER_NAME="Datadog-Extension-${IDENTIFIER}"
459+
echo "Looking for layer: ${LAYER_NAME}"
460+
461+
# Get all versions of the layer
462+
VERSIONS=$(aws lambda list-layer-versions --layer-name "${LAYER_NAME}" --query 'LayerVersions[*].Version' --output text --region us-east-1 2>/dev/null || echo "")
463+
464+
if [ -z "$VERSIONS" ]; then
465+
echo "No versions found for layer ${LAYER_NAME}"
466+
else
467+
echo "Found versions: ${VERSIONS}"
468+
for VERSION in $VERSIONS; do
469+
echo "Deleting ${LAYER_NAME} version ${VERSION}..."
470+
aws lambda delete-layer-version --layer-name "${LAYER_NAME}" --version-number "${VERSION}" --region us-east-1 || echo "Failed to delete version ${VERSION}, continuing..."
471+
done
472+
echo "Successfully deleted all versions of ${LAYER_NAME}"
473+
fi
474+

integration-tests/.gitignore

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# CDK
2+
*.js
3+
!jest.config.js
4+
!lambda/**/*.js
5+
*.d.ts
6+
node_modules
7+
cdk.out
8+
.cdk.staging
9+
10+
# Compiled output
11+
dist/
12+
*.tsbuildinfo
13+
14+
# Logs
15+
*.log
16+
npm-debug.log*
17+
18+
# Testing
19+
coverage/
20+
.nyc_output/
21+
test-results/
22+
23+
# Environment
24+
.env
25+
.env.local
26+
27+
# IDE
28+
.vscode/
29+
.idea/
30+
*.swp
31+
*.swo
32+
*~
33+
34+
# OS
35+
.DS_Store
36+
Thumbs.db
37+
38+
# Lambda artifacts
39+
response.json
40+
lambda-bundle.zip

integration-tests/README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Datadog Lambda Extension Integration Tests
2+
3+
This directory contains integration tests for the Datadog Lambda Extension.
4+
5+
The general flow is:
6+
1. Deploy test setup using CDK.
7+
2. Invoke lambda functions.
8+
3. Wait for data to propagate to Datadog.
9+
4. Call Datadog to get telemetry data and check the data based on test requirements.
10+
11+
For simplicity, integraiton tests are setup to only test against ARM runtimes.
12+
13+
## Guidelines
14+
15+
### Naming
16+
* 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.
17+
* Stacks should be named `integ-<identifier>-<stack name>`
18+
* Lambda functions should be named `<stack-id>-<function name>`
19+
20+
### Stacks
21+
* 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`.
22+
23+
24+
## Local Development
25+
26+
### Prerequisites Set env variables
27+
**Datadog API Keys**: Set environment variables
28+
```bash
29+
export DD_API_KEY="your-datadog-api-key"
30+
export DD_APP_KEY="your-datadog-app-key"
31+
export DATADOG_API_SECRET_ARN="arn:aws:secretsmanager:us-east-1:ACCOUNT_ID:secret:YOUR_SECRET"
32+
```
33+
34+
### 1. Build and Deploy Extension Layer
35+
36+
First, publish your extension layer.
37+
38+
```bash
39+
./scripts/local_publish.sh
40+
```
41+
42+
This will create and publish `Datadog-Extension-ARM-<your name>`.
43+
44+
### 2. Deploy Test Stacks
45+
46+
Deploy the CDK stacks that create Lambda functions for testing.
47+
48+
```bash
49+
./scripts/local_deploy.sh <stack name>
50+
```
51+
52+
This will create `integ-<your name>-<stack name>`. The stacks will use the lambda extension created in the previous step.
53+
54+
### 3. Run Integration Tests
55+
56+
Run Jest tests that invoke Lambda functions and verify Datadog telemetry:
57+
58+
```bash
59+
# All tests
60+
npm test
61+
62+
# Single test
63+
npm test -- <my test file>
64+
```
65+
66+
67+
68+
**Note**: Tests wait for a few minutes after Lambda invocation to allow telemetry to appear in Datadog.
69+
70+

integration-tests/bin/app.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env node
2+
import 'source-map-support/register';
3+
import * as cdk from 'aws-cdk-lib';
4+
import { BaseNodeStack } from '../lib/stacks/base-node-stack';
5+
import { BasePythonStack } from '../lib/stacks/base-python-stack';
6+
import { getIdentifier } from '../tests/utils/config';
7+
8+
const app = new cdk.App();
9+
10+
const env = {
11+
account: process.env.CDK_DEFAULT_ACCOUNT || process.env.AWS_ACCOUNT_ID,
12+
region: process.env.CDK_DEFAULT_REGION || process.env.AWS_REGION || 'us-east-1',
13+
};
14+
15+
const identifier = getIdentifier();
16+
17+
new BaseNodeStack(app, `integ-${identifier}-base-node`, {
18+
env,
19+
});
20+
21+
new BasePythonStack(app, `integ-${identifier}-base-python`, {
22+
env,
23+
});
24+
25+
app.synth();

0 commit comments

Comments
 (0)