@digitraffic/common 2026.2.5-2 → 2026.2.5-4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__test__/imports.test.js +2 -6
- package/dist/__test__/infra/api/integration.test.js +1 -1
- package/dist/__test__/infra/api/response.test.js +7 -21
- package/dist/__test__/stack/dt-function.test.js +30 -6
- package/dist/__test__/types/lambda-proxy-types.test.d.ts +8 -0
- package/dist/__test__/types/lambda-proxy-types.test.js +154 -0
- package/dist/__test__/types/lambda-response-builder.test.d.ts +1 -0
- package/dist/__test__/types/lambda-response-builder.test.js +80 -0
- package/dist/__test__/types/lambda-response.test.d.ts +8 -7
- package/dist/__test__/types/lambda-response.test.js +15 -65
- package/dist/__test__/utils/base64.test.js +11 -1
- package/dist/__test__/utils/lambda-proxy-event.test.d.ts +1 -0
- package/dist/__test__/utils/lambda-proxy-event.test.js +44 -0
- package/dist/__test__/utils/logging.test.js +13 -1
- package/dist/aws/infra/api/response.d.ts +1 -1
- package/dist/aws/infra/api/response.js +18 -22
- package/dist/aws/infra/canaries/canary.js +1 -1
- package/dist/aws/infra/canaries/url-checker.js +11 -4
- package/dist/aws/infra/sqs-queue.js +1 -1
- package/dist/aws/infra/stack/dt-function.d.ts +5 -2
- package/dist/aws/infra/stack/dt-function.js +17 -4
- package/dist/aws/infra/stack/lambda-configs.d.ts +6 -0
- package/dist/aws/infra/stack/lambda-configs.js +8 -2
- package/dist/aws/infra/stack/rest-api.js +1 -1
- package/dist/aws/infra/stack/stack-checking-aspect.d.ts +1 -0
- package/dist/aws/infra/stack/stack-checking-aspect.js +7 -3
- package/dist/aws/types/lambda-proxy-types.d.ts +59 -0
- package/dist/aws/types/lambda-proxy-types.js +210 -0
- package/dist/aws/types/lambda-response.d.ts +22 -19
- package/dist/aws/types/lambda-response.js +65 -73
- package/dist/utils/base64.d.ts +5 -3
- package/dist/utils/base64.js +12 -4
- package/dist/utils/lambda-proxy-event.d.ts +9 -0
- package/dist/utils/lambda-proxy-event.js +31 -0
- package/dist/utils/logging.d.ts +12 -0
- package/dist/utils/logging.js +33 -0
- package/dist/utils/zod-utils.d.ts +14 -0
- package/dist/utils/zod-utils.js +29 -0
- package/package.json +1 -1
- package/dist/aws/types/proxytypes.d.ts +0 -26
- package/dist/aws/types/proxytypes.js +0 -2
- package/dist/database/cached.d.ts +0 -19
- package/dist/database/cached.js +0 -40
|
@@ -7,10 +7,6 @@ test("database import ok?", () => {
|
|
|
7
7
|
const database = import("../database/database.js");
|
|
8
8
|
return expect(database).resolves.toBeDefined();
|
|
9
9
|
});
|
|
10
|
-
test("cached import ok?", () => {
|
|
11
|
-
const cached = import("../database/cached.js");
|
|
12
|
-
return expect(cached).resolves.toBeDefined();
|
|
13
|
-
});
|
|
14
10
|
test("models import ok?", () => {
|
|
15
11
|
const models = import("../database/models.js");
|
|
16
12
|
return expect(models).resolves.toBeDefined();
|
|
@@ -243,8 +239,8 @@ test("canaryKeys import ok?", () => {
|
|
|
243
239
|
const canaryKeys = import("../aws/infra/canaries/canary-keys.js");
|
|
244
240
|
return expect(canaryKeys).resolves.toBeDefined();
|
|
245
241
|
});
|
|
246
|
-
test("
|
|
247
|
-
const proxytypes = import("../aws/types/
|
|
242
|
+
test("lambda-proxy-types import ok?", () => {
|
|
243
|
+
const proxytypes = import("../aws/types/lambda-proxy-types.js");
|
|
248
244
|
return expect(proxytypes).resolves.toBeDefined();
|
|
249
245
|
});
|
|
250
246
|
test("tags import ok?", () => {
|
|
@@ -58,7 +58,7 @@ describe("integration tests", () => {
|
|
|
58
58
|
const app = new App();
|
|
59
59
|
const stack = new Stack(app);
|
|
60
60
|
const f = new LambdaFunction(stack, "id", {
|
|
61
|
-
runtime: Runtime.
|
|
61
|
+
runtime: Runtime.NODEJS_24_X,
|
|
62
62
|
code: Code.fromInline("placeholder"),
|
|
63
63
|
handler: "handler",
|
|
64
64
|
});
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import etag from "etag";
|
|
2
2
|
import velocity from "velocityjs";
|
|
3
3
|
import { RESPONSE_DEFAULT_LAMBDA } from "../../../aws/infra/api/response.js";
|
|
4
|
-
import { compressBuffer, decodeBase64ToString, } from "../../../aws/types/lambda-response.js";
|
|
5
|
-
import { TEST_BIG_JSON } from "../../types/lambda-response.test.js";
|
|
6
4
|
const TEST_BODY = "Hello world!";
|
|
7
5
|
describe("response tests", () => {
|
|
8
6
|
function generateEtagValueFromString(body) {
|
|
@@ -11,24 +9,20 @@ describe("response tests", () => {
|
|
|
11
9
|
function generateEtagValueFromBase64String(bodyBase64) {
|
|
12
10
|
return etag(bodyBase64);
|
|
13
11
|
}
|
|
14
|
-
function generateResponse(status, fileName, timestamp
|
|
12
|
+
function generateResponse(status, fileName, timestamp) {
|
|
15
13
|
const compile = new velocity.Compile(velocity.parse(RESPONSE_DEFAULT_LAMBDA));
|
|
16
|
-
const rawBuffer = Buffer.from(body, "utf8");
|
|
17
14
|
const output = compile.render({
|
|
18
15
|
input: {
|
|
19
16
|
path: () => ({
|
|
20
|
-
body: (
|
|
21
|
-
? compressBuffer(rawBuffer)
|
|
22
|
-
: rawBuffer).toString("base64"),
|
|
17
|
+
body: Buffer.from(TEST_BODY).toString("base64"),
|
|
23
18
|
status,
|
|
24
19
|
fileName,
|
|
25
20
|
timestamp: timestamp?.toUTCString(),
|
|
26
|
-
etag: generateEtagValueFromString(
|
|
27
|
-
compressed: compressBody,
|
|
21
|
+
etag: generateEtagValueFromString(TEST_BODY),
|
|
28
22
|
}),
|
|
29
23
|
},
|
|
30
24
|
util: {
|
|
31
|
-
base64Decode: (data) =>
|
|
25
|
+
base64Decode: (data) => Buffer.from(data, "base64").toString(),
|
|
32
26
|
},
|
|
33
27
|
context: {
|
|
34
28
|
responseOverride: {
|
|
@@ -39,7 +33,6 @@ describe("response tests", () => {
|
|
|
39
33
|
ETag: undefined,
|
|
40
34
|
"Last-Modified": undefined,
|
|
41
35
|
"Content-Disposition": undefined,
|
|
42
|
-
"Content-Encoding": undefined,
|
|
43
36
|
},
|
|
44
37
|
},
|
|
45
38
|
},
|
|
@@ -47,8 +40,8 @@ describe("response tests", () => {
|
|
|
47
40
|
// @ts-expect-error: context is not in the type definition
|
|
48
41
|
return [output, compile.context.context];
|
|
49
42
|
}
|
|
50
|
-
function assertOutputAndContext(output, context, status, contentType, fileName, timestamp
|
|
51
|
-
expect(output).toEqual(
|
|
43
|
+
function assertOutputAndContext(output, context, status, contentType, fileName, timestamp) {
|
|
44
|
+
expect(output).toEqual(TEST_BODY);
|
|
52
45
|
expect(context).toMatchObject({
|
|
53
46
|
responseOverride: {
|
|
54
47
|
status,
|
|
@@ -57,8 +50,7 @@ describe("response tests", () => {
|
|
|
57
50
|
"Access-Control-Allow-Origin": "*",
|
|
58
51
|
"Content-Disposition": fileName,
|
|
59
52
|
"Last-Modified": timestamp?.toUTCString(),
|
|
60
|
-
ETag: generateEtagValueFromString(
|
|
61
|
-
"Content-Encoding": compressBody ? "gzip" : undefined,
|
|
53
|
+
ETag: generateEtagValueFromString(TEST_BODY),
|
|
62
54
|
},
|
|
63
55
|
},
|
|
64
56
|
});
|
|
@@ -80,11 +72,5 @@ describe("response tests", () => {
|
|
|
80
72
|
const [output, context] = generateResponse(204);
|
|
81
73
|
assertOutputAndContext(output, context, 204, "text/plain");
|
|
82
74
|
});
|
|
83
|
-
test("test 200 - compressed", () => {
|
|
84
|
-
const now = new Date();
|
|
85
|
-
const body = JSON.stringify(TEST_BIG_JSON);
|
|
86
|
-
const [output, context] = generateResponse(200, "test.json", now, true, body);
|
|
87
|
-
assertOutputAndContext(output, context, undefined, undefined, 'attachment; filename="test.json"', now, body, true);
|
|
88
|
-
});
|
|
89
75
|
});
|
|
90
76
|
//# sourceMappingURL=response.test.js.map
|
|
@@ -8,8 +8,10 @@ import { EnvKeys } from "../../aws/runtime/environment.js";
|
|
|
8
8
|
import { TrafficType } from "../../types/traffictype.js";
|
|
9
9
|
const TEST_ENV_VAR = "TEST_ENV_VAR";
|
|
10
10
|
const TEST_ENV_VALUE = "testValue";
|
|
11
|
+
// AWS::Lambda::Function Template Reference
|
|
12
|
+
// https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-lambda-function.html
|
|
11
13
|
describe("FunctionBuilder test", () => {
|
|
12
|
-
function createTemplate(tester, plain = false) {
|
|
14
|
+
function createTemplate(tester, plain = false, lambdaName = "test") {
|
|
13
15
|
const app = new App();
|
|
14
16
|
const stack = new DigitrafficStack(app, "test-stack", {
|
|
15
17
|
alarmTopicArn: "",
|
|
@@ -24,10 +26,10 @@ describe("FunctionBuilder test", () => {
|
|
|
24
26
|
[TEST_ENV_VAR]: TEST_ENV_VALUE,
|
|
25
27
|
};
|
|
26
28
|
const builder = plain
|
|
27
|
-
? FunctionBuilder.plain(stack,
|
|
29
|
+
? FunctionBuilder.plain(stack, lambdaName)
|
|
28
30
|
.withEnvironment(environment)
|
|
29
31
|
.withCode(Code.fromInline("{}"))
|
|
30
|
-
: FunctionBuilder.create(stack,
|
|
32
|
+
: FunctionBuilder.create(stack, lambdaName)
|
|
31
33
|
.withoutDatabaseAccess()
|
|
32
34
|
.withEnvironment(environment)
|
|
33
35
|
.withCode(Code.fromInline("{}"));
|
|
@@ -62,7 +64,7 @@ describe("FunctionBuilder test", () => {
|
|
|
62
64
|
[TEST_ENV_VAR]: TEST_ENV_VALUE,
|
|
63
65
|
},
|
|
64
66
|
},
|
|
65
|
-
Runtime: Runtime.
|
|
67
|
+
Runtime: Runtime.NODEJS_24_X.name,
|
|
66
68
|
MemorySize: 128,
|
|
67
69
|
Timeout: 60,
|
|
68
70
|
Handler: "test.handler",
|
|
@@ -81,10 +83,18 @@ describe("FunctionBuilder test", () => {
|
|
|
81
83
|
});
|
|
82
84
|
test("Lambda runtime is set", () => {
|
|
83
85
|
const template = createTemplate((builder) => {
|
|
84
|
-
builder.withRuntime(Runtime.
|
|
86
|
+
builder.withRuntime(Runtime.NODEJS_24_X);
|
|
85
87
|
});
|
|
86
88
|
template.hasResourceProperties("AWS::Lambda::Function", {
|
|
87
|
-
Runtime: Runtime.
|
|
89
|
+
Runtime: Runtime.NODEJS_24_X.name,
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
test("Lambda description is set", () => {
|
|
93
|
+
const template = createTemplate((builder) => {
|
|
94
|
+
builder.withDescription("Does something useful");
|
|
95
|
+
});
|
|
96
|
+
template.hasResourceProperties("AWS::Lambda::Function", {
|
|
97
|
+
Description: "Does something useful",
|
|
88
98
|
});
|
|
89
99
|
});
|
|
90
100
|
test("Lambda memory size is set", () => {
|
|
@@ -127,6 +137,20 @@ describe("FunctionBuilder test", () => {
|
|
|
127
137
|
Handler: "custom.main",
|
|
128
138
|
});
|
|
129
139
|
});
|
|
140
|
+
test("Lambda handler module is resolved from path last element", () => {
|
|
141
|
+
const template = createTemplate((_builder) => { }, false, "api/charging-network/v1/operators");
|
|
142
|
+
// const lambdas = template.findResources("AWS::Lambda::Function");
|
|
143
|
+
// console.debug(JSON.stringify(lambdas, null, 2));
|
|
144
|
+
template.hasResourceProperties("AWS::Lambda::Function", {
|
|
145
|
+
Handler: "operators.handler",
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
test("Lambda handler module is same as lambda name", () => {
|
|
149
|
+
const template = createTemplate((_builder) => { }, false, "operators");
|
|
150
|
+
template.hasResourceProperties("AWS::Lambda::Function", {
|
|
151
|
+
Handler: "operators.handler",
|
|
152
|
+
});
|
|
153
|
+
});
|
|
130
154
|
test("withRolePolicies adds custom policy to lambda role", () => {
|
|
131
155
|
const template = createTemplate((builder) => {
|
|
132
156
|
builder.withRolePolicies(new PolicyStatement({
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { LambdaProxyResponseBuilder } from "../../aws/types/lambda-proxy-types.js";
|
|
2
|
+
import { MediaType } from "../../aws/types/mediatypes.js";
|
|
3
|
+
import { decodeBase64ToUtf8 } from "../../utils/base64.js";
|
|
4
|
+
// About 18 MB will be compressed to 2 MB
|
|
5
|
+
export const TEST_BIG_JSON = {
|
|
6
|
+
items: Array.from({ length: 10 }, (_, i) => ({
|
|
7
|
+
id: i,
|
|
8
|
+
name: `Item ${i}`,
|
|
9
|
+
description: "This is a test description that repeats to allow compression",
|
|
10
|
+
value: Math.random(),
|
|
11
|
+
})),
|
|
12
|
+
};
|
|
13
|
+
describe("lambda-response", () => {
|
|
14
|
+
const TEST_MESSAGE = "HELLO";
|
|
15
|
+
const TEST_COUNT = 12;
|
|
16
|
+
const TEST_FILENAME = "file.txt";
|
|
17
|
+
const TEST_TIMESTAMP = new Date();
|
|
18
|
+
const TEST_TIMESTAMP_STR = TEST_TIMESTAMP.toISOString();
|
|
19
|
+
const TEST_JSON = {
|
|
20
|
+
message: TEST_MESSAGE,
|
|
21
|
+
count: TEST_COUNT,
|
|
22
|
+
};
|
|
23
|
+
function isCompressed(response) {
|
|
24
|
+
return response.headers?.["Content-Encoding"] === "gzip";
|
|
25
|
+
}
|
|
26
|
+
function assertContent(response, expectedBody, expectedStatus, expectedFilename, expectedTimestamp, expectContentType = MediaType.APPLICATION_JSON, compressed = false, isBase64Encoded = false) {
|
|
27
|
+
const isBinary = typeof expectedBody !== "string";
|
|
28
|
+
const decodedBody = response.isBase64Encoded
|
|
29
|
+
? decodeBase64ToUtf8(response.body, isCompressed(response))
|
|
30
|
+
: response.body;
|
|
31
|
+
const body = isBinary ? JSON.parse(decodedBody) : decodedBody;
|
|
32
|
+
expect(body).toEqual(expectedBody);
|
|
33
|
+
// compressed responses are always base64 encoded
|
|
34
|
+
expect(response.isBase64Encoded).toEqual(compressed || isBase64Encoded);
|
|
35
|
+
expect(response.statusCode).toEqual(expectedStatus);
|
|
36
|
+
if (expectedFilename) {
|
|
37
|
+
expect(response.headers?.["Content-Disposition"]).toEqual(`attachment; filename="${expectedFilename}"`);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
expect(response.headers?.["Content-Disposition"]).toBeUndefined();
|
|
41
|
+
}
|
|
42
|
+
if (expectedTimestamp) {
|
|
43
|
+
expect(response.headers?.["Last-Modified"]).toEqual(expectedTimestamp?.toUTCString());
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
expect(response.headers?.["Last-Modified"]).toBeUndefined();
|
|
47
|
+
}
|
|
48
|
+
if (compressed) {
|
|
49
|
+
expect(response.headers?.["Content-Encoding"]).toEqual("gzip");
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// No content-encoding header for uncompressed content
|
|
53
|
+
expect(response.headers?.["Content-Encoding"]).toBeUndefined();
|
|
54
|
+
}
|
|
55
|
+
expect(response.headers?.["Content-Type"]).toEqual(expectContentType);
|
|
56
|
+
}
|
|
57
|
+
test("okJson - create json", () => {
|
|
58
|
+
const response = LambdaProxyResponseBuilder.create(TEST_JSON).build();
|
|
59
|
+
assertContent(response, TEST_JSON, 200);
|
|
60
|
+
});
|
|
61
|
+
test("okJson - with json", () => {
|
|
62
|
+
const response = LambdaProxyResponseBuilder.create()
|
|
63
|
+
.withBody(TEST_JSON)
|
|
64
|
+
.build();
|
|
65
|
+
assertContent(response, TEST_JSON, 200);
|
|
66
|
+
});
|
|
67
|
+
test("okJson - with json and fileName", () => {
|
|
68
|
+
const response = LambdaProxyResponseBuilder.create()
|
|
69
|
+
.withBody(TEST_JSON)
|
|
70
|
+
.withFileName(TEST_FILENAME)
|
|
71
|
+
.build();
|
|
72
|
+
assertContent(response, TEST_JSON, 200, TEST_FILENAME);
|
|
73
|
+
});
|
|
74
|
+
test("okJson - with json, fileName and timestamp", () => {
|
|
75
|
+
const response = LambdaProxyResponseBuilder.create()
|
|
76
|
+
.withBody(TEST_JSON)
|
|
77
|
+
.withFileName(TEST_FILENAME)
|
|
78
|
+
.withTimestamp(TEST_TIMESTAMP)
|
|
79
|
+
.build();
|
|
80
|
+
const response2 = LambdaProxyResponseBuilder.create()
|
|
81
|
+
.withBody(TEST_JSON)
|
|
82
|
+
.withFileName(TEST_FILENAME)
|
|
83
|
+
.withTimestamp(TEST_TIMESTAMP_STR)
|
|
84
|
+
.build();
|
|
85
|
+
assertContent(response, TEST_JSON, 200, TEST_FILENAME, TEST_TIMESTAMP);
|
|
86
|
+
assertContent(response2, TEST_JSON, 200, TEST_FILENAME, TEST_TIMESTAMP);
|
|
87
|
+
});
|
|
88
|
+
test("okBinary - create binary, fileName and timestamp", () => {
|
|
89
|
+
const response = LambdaProxyResponseBuilder.create(Buffer.from(TEST_MESSAGE).toString("base64"), true)
|
|
90
|
+
.withFileName(TEST_FILENAME)
|
|
91
|
+
.withTimestamp(TEST_TIMESTAMP)
|
|
92
|
+
.withContentType(MediaType.TEXT_PLAIN)
|
|
93
|
+
.build();
|
|
94
|
+
assertContent(response, TEST_MESSAGE, 200, TEST_FILENAME, TEST_TIMESTAMP, MediaType.TEXT_PLAIN, false, true);
|
|
95
|
+
});
|
|
96
|
+
test("badRequest", () => {
|
|
97
|
+
const response = LambdaProxyResponseBuilder.badRequest(TEST_MESSAGE);
|
|
98
|
+
assertContent(response, TEST_MESSAGE, 400, undefined, undefined, MediaType.TEXT_PLAIN);
|
|
99
|
+
});
|
|
100
|
+
test("notFound", () => {
|
|
101
|
+
const response = LambdaProxyResponseBuilder.notFound();
|
|
102
|
+
assertContent(response, "Not Found", 404, undefined, undefined, MediaType.TEXT_PLAIN);
|
|
103
|
+
});
|
|
104
|
+
test("internalError", () => {
|
|
105
|
+
const response = LambdaProxyResponseBuilder.internalError();
|
|
106
|
+
assertContent(response, "Internal Error", 500, undefined, undefined, MediaType.TEXT_PLAIN);
|
|
107
|
+
});
|
|
108
|
+
test("notImplemented", () => {
|
|
109
|
+
const response = LambdaProxyResponseBuilder.notImplemented();
|
|
110
|
+
assertContent(response, "Not Implemented", 501, undefined, undefined, MediaType.TEXT_PLAIN);
|
|
111
|
+
});
|
|
112
|
+
test("notImplemented", () => {
|
|
113
|
+
const response = LambdaProxyResponseBuilder.unauthorized();
|
|
114
|
+
assertContent(response, "Unauthorized", 401, undefined, undefined, MediaType.TEXT_PLAIN);
|
|
115
|
+
});
|
|
116
|
+
test("okText - with fileName and timestamp", () => {
|
|
117
|
+
const response = LambdaProxyResponseBuilder.create()
|
|
118
|
+
.withBody(TEST_MESSAGE)
|
|
119
|
+
.withFileName(TEST_FILENAME)
|
|
120
|
+
.withTimestamp(TEST_TIMESTAMP)
|
|
121
|
+
.build();
|
|
122
|
+
assertContent(response, TEST_MESSAGE, 200, TEST_FILENAME, TEST_TIMESTAMP);
|
|
123
|
+
});
|
|
124
|
+
test("okJson - compression uneffective for small json", () => {
|
|
125
|
+
const response = LambdaProxyResponseBuilder.create()
|
|
126
|
+
.withBody(TEST_JSON)
|
|
127
|
+
.withFileName(TEST_FILENAME)
|
|
128
|
+
.withTimestamp(TEST_TIMESTAMP)
|
|
129
|
+
.withCompression()
|
|
130
|
+
.withDebug()
|
|
131
|
+
.build();
|
|
132
|
+
assertContent(response, TEST_JSON, 200, TEST_FILENAME, TEST_TIMESTAMP, MediaType.APPLICATION_JSON, false);
|
|
133
|
+
});
|
|
134
|
+
test("okJson - compression effective for large json", () => {
|
|
135
|
+
const response = LambdaProxyResponseBuilder.create()
|
|
136
|
+
.withBody(TEST_BIG_JSON)
|
|
137
|
+
.withFileName(TEST_FILENAME)
|
|
138
|
+
.withTimestamp(TEST_TIMESTAMP)
|
|
139
|
+
.withCompression()
|
|
140
|
+
.withDebug()
|
|
141
|
+
.build();
|
|
142
|
+
assertContent(response, TEST_BIG_JSON, 200, TEST_FILENAME, TEST_TIMESTAMP, MediaType.APPLICATION_JSON, true);
|
|
143
|
+
});
|
|
144
|
+
test("okText - as binary", () => {
|
|
145
|
+
const response = LambdaProxyResponseBuilder.create()
|
|
146
|
+
.withBody(Buffer.from(TEST_MESSAGE).toString("base64"), true)
|
|
147
|
+
.withFileName(TEST_FILENAME)
|
|
148
|
+
.withTimestamp(TEST_TIMESTAMP)
|
|
149
|
+
.withContentType(MediaType.TEXT_PLAIN)
|
|
150
|
+
.build();
|
|
151
|
+
assertContent(response, TEST_MESSAGE, 200, TEST_FILENAME, TEST_TIMESTAMP, MediaType.TEXT_PLAIN, false, true);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
//# sourceMappingURL=lambda-proxy-types.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { LambdaResponseBuilder } from "../../aws/types/lambda-response.js";
|
|
2
|
+
import { decodeBase64ToUtf8 } from "../../utils/base64.js";
|
|
3
|
+
import { TEST_FILENAME, TEST_JSON, TEST_MESSAGE, TEST_TIMESTAMP, TEST_TIMESTAMP_STR, } from "./lambda-response.test.js";
|
|
4
|
+
describe("lambda-response", () => {
|
|
5
|
+
function assertJson(response, expectedJson, expectedStatus, expectedFilename, expectedTimestamp) {
|
|
6
|
+
const body = JSON.parse(decodeBase64ToUtf8(response.body));
|
|
7
|
+
expect(body).toEqual(expectedJson);
|
|
8
|
+
expect(response.status).toEqual(expectedStatus);
|
|
9
|
+
expect(response.fileName).toEqual(expectedFilename);
|
|
10
|
+
expect(response.timestamp).toEqual(expectedTimestamp?.toUTCString());
|
|
11
|
+
}
|
|
12
|
+
function assertBinary(response, expectedString, expectedStatus, expectedFilename, expectedTimestamp) {
|
|
13
|
+
const body = decodeBase64ToUtf8(response.body);
|
|
14
|
+
expect(body).toEqual(expectedString);
|
|
15
|
+
expect(response.status).toEqual(expectedStatus);
|
|
16
|
+
expect(response.fileName).toEqual(expectedFilename);
|
|
17
|
+
expect(response.timestamp).toEqual(expectedTimestamp?.toUTCString());
|
|
18
|
+
}
|
|
19
|
+
test("okJson - without fileName", () => {
|
|
20
|
+
const response = LambdaResponseBuilder.create(TEST_JSON).build();
|
|
21
|
+
assertJson(response, TEST_JSON, 200);
|
|
22
|
+
});
|
|
23
|
+
test("okJson - with fileName", () => {
|
|
24
|
+
const response = LambdaResponseBuilder.create(TEST_JSON)
|
|
25
|
+
.withFileName(TEST_FILENAME)
|
|
26
|
+
.build();
|
|
27
|
+
assertJson(response, TEST_JSON, 200, TEST_FILENAME);
|
|
28
|
+
});
|
|
29
|
+
test("okJson - with fileName and timestamp", () => {
|
|
30
|
+
const responseWithTimestampDate = LambdaResponseBuilder.create()
|
|
31
|
+
.withBody(TEST_JSON)
|
|
32
|
+
.withFileName(TEST_FILENAME)
|
|
33
|
+
.withTimestamp(TEST_TIMESTAMP)
|
|
34
|
+
.build();
|
|
35
|
+
const responseWithTimestampString = LambdaResponseBuilder.create()
|
|
36
|
+
.withBody(TEST_JSON)
|
|
37
|
+
.withFileName(TEST_FILENAME)
|
|
38
|
+
.withTimestamp(TEST_TIMESTAMP_STR)
|
|
39
|
+
.build();
|
|
40
|
+
assertJson(responseWithTimestampDate, TEST_JSON, 200, TEST_FILENAME, TEST_TIMESTAMP);
|
|
41
|
+
assertJson(responseWithTimestampString, TEST_JSON, 200, TEST_FILENAME, TEST_TIMESTAMP);
|
|
42
|
+
});
|
|
43
|
+
test("okBinary - with fileName and timestamp", () => {
|
|
44
|
+
const response = LambdaResponseBuilder.create()
|
|
45
|
+
.withBody(TEST_MESSAGE)
|
|
46
|
+
.withFileName(TEST_FILENAME)
|
|
47
|
+
.withTimestamp(TEST_TIMESTAMP)
|
|
48
|
+
.build();
|
|
49
|
+
assertBinary(response, TEST_MESSAGE, 200, TEST_FILENAME, TEST_TIMESTAMP);
|
|
50
|
+
});
|
|
51
|
+
test("badRequest", () => {
|
|
52
|
+
const response = LambdaResponseBuilder.badRequest(TEST_MESSAGE);
|
|
53
|
+
assertBinary(response, TEST_MESSAGE, 400);
|
|
54
|
+
});
|
|
55
|
+
test("notFound", () => {
|
|
56
|
+
const response = LambdaResponseBuilder.notFound();
|
|
57
|
+
assertBinary(response, "Not Found", 404);
|
|
58
|
+
});
|
|
59
|
+
test("internalError", () => {
|
|
60
|
+
const response = LambdaResponseBuilder.internalError();
|
|
61
|
+
assertBinary(response, "Internal Error", 500);
|
|
62
|
+
});
|
|
63
|
+
test("notImplemented", () => {
|
|
64
|
+
const response = LambdaResponseBuilder.notImplemented();
|
|
65
|
+
assertBinary(response, "Not Implemented", 501);
|
|
66
|
+
});
|
|
67
|
+
// Builder
|
|
68
|
+
test("Builder - okJson - without fileName", () => {
|
|
69
|
+
const response = LambdaResponseBuilder.create().withBody(TEST_JSON).build();
|
|
70
|
+
assertJson(response, TEST_JSON, 200);
|
|
71
|
+
});
|
|
72
|
+
test("Builder - okJson - with fileName", () => {
|
|
73
|
+
const response = LambdaResponseBuilder.create()
|
|
74
|
+
.withBody(TEST_JSON)
|
|
75
|
+
.withFileName(TEST_FILENAME)
|
|
76
|
+
.build();
|
|
77
|
+
assertJson(response, TEST_JSON, 200, TEST_FILENAME);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
//# sourceMappingURL=lambda-response-builder.test.js.map
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
export declare const TEST_MESSAGE = "HELLO";
|
|
2
|
+
export declare const TEST_COUNT = 12;
|
|
3
|
+
export declare const TEST_FILENAME = "file.txt";
|
|
4
|
+
export declare const TEST_TIMESTAMP: Date;
|
|
5
|
+
export declare const TEST_TIMESTAMP_STR: string;
|
|
6
|
+
export declare const TEST_JSON: {
|
|
7
|
+
message: string;
|
|
8
|
+
count: number;
|
|
8
9
|
};
|
|
@@ -1,32 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { LambdaResponse, LambdaResponseBuilder, } from "../../aws/types/lambda-response.js";
|
|
2
|
+
import { decodeBase64ToUtf8 } from "../../utils/base64.js";
|
|
3
|
+
export const TEST_MESSAGE = "HELLO";
|
|
4
|
+
export const TEST_COUNT = 12;
|
|
5
|
+
export const TEST_FILENAME = "file.txt";
|
|
6
|
+
export const TEST_TIMESTAMP = new Date();
|
|
7
|
+
export const TEST_TIMESTAMP_STR = TEST_TIMESTAMP.toISOString();
|
|
8
|
+
export const TEST_JSON = {
|
|
9
|
+
message: TEST_MESSAGE,
|
|
10
|
+
count: TEST_COUNT,
|
|
10
11
|
};
|
|
11
12
|
describe("lambda-response", () => {
|
|
12
|
-
const TEST_MESSAGE = "HELLO";
|
|
13
|
-
const TEST_COUNT = 12;
|
|
14
|
-
const TEST_FILENAME = "file.txt";
|
|
15
|
-
const TEST_TIMESTAMP = new Date();
|
|
16
|
-
const TEST_TIMESTAMP_STR = TEST_TIMESTAMP.toISOString();
|
|
17
|
-
const TEST_JSON = {
|
|
18
|
-
message: TEST_MESSAGE,
|
|
19
|
-
count: TEST_COUNT,
|
|
20
|
-
};
|
|
21
13
|
function assertJson(response, expectedJson, expectedStatus, expectedFilename, expectedTimestamp) {
|
|
22
|
-
const body = JSON.parse(
|
|
14
|
+
const body = JSON.parse(decodeBase64ToUtf8(response.body));
|
|
23
15
|
expect(body).toEqual(expectedJson);
|
|
24
16
|
expect(response.status).toEqual(expectedStatus);
|
|
25
17
|
expect(response.fileName).toEqual(expectedFilename);
|
|
26
18
|
expect(response.timestamp).toEqual(expectedTimestamp?.toUTCString());
|
|
27
19
|
}
|
|
28
20
|
function assertBinary(response, expectedString, expectedStatus, expectedFilename, expectedTimestamp) {
|
|
29
|
-
const body =
|
|
21
|
+
const body = decodeBase64ToUtf8(response.body);
|
|
30
22
|
expect(body).toEqual(expectedString);
|
|
31
23
|
expect(response.status).toEqual(expectedStatus);
|
|
32
24
|
expect(response.fileName).toEqual(expectedFilename);
|
|
@@ -54,15 +46,15 @@ describe("lambda-response", () => {
|
|
|
54
46
|
});
|
|
55
47
|
test("notFound", () => {
|
|
56
48
|
const response = LambdaResponse.notFound();
|
|
57
|
-
assertBinary(response, "Not
|
|
49
|
+
assertBinary(response, "Not Found", 404);
|
|
58
50
|
});
|
|
59
51
|
test("internalError", () => {
|
|
60
52
|
const response = LambdaResponse.internalError();
|
|
61
|
-
assertBinary(response, "Internal
|
|
53
|
+
assertBinary(response, "Internal Error", 500);
|
|
62
54
|
});
|
|
63
55
|
test("notImplemented", () => {
|
|
64
56
|
const response = LambdaResponse.notImplemented();
|
|
65
|
-
assertBinary(response, "Not
|
|
57
|
+
assertBinary(response, "Not Implemented", 501);
|
|
66
58
|
});
|
|
67
59
|
// Builder
|
|
68
60
|
test("Builder - okJson - without fileName", () => {
|
|
@@ -76,47 +68,5 @@ describe("lambda-response", () => {
|
|
|
76
68
|
.build();
|
|
77
69
|
assertJson(response, TEST_JSON, 200, TEST_FILENAME);
|
|
78
70
|
});
|
|
79
|
-
test("Builder - okJson - with fileName and timestamp", () => {
|
|
80
|
-
const response = LambdaResponseBuilder.create()
|
|
81
|
-
.withBody(TEST_JSON)
|
|
82
|
-
.withFileName(TEST_FILENAME)
|
|
83
|
-
.withTimestamp(TEST_TIMESTAMP)
|
|
84
|
-
.build();
|
|
85
|
-
const response2 = LambdaResponseBuilder.create()
|
|
86
|
-
.withBody(TEST_JSON)
|
|
87
|
-
.withFileName(TEST_FILENAME)
|
|
88
|
-
.withTimestamp(TEST_TIMESTAMP_STR)
|
|
89
|
-
.build();
|
|
90
|
-
assertJson(response, TEST_JSON, 200, TEST_FILENAME, TEST_TIMESTAMP);
|
|
91
|
-
assertJson(response2, TEST_JSON, 200, TEST_FILENAME, TEST_TIMESTAMP);
|
|
92
|
-
});
|
|
93
|
-
test("Builder - okBinary - with fileName and timestamp", () => {
|
|
94
|
-
const response = LambdaResponseBuilder.create()
|
|
95
|
-
.withBody(TEST_MESSAGE)
|
|
96
|
-
.withFileName(TEST_FILENAME)
|
|
97
|
-
.withTimestamp(TEST_TIMESTAMP)
|
|
98
|
-
.build();
|
|
99
|
-
assertBinary(response, TEST_MESSAGE, 200, TEST_FILENAME, TEST_TIMESTAMP);
|
|
100
|
-
});
|
|
101
|
-
test("Builder - compression uneffective for small json", () => {
|
|
102
|
-
const response = LambdaResponseBuilder.create()
|
|
103
|
-
.withBody(TEST_JSON)
|
|
104
|
-
.withFileName(TEST_FILENAME)
|
|
105
|
-
.withCompression()
|
|
106
|
-
.withDebug()
|
|
107
|
-
.build();
|
|
108
|
-
expect(response.compressed).toBe(false);
|
|
109
|
-
assertJson(response, TEST_JSON, 200, TEST_FILENAME);
|
|
110
|
-
});
|
|
111
|
-
test("Builder - compression effective for large json", () => {
|
|
112
|
-
const response = LambdaResponseBuilder.create()
|
|
113
|
-
.withBody(TEST_BIG_JSON)
|
|
114
|
-
.withFileName(TEST_FILENAME)
|
|
115
|
-
.withCompression()
|
|
116
|
-
.withDebug()
|
|
117
|
-
.build();
|
|
118
|
-
expect(response.compressed).toBe(true);
|
|
119
|
-
assertJson(response, TEST_BIG_JSON, 200, TEST_FILENAME);
|
|
120
|
-
});
|
|
121
71
|
});
|
|
122
72
|
//# sourceMappingURL=lambda-response.test.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { decodeBase64ToAscii, decodeBase64ToUtf8, encodeAsciiToBase64, encodeUtf8ToBase64, } from "../../utils/base64.js";
|
|
1
|
+
import { compressBuffer, decodeBase64ToAscii, decodeBase64ToUtf8, encodeAsciiToBase64, encodeUtf8ToBase64, } from "../../utils/base64.js";
|
|
2
2
|
describe("Base64UtilTest", () => {
|
|
3
3
|
const EXPECTED_ASCII = "0a9f4967-faaa-445a-ba11-078f7f9556b4";
|
|
4
4
|
const EXPECTED_ASCII_BASE64 = "MGE5ZjQ5NjctZmFhYS00NDVhLWJhMTEtMDc4ZjdmOTU1NmI0";
|
|
@@ -23,5 +23,15 @@ describe("Base64UtilTest", () => {
|
|
|
23
23
|
expect(encodedUtf8).toEqual(EXPECTED_UTF8_BASE64);
|
|
24
24
|
expect(decodedUtf8).toEqual(EXPECTED_UTF8);
|
|
25
25
|
});
|
|
26
|
+
test("decode utf8 compressed", () => {
|
|
27
|
+
const originalBody = { message: EXPECTED_UTF8 };
|
|
28
|
+
const body = JSON.stringify(originalBody);
|
|
29
|
+
const rawBuffer = Buffer.from(body, "utf8");
|
|
30
|
+
const compressed = compressBuffer(rawBuffer);
|
|
31
|
+
const compressedBase64 = compressed.toString("base64");
|
|
32
|
+
const uncompressedBody = decodeBase64ToUtf8(compressedBase64, true);
|
|
33
|
+
const restoredBody = JSON.parse(uncompressedBody);
|
|
34
|
+
expect(originalBody).toEqual(restoredBody);
|
|
35
|
+
});
|
|
26
36
|
});
|
|
27
37
|
//# sourceMappingURL=base64.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { parseQueryParams } from "../../utils/lambda-proxy-event.js";
|
|
2
|
+
describe("lambda-proxy-event.test", () => {
|
|
3
|
+
test("StopWatch start-stop", async () => {
|
|
4
|
+
const event = {
|
|
5
|
+
body: null,
|
|
6
|
+
headers: {},
|
|
7
|
+
multiValueHeaders: {},
|
|
8
|
+
httpMethod: "GET",
|
|
9
|
+
isBase64Encoded: false,
|
|
10
|
+
multiValueQueryStringParameters: {
|
|
11
|
+
evseStatus: ["CHARGING", "OUTOFORDER"],
|
|
12
|
+
operatorPartyId: ["LDL"],
|
|
13
|
+
},
|
|
14
|
+
queryStringParameters: {
|
|
15
|
+
evseStatus: "OUTOFORDER",
|
|
16
|
+
operatorPartyId: "LDL",
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
const parsed = parseQueryParams(event, ["evseStatus"]);
|
|
20
|
+
expect(parsed.evseStatus).toEqual(["CHARGING", "OUTOFORDER"]);
|
|
21
|
+
expect(parsed.operatorPartyId).toEqual("LDL");
|
|
22
|
+
});
|
|
23
|
+
test("StopWatch start-stop", async () => {
|
|
24
|
+
const event = {
|
|
25
|
+
body: null,
|
|
26
|
+
headers: {},
|
|
27
|
+
multiValueHeaders: {},
|
|
28
|
+
httpMethod: "GET",
|
|
29
|
+
isBase64Encoded: false,
|
|
30
|
+
multiValueQueryStringParameters: {
|
|
31
|
+
evseStatus: ["CHARGING", "OUTOFORDER"],
|
|
32
|
+
operatorPartyId: ["LDL"],
|
|
33
|
+
},
|
|
34
|
+
queryStringParameters: {
|
|
35
|
+
evseStatus: "OUTOFORDER",
|
|
36
|
+
operatorPartyId: "LDL",
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
const parsed = parseQueryParams(event, ["evseStatus"]);
|
|
40
|
+
expect(parsed.evseStatus).toEqual(["CHARGING", "OUTOFORDER"]);
|
|
41
|
+
expect(parsed.operatorPartyId).toEqual("LDL");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=lambda-proxy-event.test.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Writable } from "node:stream";
|
|
2
2
|
import { DtLogger } from "../../aws/runtime/dt-logger.js";
|
|
3
|
-
import { logException } from "../../utils/logging.js";
|
|
3
|
+
import { logException, truncateEnd, truncateMiddle, } from "../../utils/logging.js";
|
|
4
4
|
const TEST_METHODNAME = "test.logException";
|
|
5
5
|
describe("logging-test", () => {
|
|
6
6
|
function assertLogError(error, expected, includeStack = false) {
|
|
@@ -58,5 +58,17 @@ describe("logging-test", () => {
|
|
|
58
58
|
stack: true,
|
|
59
59
|
}, true);
|
|
60
60
|
});
|
|
61
|
+
test("truncateEnd - not truncated as would be longer", () => {
|
|
62
|
+
expect(truncateEnd("This is a test string", 10)).toBe("This is a test string");
|
|
63
|
+
});
|
|
64
|
+
test("truncateEnd", () => {
|
|
65
|
+
expect(truncateEnd("This is a test string that is long enough", 10)).toBe("This is a [TRUNCATED 31 CHARS]");
|
|
66
|
+
});
|
|
67
|
+
test("truncateMiddle - not truncated as would be longer", () => {
|
|
68
|
+
expect(truncateMiddle("This is a test string", 10)).toBe("This is a test string");
|
|
69
|
+
});
|
|
70
|
+
test("truncateMiddle", () => {
|
|
71
|
+
expect(truncateMiddle("This is a test string that is long enough", 20)).toBe("This is a [TRUNCATED 21 CHARS] ong enough");
|
|
72
|
+
});
|
|
61
73
|
});
|
|
62
74
|
//# sourceMappingURL=logging.test.js.map
|