From 9cf490e65c324b7bd544c89a3e6216a591819d1a Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 20 May 2024 10:32:31 -0700 Subject: [PATCH 1/5] chore(tracer): remove axios from e2e tests and use https directly --- package-lock.json | 1 - packages/tracer/package.json | 1 - ...allFeatures.decorator.test.functionCode.ts | 9 ++-- .../allFeatures.manual.test.functionCode.ts | 12 +++-- .../allFeatures.middy.test.functionCode.ts | 12 +++-- ...syncHandler.decorator.test.functionCode.ts | 9 +++- packages/tracer/tests/helpers/httpRequest.ts | 47 +++++++++++++++++++ 7 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 packages/tracer/tests/helpers/httpRequest.ts diff --git a/package-lock.json b/package-lock.json index 7238f5c760..1f1e103489 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18864,7 +18864,6 @@ "@aws-sdk/client-xray": "^3.574.0", "@types/promise-retry": "^1.1.6", "aws-sdk": "^2.1623.0", - "axios": "^1.6.8", "promise-retry": "^2.0.1" }, "peerDependencies": { diff --git a/packages/tracer/package.json b/packages/tracer/package.json index b7da61dff0..f2c7606392 100644 --- a/packages/tracer/package.json +++ b/packages/tracer/package.json @@ -33,7 +33,6 @@ "@aws-sdk/client-xray": "^3.574.0", "@types/promise-retry": "^1.1.6", "aws-sdk": "^2.1623.0", - "axios": "^1.6.8", "promise-retry": "^2.0.1" }, "peerDependencies": { diff --git a/packages/tracer/tests/e2e/allFeatures.decorator.test.functionCode.ts b/packages/tracer/tests/e2e/allFeatures.decorator.test.functionCode.ts index ca2f6ace93..5d6a635b5f 100644 --- a/packages/tracer/tests/e2e/allFeatures.decorator.test.functionCode.ts +++ b/packages/tracer/tests/e2e/allFeatures.decorator.test.functionCode.ts @@ -1,7 +1,7 @@ import { Tracer } from '../../src/Tracer.js'; import type { Callback, Context } from 'aws-lambda'; import AWS from 'aws-sdk'; -import axios from 'axios'; +import { httpRequest } from '../helpers/httpRequest.js'; const serviceName = process.env.EXPECTED_SERVICE_NAME ?? 'MyFunctionWithStandardHandler'; @@ -52,7 +52,10 @@ export class MyFunctionBase { Item: { id: `${serviceName}-${event.invocation}-sdkv2` }, }) .promise(), - axios.get('https://docs.powertools.aws.dev/lambda/typescript/latest/', { + httpRequest({ + hostname: 'docs.powertools.aws.dev', + path: '/lambda/typescript/latest/', + protocol: 'https', timeout: 5000, }), new Promise((resolve, reject) => { @@ -66,7 +69,7 @@ export class MyFunctionBase { }, 2000); // We need to wait for to make sure previous calls are finished }), ]) - .then(([_dynamoDBRes, _axiosRes, promiseRes]) => promiseRes) + .then(([_dynamoDBRes, _httpRes, promiseRes]) => promiseRes) .catch((err) => { throw err; }); diff --git a/packages/tracer/tests/e2e/allFeatures.manual.test.functionCode.ts b/packages/tracer/tests/e2e/allFeatures.manual.test.functionCode.ts index 95cdc3fd33..0a82c9473e 100644 --- a/packages/tracer/tests/e2e/allFeatures.manual.test.functionCode.ts +++ b/packages/tracer/tests/e2e/allFeatures.manual.test.functionCode.ts @@ -1,8 +1,8 @@ import { Tracer } from '../../src/index.js'; import type { Context } from 'aws-lambda'; -import axios from 'axios'; import AWS from 'aws-sdk'; import type { Subsegment } from 'aws-xray-sdk-core'; +import { httpRequest } from '../helpers/httpRequest.js'; const serviceName = process.env.EXPECTED_SERVICE_NAME ?? 'MyFunctionWithStandardHandler'; @@ -55,10 +55,12 @@ export const handler = async ( Item: { id: `${serviceName}-${event.invocation}-sdkv2` }, }) .promise(); - await axios.get( - 'https://docs.powertools.aws.dev/lambda/typescript/latest/', - { timeout: 5000 } - ); + await httpRequest({ + hostname: 'docs.powertools.aws.dev', + path: '/lambda/typescript/latest/', + protocol: 'https', + timeout: 5000, + }); const res = customResponseValue; if (event.throw) { diff --git a/packages/tracer/tests/e2e/allFeatures.middy.test.functionCode.ts b/packages/tracer/tests/e2e/allFeatures.middy.test.functionCode.ts index f55af0bdd4..77b2d7ad02 100644 --- a/packages/tracer/tests/e2e/allFeatures.middy.test.functionCode.ts +++ b/packages/tracer/tests/e2e/allFeatures.middy.test.functionCode.ts @@ -3,7 +3,7 @@ import { Tracer } from '../../src/index.js'; import { captureLambdaHandler } from '../../src/middleware/middy.js'; import type { Context } from 'aws-lambda'; import { DynamoDBClient, PutItemCommand } from '@aws-sdk/client-dynamodb'; -import axios from 'axios'; +import { httpRequest } from '../helpers/httpRequest.js'; const serviceName = process.env.EXPECTED_SERVICE_NAME ?? 'MyFunctionWithStandardHandler'; @@ -46,10 +46,12 @@ const testHandler = async ( Item: { id: { S: `${serviceName}-${event.invocation}-sdkv3` } }, }) ); - await axios.get( - 'https://docs.powertools.aws.dev/lambda/typescript/latest/', - { timeout: 5000 } - ); + await httpRequest({ + hostname: 'docs.powertools.aws.dev', + path: '/lambda/typescript/latest/', + protocol: 'https', + timeout: 5000, + }); const res = customResponseValue; if (event.throw) { diff --git a/packages/tracer/tests/e2e/asyncHandler.decorator.test.functionCode.ts b/packages/tracer/tests/e2e/asyncHandler.decorator.test.functionCode.ts index 05668a7b9f..420dd48fcb 100644 --- a/packages/tracer/tests/e2e/asyncHandler.decorator.test.functionCode.ts +++ b/packages/tracer/tests/e2e/asyncHandler.decorator.test.functionCode.ts @@ -2,7 +2,7 @@ import { Tracer } from '../../src/index.js'; import type { Context } from 'aws-lambda'; import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; import { DynamoDBDocumentClient, PutCommand } from '@aws-sdk/lib-dynamodb'; -import axios from 'axios'; +import { httpRequest } from '../helpers/httpRequest.js'; const serviceName = process.env.EXPECTED_SERVICE_NAME ?? 'MyFunctionWithStandardHandler'; @@ -58,7 +58,12 @@ export class MyFunctionBase { const url = 'https://docs.powertools.aws.dev/lambda/typescript/latest/'; // Add conditional behavior because fetch is not available in Node.js 16 - this can be removed once we drop support for Node.js 16 if (process.version.startsWith('v16')) { - await axios.get(url, { timeout: 5000 }); + await httpRequest({ + hostname: 'docs.powertools.aws.dev', + path: '/lambda/typescript/latest/', + protocol: 'https', + timeout: 5000, + }); } else { await fetch(url); } diff --git a/packages/tracer/tests/helpers/httpRequest.ts b/packages/tracer/tests/helpers/httpRequest.ts new file mode 100644 index 0000000000..1439327cfe --- /dev/null +++ b/packages/tracer/tests/helpers/httpRequest.ts @@ -0,0 +1,47 @@ +import https, { type RequestOptions } from 'node:https'; + +/** + * Make an HTTP request using the built-in `https` module + * + * This helper function is used in Tracer's tests to make HTTP requests + * and assert that the requests are being traced correctly. + * + * If the requests are traced correctly, then all 3rd party libraries + * built on top of the `https` module should also be traced correctly. + * + * @param params - The request options + */ +const httpRequest = (params: RequestOptions): Promise => + new Promise((resolve, reject) => { + const req = https.request(params, (res) => { + // reject on bad status + if ( + res.statusCode == null || + res.statusCode < 200 || + res.statusCode >= 300 + ) { + return reject(new Error(`statusCode=${res.statusCode || 'unknown'}`)); + } + // cumulate data + let body: Uint8Array[] = []; + res.on('data', (chunk) => { + body.push(chunk); + }); + // resolve on end + res.on('end', () => { + try { + body = JSON.parse(Buffer.concat(body).toString()); + } catch (e) { + reject(e); + } + resolve(body); + }); + }); + req.on('error', (err) => { + reject(err); + }); + + req.end(); + }); + +export { httpRequest }; From a1b4c9ce1caff096f945e49f1f63c34263d5a354 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 20 May 2024 10:48:21 -0700 Subject: [PATCH 2/5] chore: set default protocol & timeout --- .../tests/e2e/allFeatures.decorator.test.functionCode.ts | 2 -- .../tests/e2e/allFeatures.manual.test.functionCode.ts | 2 -- .../tests/e2e/allFeatures.middy.test.functionCode.ts | 2 -- .../tests/e2e/asyncHandler.decorator.test.functionCode.ts | 2 -- packages/tracer/tests/helpers/httpRequest.ts | 7 +++++++ 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/tracer/tests/e2e/allFeatures.decorator.test.functionCode.ts b/packages/tracer/tests/e2e/allFeatures.decorator.test.functionCode.ts index 5d6a635b5f..c6f1734ff7 100644 --- a/packages/tracer/tests/e2e/allFeatures.decorator.test.functionCode.ts +++ b/packages/tracer/tests/e2e/allFeatures.decorator.test.functionCode.ts @@ -55,8 +55,6 @@ export class MyFunctionBase { httpRequest({ hostname: 'docs.powertools.aws.dev', path: '/lambda/typescript/latest/', - protocol: 'https', - timeout: 5000, }), new Promise((resolve, reject) => { setTimeout(() => { diff --git a/packages/tracer/tests/e2e/allFeatures.manual.test.functionCode.ts b/packages/tracer/tests/e2e/allFeatures.manual.test.functionCode.ts index 0a82c9473e..74983fe5f6 100644 --- a/packages/tracer/tests/e2e/allFeatures.manual.test.functionCode.ts +++ b/packages/tracer/tests/e2e/allFeatures.manual.test.functionCode.ts @@ -58,8 +58,6 @@ export const handler = async ( await httpRequest({ hostname: 'docs.powertools.aws.dev', path: '/lambda/typescript/latest/', - protocol: 'https', - timeout: 5000, }); const res = customResponseValue; diff --git a/packages/tracer/tests/e2e/allFeatures.middy.test.functionCode.ts b/packages/tracer/tests/e2e/allFeatures.middy.test.functionCode.ts index 77b2d7ad02..61e5a9198c 100644 --- a/packages/tracer/tests/e2e/allFeatures.middy.test.functionCode.ts +++ b/packages/tracer/tests/e2e/allFeatures.middy.test.functionCode.ts @@ -49,8 +49,6 @@ const testHandler = async ( await httpRequest({ hostname: 'docs.powertools.aws.dev', path: '/lambda/typescript/latest/', - protocol: 'https', - timeout: 5000, }); const res = customResponseValue; diff --git a/packages/tracer/tests/e2e/asyncHandler.decorator.test.functionCode.ts b/packages/tracer/tests/e2e/asyncHandler.decorator.test.functionCode.ts index 420dd48fcb..65d9cbf937 100644 --- a/packages/tracer/tests/e2e/asyncHandler.decorator.test.functionCode.ts +++ b/packages/tracer/tests/e2e/asyncHandler.decorator.test.functionCode.ts @@ -61,8 +61,6 @@ export class MyFunctionBase { await httpRequest({ hostname: 'docs.powertools.aws.dev', path: '/lambda/typescript/latest/', - protocol: 'https', - timeout: 5000, }); } else { await fetch(url); diff --git a/packages/tracer/tests/helpers/httpRequest.ts b/packages/tracer/tests/helpers/httpRequest.ts index 1439327cfe..54c96eb0c8 100644 --- a/packages/tracer/tests/helpers/httpRequest.ts +++ b/packages/tracer/tests/helpers/httpRequest.ts @@ -13,6 +13,13 @@ import https, { type RequestOptions } from 'node:https'; */ const httpRequest = (params: RequestOptions): Promise => new Promise((resolve, reject) => { + if (!params.protocol) { + params.protocol = 'https:'; + } + if (!params.timeout) { + params.timeout = 5000; + } + const req = https.request(params, (res) => { // reject on bad status if ( From 080b7aaf616303cda918076c2ac7ea84bdaf1cca Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 20 May 2024 11:13:42 -0700 Subject: [PATCH 3/5] fix: avoid JSON parsing response --- packages/tracer/tests/helpers/httpRequest.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/tracer/tests/helpers/httpRequest.ts b/packages/tracer/tests/helpers/httpRequest.ts index 54c96eb0c8..3743313339 100644 --- a/packages/tracer/tests/helpers/httpRequest.ts +++ b/packages/tracer/tests/helpers/httpRequest.ts @@ -21,7 +21,6 @@ const httpRequest = (params: RequestOptions): Promise => } const req = https.request(params, (res) => { - // reject on bad status if ( res.statusCode == null || res.statusCode < 200 || @@ -29,19 +28,18 @@ const httpRequest = (params: RequestOptions): Promise => ) { return reject(new Error(`statusCode=${res.statusCode || 'unknown'}`)); } - // cumulate data - let body: Uint8Array[] = []; + const incomingData: Uint8Array[] = []; + let responseBody: string; res.on('data', (chunk) => { - body.push(chunk); + incomingData.push(chunk); }); - // resolve on end res.on('end', () => { try { - body = JSON.parse(Buffer.concat(body).toString()); - } catch (e) { - reject(e); + responseBody = Buffer.concat(incomingData).toString(); + } catch (error) { + reject(error); } - resolve(body); + resolve(responseBody); }); }); req.on('error', (err) => { From 1f03b2b22179f84b738620131d6c38f957112a69 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 20 May 2024 11:54:27 -0700 Subject: [PATCH 4/5] fix: always handle rejection with error --- packages/tracer/tests/helpers/httpRequest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/tracer/tests/helpers/httpRequest.ts b/packages/tracer/tests/helpers/httpRequest.ts index 3743313339..1cc5427e91 100644 --- a/packages/tracer/tests/helpers/httpRequest.ts +++ b/packages/tracer/tests/helpers/httpRequest.ts @@ -42,8 +42,8 @@ const httpRequest = (params: RequestOptions): Promise => resolve(responseBody); }); }); - req.on('error', (err) => { - reject(err); + req.on('error', (error) => { + reject(error instanceof Error ? error : new Error(error)); }); req.end(); From 365da2cf12e37d6fe7caf89c9fcbd03c66dfe093 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 20 May 2024 11:56:08 -0700 Subject: [PATCH 5/5] fix: always handle rejection with error --- packages/tracer/tests/helpers/httpRequest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tracer/tests/helpers/httpRequest.ts b/packages/tracer/tests/helpers/httpRequest.ts index 1cc5427e91..579f56ac3f 100644 --- a/packages/tracer/tests/helpers/httpRequest.ts +++ b/packages/tracer/tests/helpers/httpRequest.ts @@ -37,7 +37,7 @@ const httpRequest = (params: RequestOptions): Promise => try { responseBody = Buffer.concat(incomingData).toString(); } catch (error) { - reject(error); + reject(error instanceof Error ? error : new Error('Unknown error')); } resolve(responseBody); });