Skip to content

Commit 34ef180

Browse files
dreamorosiijemmy
andauthored
tests(idempotency): add utility to workspace unit tests and CI (#1160)
* chore: fix package.lock & package * ci: add idempotency to ci checks on PRs * refactor: minor styling changes to folder structure, exports, types * test: unit tests style + added missing * chore: temporarily excluded makeFunctionIdempotent from coverage report * refactor: rename npx DynamoDbPersistenceLayer to DynamoDBPersistenceLayer * refactor: rename npx DynamoDbPersistenceLayer to DynamoDBPersistenceLayer * refactor: rename npx DynamoDbPersistenceLayer to DynamoDBPersistenceLayer * chore: revert changes to PersistenceLayerInterface * Trigger Build * Update packages/idempotency/src/persistence/PersistenceLayer.ts Co-authored-by: ijemmy <[email protected]> Co-authored-by: ijemmy <[email protected]>
1 parent cb91374 commit 34ef180

25 files changed

+1290
-444
lines changed

Diff for: .github/workflows/reusable-run-linting-check-and-unit-tests.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ jobs:
4242
if: steps.cache-node-modules.outputs.cache-hit == 'true'
4343
run: |
4444
npm run build -w packages/commons
45-
npm run build -w packages/logger & npm run build -w packages/tracer & npm run build -w packages/metrics -w packages/parameters
45+
npm run build -w packages/logger & npm run build -w packages/tracer & npm run build -w packages/metrics & npm run build -w packages/parameters & npm run build -w packages/idempotency
4646
- name: Run linting
47-
run: npm run lint -w packages/commons -w packages/logger -w packages/tracer -w packages/metrics -w packages/parameters
47+
run: npm run lint -w packages/commons -w packages/logger -w packages/tracer -w packages/metrics -w packages/parameters -w packages/idempotency
4848
- name: Run unit tests
49-
run: npm t -w packages/commons -w packages/logger -w packages/tracer -w packages/metrics -w packages/parameters
49+
run: npm t -w packages/commons -w packages/logger -w packages/tracer -w packages/metrics -w packages/parameters -w packages/idempotency
5050
check-examples:
5151
runs-on: ubuntu-latest
5252
env:

Diff for: package-lock.json

+857-164
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"packages/logger",
1010
"packages/metrics",
1111
"packages/tracer",
12-
"packages/parameters"
12+
"packages/parameters",
13+
"packages/idempotency"
1314
],
1415
"scripts": {
1516
"init-environment": "husky install",
@@ -84,4 +85,4 @@
8485
"dependencies": {
8586
"hosted-git-info": "^5.0.0"
8687
}
87-
}
88+
}

Diff for: packages/idempotency/jest.config.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module.exports = {
22
displayName: {
33
name: 'AWS Lambda Powertools utility: IDEMPOTENCY',
4-
color: 'cyan',
4+
color: 'blue',
55
},
66
'runner': 'groups',
77
'preset': 'ts-jest',
@@ -25,6 +25,7 @@ module.exports = {
2525
'coveragePathIgnorePatterns': [
2626
'/node_modules/',
2727
'/types/',
28+
'src/makeFunctionIdempotent.ts', // TODO: remove this once makeFunctionIdempotent is implemented
2829
],
2930
'coverageThreshold': {
3031
'global': {
@@ -38,5 +39,8 @@ module.exports = {
3839
'json-summary',
3940
'text',
4041
'lcov'
42+
],
43+
'setupFiles': [
44+
'<rootDir>/tests/helpers/populateEnvironmentVariables.ts'
4145
]
4246
};

Diff for: packages/idempotency/package.json

+8-8
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@
1313
"commit": "commit",
1414
"test": "npm run test:unit",
1515
"test:unit": "jest --group=unit --detectOpenHandles --coverage --verbose",
16-
"test:e2e:nodejs12x": "RUNTIME=nodejs12x jest --group=e2e",
17-
"test:e2e:nodejs14x": "RUNTIME=nodejs14x jest --group=e2e",
18-
"test:e2e:nodejs16x": "RUNTIME=nodejs16x jest --group=e2e",
19-
"test:e2e": "jest --group=e2e",
16+
"test:e2e:nodejs12x": "echo \"Not implemented\"",
17+
"test:e2e:nodejs14x": "echo \"Not implemented\"",
18+
"test:e2e:nodejs16x": "echo \"Not implemented\"",
19+
"test:e2e": "echo \"Not implemented\"",
2020
"watch": "jest --watch --group=unit",
2121
"build": "tsc",
2222
"lint": "eslint --ext .ts --no-error-on-unmatched-pattern src tests",
2323
"lint-fix": "eslint --fix --ext .ts --no-error-on-unmatched-pattern src tests",
2424
"package": "mkdir -p dist/ && npm pack && mv *.tgz dist/",
25-
"package-bundle": "../../package-bundler.sh logger-bundle ./dist",
25+
"package-bundle": "../../package-bundler.sh idempotency-bundle ./dist",
2626
"prepare": "npm run build",
27-
"postversion": "git push --tags"
27+
"postversion": "echo \"Not implemented\""
2828
},
2929
"homepage": "https://github.com/awslabs/aws-lambda-powertools-typescript/tree/master/packages/idempotency#readme",
3030
"license": "MIT",
@@ -42,7 +42,7 @@
4242
"url": "https://github.com/awslabs/aws-lambda-powertools-typescript/issues"
4343
},
4444
"dependencies": {
45-
"@aws-lambda-powertools/commons": "^1.2.1",
45+
"@aws-lambda-powertools/commons": "^1.4.1",
4646
"@aws-sdk/lib-dynamodb": "^3.170.0"
4747
},
4848
"keywords": [
@@ -56,4 +56,4 @@
5656
"aws-sdk-client-mock": "^2.0.0",
5757
"aws-sdk-client-mock-jest": "^2.0.0"
5858
}
59-
}
59+
}

Diff for: packages/idempotency/src/EnvironmentVariablesService.ts

-25
This file was deleted.
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
interface ConfigServiceInterface {
2+
3+
get(name: string): string
4+
5+
getServiceName(): string
6+
7+
getFunctionName(): string
8+
9+
}
10+
11+
export {
12+
ConfigServiceInterface
13+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { ConfigServiceInterface } from './ConfigServiceInterface';
2+
import { EnvironmentVariablesService as CommonEnvironmentVariablesService } from '@aws-lambda-powertools/commons';
3+
4+
/**
5+
* Class EnvironmentVariablesService
6+
*
7+
* This class is used to return environment variables that are available in the runtime of
8+
* the current Lambda invocation.
9+
* These variables can be a mix of runtime environment variables set by AWS and
10+
* variables that can be set by the developer additionally.
11+
*
12+
* @class
13+
* @extends {CommonEnvironmentVariablesService}
14+
* @implements {ConfigServiceInterface}
15+
* @see https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime
16+
* @see https://awslabs.github.io/aws-lambda-powertools-typescript/latest/#environment-variables
17+
*/
18+
class EnvironmentVariablesService extends CommonEnvironmentVariablesService implements ConfigServiceInterface {
19+
20+
// Reserved environment variables
21+
private functionNameVariable = 'AWS_LAMBDA_FUNCTION_NAME';
22+
23+
/**
24+
* It returns the value of the AWS_LAMBDA_FUNCTION_NAME environment variable.
25+
*
26+
* @returns {string}
27+
*/
28+
public getFunctionName(): string {
29+
return this.get(this.functionNameVariable);
30+
}
31+
32+
}
33+
34+
export {
35+
EnvironmentVariablesService
36+
};

Diff for: packages/idempotency/src/config/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './EnvironmentVariablesService';

Diff for: packages/idempotency/src/makeFunctionIdempotent.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
/* eslint-disable @typescript-eslint/no-explicit-any */
2-
import { AnyFunction } from './types/AnyFunction';
3-
import { IdempotencyOptions } from './IdempotencyOptions';
1+
import type { AnyFunction } from './types/AnyFunction';
2+
import type { IdempotencyOptions } from './types/IdempotencyOptions';
43

54
const makeFunctionIdempotent = <U>(
65
fn: AnyFunction<U>,
76
_options: IdempotencyOptions
7+
// TODO: revisit this with a more specific type if possible
8+
/* eslint-disable @typescript-eslint/no-explicit-any */
89
): (...args: Array<any>) => Promise<U | void> => (...args) => fn(...args);
910

1011
export { makeFunctionIdempotent };

Diff for: packages/idempotency/src/persistence/DynamoDbPersistenceLayer.ts renamed to packages/idempotency/src/persistence/DynamoDBPersistenceLayer.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { DynamoDB, DynamoDBServiceException } from '@aws-sdk/client-dynamodb';
2-
import { DynamoDBDocument, GetCommandOutput } from '@aws-sdk/lib-dynamodb';
2+
import { DynamoDBDocument } from '@aws-sdk/lib-dynamodb';
3+
import type { GetCommandOutput } from '@aws-sdk/lib-dynamodb';
34
import { DynamoPersistenceConstructorOptions } from '../types/DynamoPersistenceConstructorOptions';
45
import { IdempotencyItemAlreadyExistsError, IdempotencyItemNotFoundError } from '../Exceptions';
56
import { IdempotencyRecordStatus } from '../types/IdempotencyRecordStatus';
@@ -23,7 +24,7 @@ class DynamoDBPersistenceLayer extends PersistenceLayer {
2324
this.statusAttr = constructorOptions.statusAttr ?? 'status';
2425
this.expiryAttr = constructorOptions.expiryAttr ?? 'expiration';
2526
this.inProgressExpiryAttr = constructorOptions.inProgressExpiryAttr ?? 'in_progress_expiry_attr';
26-
this.dataAttr = constructorOptions.data_attr ?? 'data';
27+
this.dataAttr = constructorOptions.dataAttr ?? 'data';
2728
}
2829

2930
protected async _deleteRecord(record: IdempotencyRecord): Promise<void> {

Diff for: packages/idempotency/src/persistence/PersistenceLayer.ts

+20-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { BinaryToTextEncoding, createHash, Hash } from 'crypto';
22
import { IdempotencyRecordStatus } from '../types/IdempotencyRecordStatus';
3-
import { EnvironmentVariablesService } from '../EnvironmentVariablesService';
3+
import type { PersistenceLayerConfigureOptions } from '../types/PersistenceLayer';
4+
import { EnvironmentVariablesService } from '../config';
45
import { IdempotencyRecord } from './IdempotencyRecord';
56
import { PersistenceLayerInterface } from './PersistenceLayerInterface';
67

@@ -10,22 +11,32 @@ abstract class PersistenceLayer implements PersistenceLayerInterface {
1011
private envVarsService!: EnvironmentVariablesService;
1112

1213
private expiresAfterSeconds: number;
13-
14-
private functionName: string = '';
15-
14+
1615
private hashDigest: BinaryToTextEncoding;
17-
16+
1817
private hashFunction: string;
18+
19+
private idempotencyKeyPrefix: string;
1920

2021
public constructor() {
2122
this.setEnvVarsService();
2223
this.expiresAfterSeconds = 60 * 60; //one hour is the default expiration
2324
this.hashFunction = 'md5';
2425
this.hashDigest = 'base64';
25-
26+
this.idempotencyKeyPrefix = this.getEnvVarsService().getFunctionName();
27+
2628
}
27-
public configure(functionName: string = ''): void {
28-
this.functionName = this.getEnvVarsService().getLambdaFunctionName() + '.' + functionName;
29+
30+
/**
31+
* Configures the persistence layer by passing the name of the idempotent function. This will be used
32+
* in the prefix of the idempotency key
33+
*
34+
* @param {PersistenceLayerConfigureOptions} options - configuration object for the persistence layer
35+
*/
36+
public configure(options?: PersistenceLayerConfigureOptions): void {
37+
if (options?.functionName && options.functionName.trim() !== '') {
38+
this.idempotencyKeyPrefix = `${this.idempotencyKeyPrefix}.${options.functionName}`;
39+
}
2940
}
3041

3142
/**
@@ -136,7 +147,7 @@ abstract class PersistenceLayer implements PersistenceLayerInterface {
136147
console.warn('No data found for idempotency key');
137148
}
138149

139-
return this.functionName + '#' + this.generateHash(JSON.stringify(data));
150+
return `${this.idempotencyKeyPrefix}#${this.generateHash(JSON.stringify(data))}`;
140151
}
141152

142153
/**

Diff for: packages/idempotency/src/persistence/PersistenceLayerInterface.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { IdempotencyRecord } from './IdempotencyRecord';
2+
import type { PersistenceLayerConfigureOptions } from '../types/PersistenceLayer';
23

34
interface PersistenceLayerInterface {
4-
configure(functionName: string): void
5+
configure(options?: PersistenceLayerConfigureOptions): void
56
saveInProgress(data: unknown): Promise<void>
67
saveSuccess(data: unknown, result: unknown): Promise<void>
78
deleteRecord(data: unknown): Promise<void>

Diff for: packages/idempotency/src/persistence/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export * from './DynamoDbPersistenceLayer';
1+
export * from './DynamoDBPersistenceLayer';
22
export * from './PersistenceLayer';
33
export * from './PersistenceLayerInterface';
44
export * from './IdempotencyRecord';

Diff for: packages/idempotency/src/types/DynamoPersistenceConstructorOptions.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ type DynamoPersistenceConstructorOptions = {
44
statusAttr?: string
55
expiryAttr?: string
66
inProgressExpiryAttr?: string
7-
data_attr?: string
7+
dataAttr?: string
88
};
99

1010
export {

Diff for: packages/idempotency/src/IdempotencyOptions.ts renamed to packages/idempotency/src/types/IdempotencyOptions.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PersistenceLayer } from './persistence/PersistenceLayer';
1+
import { PersistenceLayer } from '../persistence/PersistenceLayer';
22

33
type IdempotencyOptions = {
44
dataKeywordArgument: string

Diff for: packages/idempotency/src/types/PersistenceLayer.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
type PersistenceLayerConfigureOptions = {
2+
functionName?: string
3+
};
4+
5+
export {
6+
PersistenceLayerConfigureOptions
7+
};

Diff for: packages/idempotency/src/types/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './AnyFunction';
2-
export * from './IdempotencyRecordStatus';
2+
export * from './IdempotencyRecordStatus';
3+
export * from './PersistenceLayer';
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
// Reserved variables
2-
process.env.AWS_REGION = 'us-east-1';
2+
process.env._X_AMZN_TRACE_ID = '1-abcdef12-3456abcdef123456abcdef12';
3+
process.env.AWS_LAMBDA_FUNCTION_NAME = 'my-lambda-function';
4+
process.env.AWS_EXECUTION_ENV = 'nodejs16.x';
5+
process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '128';
6+
process.env.AWS_REGION = 'eu-west-1';
7+
process.env._HANDLER = 'index.handler';

Diff for: packages/idempotency/tests/unit/EnvironmentVariableService.test.ts

-34
This file was deleted.

0 commit comments

Comments
 (0)