@othree.io/chisel-forge 1.0.1
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/README.md +234 -0
- package/lib/cjs/index.d.ts +13 -0
- package/lib/cjs/index.d.ts.map +1 -0
- package/lib/cjs/index.js +167 -0
- package/lib/cjs/index.js.map +1 -0
- package/lib/cjs/utils.d.ts +233 -0
- package/lib/cjs/utils.d.ts.map +1 -0
- package/lib/cjs/utils.js +395 -0
- package/lib/cjs/utils.js.map +1 -0
- package/lib/esm/index.js +130 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/utils.js +380 -0
- package/lib/esm/utils.js.map +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# @othree.io/chisel-forge
|
|
2
|
+
|
|
3
|
+
Integration testing utilities for the [Chisel](https://www.npmjs.com/package/@othree.io/chisel) CQRS/Event Sourcing framework. Provides a fluent API to send commands against deployed AWS infrastructure and validate triggered events and aggregate state.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @othree.io/chisel-forge
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Peer Dependencies
|
|
12
|
+
|
|
13
|
+
- `@othree.io/awsome` ^4.0.0
|
|
14
|
+
- `@othree.io/chisel` ^5.0.0
|
|
15
|
+
- `@othree.io/optional` ^2.3.2
|
|
16
|
+
- `vitest` ^3.2.4
|
|
17
|
+
|
|
18
|
+
## Quick Start~
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { when } from '@othree.io/chisel-forge'
|
|
22
|
+
import { Empty } from '@othree.io/optional'
|
|
23
|
+
|
|
24
|
+
type PersonState = Readonly<{
|
|
25
|
+
name: string
|
|
26
|
+
lastName: string
|
|
27
|
+
}>
|
|
28
|
+
|
|
29
|
+
const configuration = {
|
|
30
|
+
boundedContext: 'Person',
|
|
31
|
+
commandHandlerArn: 'arn:aws:lambda:us-east-1:123456789:function:PersonCommandHandler',
|
|
32
|
+
eventsTable: 'PersonEvents',
|
|
33
|
+
topicArn: 'arn:aws:sns:us-east-1:123456789:PersonEventsTopic',
|
|
34
|
+
testName: 'CreatePerson',
|
|
35
|
+
subscriptionAwaitTime: 3000,
|
|
36
|
+
loadStateLambdaArn: Empty(),
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
it('should create a person', async () => {
|
|
40
|
+
await when<PersonState>(configuration)({
|
|
41
|
+
type: 'CreatePerson',
|
|
42
|
+
body: { name: 'Chuck', lastName: 'Norris' },
|
|
43
|
+
})
|
|
44
|
+
.expectState({ name: 'Chuck', lastName: 'Norris' })
|
|
45
|
+
.expectEvent({
|
|
46
|
+
contextId: expect.any(String),
|
|
47
|
+
type: 'PersonCreated',
|
|
48
|
+
body: { name: 'Chuck', lastName: 'Norris' },
|
|
49
|
+
})
|
|
50
|
+
.toPass()
|
|
51
|
+
}, 30000)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Command Handler Modes
|
|
55
|
+
|
|
56
|
+
The `when()` function supports three command delivery modes, determined by the configuration type.
|
|
57
|
+
|
|
58
|
+
### Synchronous Lambda
|
|
59
|
+
|
|
60
|
+
Invokes the command handler Lambda directly and receives the `CommandResult` in the response.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const configuration = {
|
|
64
|
+
boundedContext: 'Person',
|
|
65
|
+
commandHandlerArn: 'arn:aws:lambda:...:PersonCommandHandler',
|
|
66
|
+
eventsTable: 'PersonEvents',
|
|
67
|
+
topicArn: 'arn:aws:sns:...:PersonEventsTopic',
|
|
68
|
+
testName: 'CreatePerson',
|
|
69
|
+
subscriptionAwaitTime: 3000,
|
|
70
|
+
loadStateLambdaArn: Empty(),
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Async SQS
|
|
75
|
+
|
|
76
|
+
Sends the command to an SQS queue. The command handler processes it asynchronously.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const configuration = {
|
|
80
|
+
boundedContext: 'Person',
|
|
81
|
+
commandQueueUrl: 'https://sqs.us-east-1.amazonaws.com/.../PersonCommandQueue.fifo',
|
|
82
|
+
commandDLQUrl: 'https://sqs.us-east-1.amazonaws.com/.../PersonCommandDLQ.fifo',
|
|
83
|
+
eventsTable: 'PersonEvents',
|
|
84
|
+
topicArn: 'arn:aws:sns:...:PersonEventsTopic.fifo',
|
|
85
|
+
testName: 'CreatePerson',
|
|
86
|
+
subscriptionAwaitTime: 3000,
|
|
87
|
+
loadStateLambdaArn: Empty(),
|
|
88
|
+
extractMessageGroupId: (command) => command.contextId,
|
|
89
|
+
extractMessageDeduplicationId: (command) => `${command.type}-${command.contextId}`,
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Async SNS
|
|
94
|
+
|
|
95
|
+
Sends the command to an SNS topic. The command handler subscribes and processes it asynchronously.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
const configuration = {
|
|
99
|
+
boundedContext: 'Person',
|
|
100
|
+
commandTopicArn: 'arn:aws:sns:...:PersonCommandTopic.fifo',
|
|
101
|
+
commandDLQUrl: 'https://sqs.us-east-1.amazonaws.com/.../PersonCommandDLQ.fifo',
|
|
102
|
+
eventsTable: 'PersonEvents',
|
|
103
|
+
topicArn: 'arn:aws:sns:...:PersonEventsTopic.fifo',
|
|
104
|
+
testName: 'CreatePerson',
|
|
105
|
+
subscriptionAwaitTime: 3000,
|
|
106
|
+
loadStateLambdaArn: Empty(),
|
|
107
|
+
extractMessageGroupId: (command) => command.contextId,
|
|
108
|
+
extractMessageDeduplicationId: (command) => `${command.type}-${command.contextId}`,
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Fluent API
|
|
113
|
+
|
|
114
|
+
### `when<State>(configuration)(command)`
|
|
115
|
+
|
|
116
|
+
Entry point. Accepts a configuration and returns a function that takes a `Command` and returns a test builder.
|
|
117
|
+
|
|
118
|
+
### `.and(getCommand)`
|
|
119
|
+
|
|
120
|
+
Chains a subsequent command. The `getCommand` callback receives the `contextId` from the first command's result as an `Optional<string>`.
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
await when<PersonState>(configuration)({
|
|
124
|
+
type: 'CreatePerson',
|
|
125
|
+
body: { name: 'Chuck', lastName: 'Norris' },
|
|
126
|
+
})
|
|
127
|
+
.and((contextId) => ({
|
|
128
|
+
contextId: contextId.get(),
|
|
129
|
+
type: 'UpdatePerson',
|
|
130
|
+
body: { name: 'Bruce', lastName: 'Lee' },
|
|
131
|
+
}))
|
|
132
|
+
.expectState({ name: 'Bruce', lastName: 'Lee' })
|
|
133
|
+
.toPass()
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### `.expectEvent(event)`
|
|
137
|
+
|
|
138
|
+
Asserts that a specific `ChiselEvent` was triggered. Can be called multiple times for multiple expected events.
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
.expectEvent({
|
|
142
|
+
contextId: expect.any(String),
|
|
143
|
+
type: 'PersonCreated',
|
|
144
|
+
body: { name: 'Chuck', lastName: 'Norris' },
|
|
145
|
+
})
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `.expectState(state)`
|
|
149
|
+
|
|
150
|
+
Asserts the final aggregate state matches the expected value. When `loadStateLambdaArn` is configured, also validates the state returned by the load-state Lambda.
|
|
151
|
+
|
|
152
|
+
### `.toPass()`
|
|
153
|
+
|
|
154
|
+
Executes the command(s), validates events and state, and returns the `CommandResult` array. Automatically cleans up temporary SQS queues, subscriptions, and events.
|
|
155
|
+
|
|
156
|
+
### `.toFail(errorMsg?)`
|
|
157
|
+
|
|
158
|
+
Asserts the command fails with a `CommandExecutionError`. Optionally validates the error message.
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
const error = await when<PersonState>(configuration)({
|
|
162
|
+
type: 'CreatePerson',
|
|
163
|
+
body: { name: '', lastName: '' },
|
|
164
|
+
}).toFail('Validation failed')
|
|
165
|
+
|
|
166
|
+
expect(error.name).toEqual('CommandExecutionError')
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## AWS Credentials
|
|
170
|
+
|
|
171
|
+
Pass optional AWS credentials as the second argument to `when()`:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { fromSSO } from '@aws-sdk/credential-providers'
|
|
175
|
+
|
|
176
|
+
const credentials = fromSSO({ profile: 'my-profile' })
|
|
177
|
+
|
|
178
|
+
await when<PersonState>(configuration, credentials)({
|
|
179
|
+
type: 'CreatePerson',
|
|
180
|
+
body: { name: 'Chuck', lastName: 'Norris' },
|
|
181
|
+
}).toPass()
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Low-Level API
|
|
185
|
+
|
|
186
|
+
For advanced use cases, the low-level functions are available under the `lowLevel` namespace:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import { lowLevel } from '@othree.io/chisel-forge'
|
|
190
|
+
|
|
191
|
+
const {
|
|
192
|
+
when,
|
|
193
|
+
runAndValidate,
|
|
194
|
+
runAndValidateAsync,
|
|
195
|
+
cleanUp,
|
|
196
|
+
createQueueAndSubscribe,
|
|
197
|
+
receiveMessages,
|
|
198
|
+
} = lowLevel
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
These accept explicit dependency objects, making them fully testable in isolation.
|
|
202
|
+
|
|
203
|
+
## How It Works
|
|
204
|
+
|
|
205
|
+
1. Creates a temporary SQS queue and subscribes it to the bounded context's SNS events topic
|
|
206
|
+
2. Sends the command(s) to the command handler (Lambda, SQS, or SNS depending on config)
|
|
207
|
+
3. Receives triggered event messages from the temporary queue
|
|
208
|
+
4. Validates events and state against expectations
|
|
209
|
+
5. Cleans up: deletes the temporary queue, unsubscribes from the topic, and removes events from the events table
|
|
210
|
+
|
|
211
|
+
## Configuration Reference
|
|
212
|
+
|
|
213
|
+
| Property | Type | Required | Description |
|
|
214
|
+
|---|---|---|---|
|
|
215
|
+
| `boundedContext` | `string` | All | Bounded context name (matched against event message attributes) |
|
|
216
|
+
| `topicArn` | `string` | All | SNS topic ARN where the bounded context publishes events |
|
|
217
|
+
| `eventsTable` | `string` | All | DynamoDB events table name (for cleanup) |
|
|
218
|
+
| `subscriptionAwaitTime` | `number` | All | Milliseconds to wait after subscribing before sending commands |
|
|
219
|
+
| `testName` | `string` | All | Used to name the temporary SQS queue |
|
|
220
|
+
| `loadStateLambdaArn` | `Optional<string>` | All | Lambda ARN for loading aggregate state (optional validation) |
|
|
221
|
+
| `commandHandlerArn` | `string` | Sync | Lambda ARN for the command handler |
|
|
222
|
+
| `commandQueueUrl` | `string` | Async SQS | SQS queue URL for commands |
|
|
223
|
+
| `commandTopicArn` | `string` | Async SNS | SNS topic ARN for commands |
|
|
224
|
+
| `commandDLQUrl` | `string` | Async | SQS DLQ URL for failed commands |
|
|
225
|
+
| `extractMessageGroupId` | `(command) => string` | Async | FIFO message group ID extractor (optional) |
|
|
226
|
+
| `extractMessageDeduplicationId` | `(command) => string` | Async | FIFO deduplication ID extractor (optional) |
|
|
227
|
+
|
|
228
|
+
## Scripts
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
npm test # Run tests
|
|
232
|
+
npm run build # Compile TypeScript
|
|
233
|
+
npm run docs # Generate JSDoc documentation
|
|
234
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TestConfiguration } from './utils';
|
|
2
|
+
import { Command } from '@othree.io/chisel';
|
|
3
|
+
import { AwsCredentialIdentity, Provider } from '@aws-sdk/types';
|
|
4
|
+
export * as lowLevel from './utils';
|
|
5
|
+
/**
|
|
6
|
+
* Initializes a testing environment for Chisel framework.
|
|
7
|
+
* @function
|
|
8
|
+
* @param {ChiselTestConfiguration} configuration - The configuration for the Chisel test.
|
|
9
|
+
* @param {TestConfiguration} [credentials] - The optional AWS credentials.
|
|
10
|
+
* @returns A function that initializes a testing environment and returns a low-level when function.
|
|
11
|
+
*/
|
|
12
|
+
export declare const when: <State>(configuration: TestConfiguration, credentials?: AwsCredentialIdentity | Provider<AwsCredentialIdentity>) => (command: Command) => import("./utils").CommandChiselTest<State>;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAWH,iBAAiB,EAEpB,MAAM,SAAS,CAAA;AAIhB,OAAO,EAAC,OAAO,EAAwC,MAAM,mBAAmB,CAAA;AAGhF,OAAO,EAAC,qBAAqB,EAAE,QAAQ,EAAC,MAAM,gBAAgB,CAAA;AAG9D,OAAO,KAAK,QAAQ,MAAM,SAAS,CAAA;AAEnC;;;;;;GAMG;AACH,eAAO,MAAM,IAAI,GAAI,KAAK,EAAE,eAAe,iBAAiB,EAAE,cAAc,qBAAqB,GAAG,QAAQ,CAAC,qBAAqB,CAAC,qEAiIlI,CAAA"}
|
package/lib/cjs/index.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.when = exports.lowLevel = void 0;
|
|
37
|
+
const utils_1 = require("./utils");
|
|
38
|
+
const client_lambda_1 = require("@aws-sdk/client-lambda");
|
|
39
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
40
|
+
const awsome_1 = require("@othree.io/awsome");
|
|
41
|
+
const client_sqs_1 = require("@aws-sdk/client-sqs");
|
|
42
|
+
const client_sns_1 = require("@aws-sdk/client-sns");
|
|
43
|
+
const optional_1 = require("@othree.io/optional");
|
|
44
|
+
exports.lowLevel = __importStar(require("./utils"));
|
|
45
|
+
/**
|
|
46
|
+
* Initializes a testing environment for Chisel framework.
|
|
47
|
+
* @function
|
|
48
|
+
* @param {ChiselTestConfiguration} configuration - The configuration for the Chisel test.
|
|
49
|
+
* @param {TestConfiguration} [credentials] - The optional AWS credentials.
|
|
50
|
+
* @returns A function that initializes a testing environment and returns a low-level when function.
|
|
51
|
+
*/
|
|
52
|
+
const when = (configuration, credentials) => {
|
|
53
|
+
const sqsClient = new client_sqs_1.SQSClient({
|
|
54
|
+
credentials: credentials
|
|
55
|
+
});
|
|
56
|
+
const createQueueFn = awsome_1.sqs.createQueue({ client: sqsClient });
|
|
57
|
+
const deleteQueueFn = awsome_1.sqs.deleteQueue({ client: sqsClient });
|
|
58
|
+
const snsClient = new client_sns_1.SNSClient({
|
|
59
|
+
credentials: credentials
|
|
60
|
+
});
|
|
61
|
+
const snsConfiguration = {
|
|
62
|
+
BatchSize: 10,
|
|
63
|
+
Parallelism: 10,
|
|
64
|
+
TopicArn: configuration.topicArn
|
|
65
|
+
};
|
|
66
|
+
const subscribeSqsFn = awsome_1.sns.subscribeSqs({ snsClient, sqsClient, configuration: snsConfiguration });
|
|
67
|
+
const unsubscribeFn = awsome_1.sns.unsubscribe({ snsClient });
|
|
68
|
+
const dynamoClient = new client_dynamodb_1.DynamoDBClient({
|
|
69
|
+
credentials: credentials
|
|
70
|
+
});
|
|
71
|
+
const dynamoConfiguration = {
|
|
72
|
+
TableName: configuration.eventsTable
|
|
73
|
+
};
|
|
74
|
+
const deleteByFn = awsome_1.dynamo.deleteBy({ dynamoDb: dynamoClient, configuration: dynamoConfiguration });
|
|
75
|
+
const queryFn = awsome_1.dynamo.query({ dynamoDb: dynamoClient, configuration: dynamoConfiguration });
|
|
76
|
+
const getByFn = awsome_1.dynamo.getBy({ query: queryFn });
|
|
77
|
+
const cleanUpFn = (0, utils_1.cleanUp)({
|
|
78
|
+
getBy: getByFn,
|
|
79
|
+
deleteBy: deleteByFn,
|
|
80
|
+
deleteQueue: deleteQueueFn,
|
|
81
|
+
unsubscribe: unsubscribeFn,
|
|
82
|
+
});
|
|
83
|
+
const loadState = configuration.loadStateLambdaArn.map(lambdaArn => {
|
|
84
|
+
const lambdaClient = new client_lambda_1.LambdaClient({
|
|
85
|
+
credentials: credentials
|
|
86
|
+
});
|
|
87
|
+
return awsome_1.lambda.query({ lambda: lambdaClient, functionName: lambdaArn });
|
|
88
|
+
}).orElse(async (payload) => (0, optional_1.Empty)());
|
|
89
|
+
const createQueueAndSubscribeFn = (0, utils_1.createQueueAndSubscribe)({
|
|
90
|
+
now: () => new Date().getTime(),
|
|
91
|
+
createQueue: createQueueFn,
|
|
92
|
+
cleanUp: cleanUpFn,
|
|
93
|
+
subscribeSqs: subscribeSqsFn,
|
|
94
|
+
});
|
|
95
|
+
const receiveMessagesFn = (0, utils_1.receiveMessages)({
|
|
96
|
+
sqsClient: sqsClient,
|
|
97
|
+
receive: awsome_1.sqs.receiveMessages,
|
|
98
|
+
});
|
|
99
|
+
if ((0, utils_1.isChiselTestConfiguration)(configuration)) {
|
|
100
|
+
const lambdaClient = new client_lambda_1.LambdaClient({
|
|
101
|
+
credentials: credentials
|
|
102
|
+
});
|
|
103
|
+
const commandHandlerClient = awsome_1.lambda.command({ lambda: lambdaClient, functionName: configuration.commandHandlerArn });
|
|
104
|
+
return (0, utils_1.when)((0, utils_1.runAndValidate)({
|
|
105
|
+
sendCommand: commandHandlerClient,
|
|
106
|
+
createQueueAndSubscribe: createQueueAndSubscribeFn,
|
|
107
|
+
receiveMessages: receiveMessagesFn,
|
|
108
|
+
cleanUp: cleanUpFn,
|
|
109
|
+
configuration,
|
|
110
|
+
loadState,
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
const receiveDLQMessages = awsome_1.sqs.receiveMessages({
|
|
115
|
+
client: sqsClient,
|
|
116
|
+
configuration: {
|
|
117
|
+
QueueUrl: configuration.commandDLQUrl,
|
|
118
|
+
maxNumberOfMessages: 10,
|
|
119
|
+
waitTimeSeconds: 5,
|
|
120
|
+
autoAcknowledgeMessages: true,
|
|
121
|
+
},
|
|
122
|
+
transformMessage: (message) => {
|
|
123
|
+
return JSON.parse((0, optional_1.Optional)(message.Body).orElse('{}'));
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
if ((0, utils_1.isAsyncSqsChiselTestConfiguration)(configuration)) {
|
|
127
|
+
const sendCommand = awsome_1.sqs.send({
|
|
128
|
+
client: sqsClient,
|
|
129
|
+
configuration: { QueueUrl: configuration.commandQueueUrl },
|
|
130
|
+
withMessageGroupId: configuration.extractMessageGroupId,
|
|
131
|
+
withDeduplicationId: configuration.extractMessageDeduplicationId,
|
|
132
|
+
});
|
|
133
|
+
return (0, utils_1.when)((0, utils_1.runAndValidateAsync)({
|
|
134
|
+
sendCommand,
|
|
135
|
+
createQueueAndSubscribe: createQueueAndSubscribeFn,
|
|
136
|
+
receiveMessages: receiveMessagesFn,
|
|
137
|
+
cleanUp: cleanUpFn,
|
|
138
|
+
receiveErrorMessages: receiveDLQMessages,
|
|
139
|
+
configuration,
|
|
140
|
+
loadState,
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
const sendCommand = awsome_1.sns.send({
|
|
145
|
+
client: snsClient,
|
|
146
|
+
configuration: {
|
|
147
|
+
TopicArn: configuration.commandTopicArn,
|
|
148
|
+
Parallelism: 10,
|
|
149
|
+
BatchSize: 10,
|
|
150
|
+
},
|
|
151
|
+
withMessageGroupId: configuration.extractMessageGroupId,
|
|
152
|
+
withMessageDeduplicationId: configuration.extractMessageDeduplicationId,
|
|
153
|
+
});
|
|
154
|
+
return (0, utils_1.when)((0, utils_1.runAndValidateAsync)({
|
|
155
|
+
sendCommand,
|
|
156
|
+
createQueueAndSubscribe: createQueueAndSubscribeFn,
|
|
157
|
+
receiveMessages: receiveMessagesFn,
|
|
158
|
+
cleanUp: cleanUpFn,
|
|
159
|
+
receiveErrorMessages: receiveDLQMessages,
|
|
160
|
+
configuration,
|
|
161
|
+
loadState,
|
|
162
|
+
}));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
exports.when = when;
|
|
167
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ChiselTestConfiguration,\n cleanUp,\n createQueueAndSubscribe,\n DLQMessage,\n isAsyncSqsChiselTestConfiguration,\n isChiselTestConfiguration,\n LoadStateQuery,\n receiveMessages,\n runAndValidate,\n runAndValidateAsync,\n TestConfiguration,\n when as lowLevelWhen\n} from './utils'\nimport {LambdaClient} from '@aws-sdk/client-lambda'\nimport {DynamoDBClient} from '@aws-sdk/client-dynamodb'\nimport {lambda, sns, sqs, dynamo} from '@othree.io/awsome'\nimport {Command, CommandResult, InternalTriggeredEvent} from '@othree.io/chisel'\nimport {Message, SQSClient} from '@aws-sdk/client-sqs'\nimport {SNSClient} from '@aws-sdk/client-sns'\nimport {AwsCredentialIdentity, Provider} from '@aws-sdk/types'\nimport {Empty, Optional} from '@othree.io/optional'\n\nexport * as lowLevel from './utils'\n\n/**\n * Initializes a testing environment for Chisel framework.\n * @function\n * @param {ChiselTestConfiguration} configuration - The configuration for the Chisel test.\n * @param {TestConfiguration} [credentials] - The optional AWS credentials.\n * @returns A function that initializes a testing environment and returns a low-level when function.\n */\nexport const when = <State>(configuration: TestConfiguration, credentials?: AwsCredentialIdentity | Provider<AwsCredentialIdentity>) => {\n const sqsClient = new SQSClient({\n credentials: credentials\n })\n\n const createQueueFn = sqs.createQueue({client: sqsClient})\n const deleteQueueFn = sqs.deleteQueue({client: sqsClient})\n\n const snsClient = new SNSClient({\n credentials: credentials\n })\n\n const snsConfiguration: sns.SNSConfiguration = {\n BatchSize: 10,\n Parallelism: 10,\n TopicArn: configuration.topicArn\n }\n\n const subscribeSqsFn = sns.subscribeSqs({snsClient, sqsClient, configuration: snsConfiguration})\n\n const unsubscribeFn = sns.unsubscribe({snsClient})\n\n const dynamoClient = new DynamoDBClient({\n credentials: credentials\n })\n\n const dynamoConfiguration: dynamo.DynamoConfiguration = {\n TableName: configuration.eventsTable\n }\n\n const deleteByFn = dynamo.deleteBy({dynamoDb: dynamoClient, configuration: dynamoConfiguration})\n\n const queryFn = dynamo.query<InternalTriggeredEvent>({dynamoDb: dynamoClient, configuration: dynamoConfiguration})\n const getByFn = dynamo.getBy<InternalTriggeredEvent>({query: queryFn})\n\n const cleanUpFn = cleanUp({\n getBy: getByFn,\n deleteBy: deleteByFn,\n deleteQueue: deleteQueueFn,\n unsubscribe: unsubscribeFn,\n })\n\n const loadState = configuration.loadStateLambdaArn.map(lambdaArn => {\n const lambdaClient = new LambdaClient({\n credentials: credentials\n })\n return lambda.query<LoadStateQuery, State>({lambda: lambdaClient, functionName: lambdaArn})\n }).orElse(async (payload: LoadStateQuery) => Empty())\n\n const createQueueAndSubscribeFn = createQueueAndSubscribe({\n now: () => new Date().getTime(),\n createQueue: createQueueFn,\n cleanUp: cleanUpFn,\n subscribeSqs: subscribeSqsFn,\n })\n const receiveMessagesFn = receiveMessages({\n sqsClient: sqsClient,\n receive: sqs.receiveMessages,\n })\n\n if (isChiselTestConfiguration(configuration)) {\n const lambdaClient = new LambdaClient({\n credentials: credentials\n })\n const commandHandlerClient = lambda.command<Command, CommandResult<State>>({lambda: lambdaClient, functionName: configuration.commandHandlerArn})\n\n return lowLevelWhen(runAndValidate<State>({\n sendCommand: commandHandlerClient,\n createQueueAndSubscribe: createQueueAndSubscribeFn,\n receiveMessages: receiveMessagesFn,\n cleanUp: cleanUpFn,\n configuration,\n loadState,\n }))\n } else {\n const receiveDLQMessages = sqs.receiveMessages<DLQMessage>({\n client: sqsClient,\n configuration: {\n QueueUrl: configuration.commandDLQUrl,\n maxNumberOfMessages: 10,\n waitTimeSeconds: 5,\n autoAcknowledgeMessages: true,\n },\n transformMessage: (message: Message) => {\n return JSON.parse(Optional(message.Body).orElse('{}')) as DLQMessage\n },\n })\n\n if (isAsyncSqsChiselTestConfiguration(configuration)) {\n const sendCommand = sqs.send<Command>({\n client: sqsClient,\n configuration: {QueueUrl: configuration.commandQueueUrl},\n withMessageGroupId: configuration.extractMessageGroupId,\n withDeduplicationId: configuration.extractMessageDeduplicationId,\n })\n\n return lowLevelWhen(runAndValidateAsync<State>({\n sendCommand,\n createQueueAndSubscribe: createQueueAndSubscribeFn,\n receiveMessages: receiveMessagesFn,\n cleanUp: cleanUpFn,\n receiveErrorMessages: receiveDLQMessages,\n configuration,\n loadState,\n }))\n } else {\n const sendCommand = sns.send<Command>({\n client: snsClient,\n configuration: {\n TopicArn: configuration.commandTopicArn,\n Parallelism: 10,\n BatchSize: 10,\n },\n withMessageGroupId: configuration.extractMessageGroupId,\n withMessageDeduplicationId: configuration.extractMessageDeduplicationId,\n })\n\n return lowLevelWhen(runAndValidateAsync<State>({\n sendCommand,\n createQueueAndSubscribe: createQueueAndSubscribeFn,\n receiveMessages: receiveMessagesFn,\n cleanUp: cleanUpFn,\n receiveErrorMessages: receiveDLQMessages,\n configuration,\n loadState,\n }))\n }\n }\n\n}\n"]}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { Command, CommandResult, InternalTriggeredEvent, ChiselEvent } from '@othree.io/chisel';
|
|
2
|
+
import { Optional } from '@othree.io/optional';
|
|
3
|
+
import { sqs, sns, dynamo } from '@othree.io/awsome';
|
|
4
|
+
import { Message, SQSClient } from '@aws-sdk/client-sqs';
|
|
5
|
+
/**
|
|
6
|
+
* Custom error class for representing errors that occur during command execution.
|
|
7
|
+
* @class
|
|
8
|
+
* @extends {Error}
|
|
9
|
+
*/
|
|
10
|
+
export declare class CommandExecutionError extends Error {
|
|
11
|
+
static ERROR: string;
|
|
12
|
+
command: Command;
|
|
13
|
+
constructor(command: Command, message?: string);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Represents an error message related to a command placed in a dead-letter queue (DLQ).
|
|
17
|
+
* @typedef DLQMessage
|
|
18
|
+
*/
|
|
19
|
+
export type DLQMessage = Readonly<{
|
|
20
|
+
request: Command;
|
|
21
|
+
error: Readonly<{
|
|
22
|
+
name: string;
|
|
23
|
+
message: string;
|
|
24
|
+
stack?: string;
|
|
25
|
+
}>;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* Represents a query for loading the state using a context identifier.
|
|
29
|
+
* @typedef LoadStateQuery
|
|
30
|
+
*/
|
|
31
|
+
export type LoadStateQuery = Readonly<{
|
|
32
|
+
contextId: string;
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* Represents a Chisel test builder that configures expected events and states for a command.
|
|
36
|
+
* @typedef ChiselTest
|
|
37
|
+
* @template State - The type representing the state.
|
|
38
|
+
*/
|
|
39
|
+
export type ChiselTest<State> = Readonly<{
|
|
40
|
+
/**
|
|
41
|
+
* Specifies an expected event that should be produced by the command.
|
|
42
|
+
* @param {ChiselEvent} event - The expected event.
|
|
43
|
+
* @returns {ChiselTest<State>} The ChiselTest instance with the expected event.
|
|
44
|
+
*/
|
|
45
|
+
expectEvent: (event: ChiselEvent) => ChiselTest<State>;
|
|
46
|
+
/**
|
|
47
|
+
* Specifies an expected state that the system should be in after the command execution.
|
|
48
|
+
* @param {State} state - The expected state.
|
|
49
|
+
* @returns {ChiselTest<State>} The ChiselTest instance with the expected state.
|
|
50
|
+
*/
|
|
51
|
+
expectState: (state: State) => ChiselTest<State>;
|
|
52
|
+
/**
|
|
53
|
+
* Executes the command and validates the expected results.
|
|
54
|
+
* @returns {Promise<CommandResult<State>>} A promise that resolves to the command(s) results.
|
|
55
|
+
*/
|
|
56
|
+
toPass: () => Promise<Array<CommandResult<State>>>;
|
|
57
|
+
}>;
|
|
58
|
+
export type GetCommand = (contextId: Optional<string>) => Command;
|
|
59
|
+
/**
|
|
60
|
+
* A specialized extension of the `ChiselTest` type tailored for testing command execution.
|
|
61
|
+
* @typedef CommandChiselTest
|
|
62
|
+
* @template State - The type representing the state used in the test.
|
|
63
|
+
*/
|
|
64
|
+
export type CommandChiselTest<State> = Readonly<{
|
|
65
|
+
and: (getCommand: GetCommand) => CommandChiselTest<State>;
|
|
66
|
+
toFail: (errorMsg?: string) => Promise<Error>;
|
|
67
|
+
}> & ChiselTest<State>;
|
|
68
|
+
/**
|
|
69
|
+
* Creates a Chisel test builder based on a given run and validate function.
|
|
70
|
+
* @template State - The type representing the state.
|
|
71
|
+
* @param {RunAndValidate<State>} runAndValidate - The function to run and validate a command.
|
|
72
|
+
* @returns A function that accepts a command and returns a ChiselTest instance.
|
|
73
|
+
*/
|
|
74
|
+
export declare const when: <State>(runAndValidate: RunAndValidate<State>) => (command: Command) => CommandChiselTest<State>;
|
|
75
|
+
/**
|
|
76
|
+
* Represents the configuration for all types of tests
|
|
77
|
+
* @typedef BaseTestConfiguration
|
|
78
|
+
*/
|
|
79
|
+
export type BaseTestConfiguration = Readonly<{
|
|
80
|
+
boundedContext: string;
|
|
81
|
+
topicArn: string;
|
|
82
|
+
eventsTable: string;
|
|
83
|
+
subscriptionAwaitTime: number;
|
|
84
|
+
testName: string;
|
|
85
|
+
loadStateLambdaArn: Optional<string>;
|
|
86
|
+
}>;
|
|
87
|
+
/**
|
|
88
|
+
* Configuration options for a Chisel test.
|
|
89
|
+
* @typedef ChiselTestConfiguration
|
|
90
|
+
*/
|
|
91
|
+
export type ChiselTestConfiguration = Readonly<{
|
|
92
|
+
commandHandlerArn: string;
|
|
93
|
+
}> & BaseTestConfiguration;
|
|
94
|
+
/**
|
|
95
|
+
* Configuration options for an Async SQS Chisel test.
|
|
96
|
+
* @typedef AsyncSqsChiselTestConfiguration
|
|
97
|
+
*/
|
|
98
|
+
export type AsyncSqsChiselTestConfiguration = Readonly<{
|
|
99
|
+
commandQueueUrl: string;
|
|
100
|
+
extractMessageGroupId?: (command: Command) => string;
|
|
101
|
+
extractMessageDeduplicationId?: (command: Command) => string;
|
|
102
|
+
commandDLQUrl: string;
|
|
103
|
+
}> & BaseTestConfiguration;
|
|
104
|
+
/**
|
|
105
|
+
* Configuration options for an Async SNS Chisel test.
|
|
106
|
+
* @typedef AsyncSnsChiselTestConfiguration
|
|
107
|
+
*/
|
|
108
|
+
export type AsyncSnsChiselTestConfiguration = Readonly<{
|
|
109
|
+
commandTopicArn: string;
|
|
110
|
+
extractMessageGroupId?: (command: Command) => string;
|
|
111
|
+
extractMessageDeduplicationId?: (command: Command) => string;
|
|
112
|
+
commandDLQUrl: string;
|
|
113
|
+
}> & BaseTestConfiguration;
|
|
114
|
+
/**
|
|
115
|
+
* Represents the possible configurations for different types of tests.
|
|
116
|
+
* @typedef {ChiselTestConfiguration | AsyncSqsChiselTestConfiguration | AsyncSnsChiselTestConfiguration} TestConfiguration
|
|
117
|
+
*/
|
|
118
|
+
export type TestConfiguration = ChiselTestConfiguration | AsyncSqsChiselTestConfiguration | AsyncSnsChiselTestConfiguration;
|
|
119
|
+
/**
|
|
120
|
+
* Determines if the configuration is an ChiselTestConfiguration
|
|
121
|
+
* @param configuration Test configuration
|
|
122
|
+
* @returns {boolean} True is configuration is of type ChiselTestConfiguration
|
|
123
|
+
*/
|
|
124
|
+
export declare const isChiselTestConfiguration: (configuration: TestConfiguration) => configuration is ChiselTestConfiguration;
|
|
125
|
+
/**
|
|
126
|
+
* Determines if the configuration is an AsyncSqsChiselTestConfiguration
|
|
127
|
+
* @param configuration Test configuration
|
|
128
|
+
* @returns {boolean} True is configuration is of type AsyncSqsChiselTestConfiguration
|
|
129
|
+
*/
|
|
130
|
+
export declare const isAsyncSqsChiselTestConfiguration: (configuration: TestConfiguration) => configuration is AsyncSqsChiselTestConfiguration;
|
|
131
|
+
/**
|
|
132
|
+
* Represents a Chisel event message containing attributes, an event, and a state.
|
|
133
|
+
* @typedef ChiselEventMessage
|
|
134
|
+
* @template State - The type representing the state.
|
|
135
|
+
*/
|
|
136
|
+
export type ChiselEventMessage<State> = Readonly<{
|
|
137
|
+
messageAttributes: Readonly<{
|
|
138
|
+
bc: string;
|
|
139
|
+
eventType: string;
|
|
140
|
+
}>;
|
|
141
|
+
event: InternalTriggeredEvent;
|
|
142
|
+
state: State;
|
|
143
|
+
}>;
|
|
144
|
+
/**
|
|
145
|
+
* Function type for cleanup operations including deleting a queue, events, and data.
|
|
146
|
+
* @typedef {Function} CleanUp
|
|
147
|
+
*/
|
|
148
|
+
export type CleanUp = <State>(queue: SubscribedSqsQueue | sqs.SqsQueue, maybeCommandResults: Optional<Array<CommandResult<State>>>) => Promise<true>;
|
|
149
|
+
/**
|
|
150
|
+
* Performs cleanup operations including deleting a queue, events, and data.
|
|
151
|
+
* @function
|
|
152
|
+
* @param deps - Dependencies for cleanup operations.
|
|
153
|
+
* @returns {CleanUp} A function that performs cleanup operations.
|
|
154
|
+
*/
|
|
155
|
+
export declare const cleanUp: (deps: {
|
|
156
|
+
getBy: (keys: dynamo.Keys) => Promise<Optional<Array<InternalTriggeredEvent>>>;
|
|
157
|
+
deleteBy: (keys: dynamo.Keys) => Promise<Optional<boolean>>;
|
|
158
|
+
deleteQueue: (request: sqs.DeleteQueueRequest) => Promise<Optional<boolean>>;
|
|
159
|
+
unsubscribe: (subscription: sns.Subscription) => Promise<Optional<true>>;
|
|
160
|
+
}) => CleanUp;
|
|
161
|
+
/**
|
|
162
|
+
* Representation of a queue subscribed to a topic
|
|
163
|
+
* @typedef SubscribedSqsQueue
|
|
164
|
+
*/
|
|
165
|
+
export type SubscribedSqsQueue = Readonly<{
|
|
166
|
+
subscriptionArn: string;
|
|
167
|
+
}> & sqs.SqsQueue;
|
|
168
|
+
/**
|
|
169
|
+
* Creates and subscribes to an SQS queue.
|
|
170
|
+
* @typedef {Function} CreateQueueAndSubscribe
|
|
171
|
+
*/
|
|
172
|
+
export type CreateQueueAndSubscribe = (configuration: TestConfiguration) => Promise<SubscribedSqsQueue | sqs.SqsQueue>;
|
|
173
|
+
/**
|
|
174
|
+
* Creates and subscribes to an SQS queue.
|
|
175
|
+
* @function
|
|
176
|
+
* @param deps - Dependencies for queue creation and subscription.
|
|
177
|
+
* @returns {CreateQueueAndSubscribe} A function that creates and subscribes to an SQS queue.
|
|
178
|
+
*/
|
|
179
|
+
export declare const createQueueAndSubscribe: (deps: {
|
|
180
|
+
now: () => number;
|
|
181
|
+
createQueue: (request: sqs.CreateQueueRequest) => Promise<Optional<sqs.SqsQueue>>;
|
|
182
|
+
cleanUp: CleanUp;
|
|
183
|
+
subscribeSqs: (request: sns.SubscribeQueueRequest) => Promise<Optional<sns.Subscription>>;
|
|
184
|
+
}) => CreateQueueAndSubscribe;
|
|
185
|
+
/**
|
|
186
|
+
* Asynchronous function for receiving messages from an SQS queue.
|
|
187
|
+
* @function
|
|
188
|
+
* @param deps - Dependencies for receiving messages.
|
|
189
|
+
* @returns A function that receives messages from a specified queue URL.
|
|
190
|
+
*/
|
|
191
|
+
export declare const receiveMessages: (deps: {
|
|
192
|
+
sqsClient: SQSClient;
|
|
193
|
+
receive: <T>(deps: Readonly<{
|
|
194
|
+
client: SQSClient;
|
|
195
|
+
configuration: sqs.ReceiveMessagesConfiguration;
|
|
196
|
+
transformMessage: (message: Message) => T;
|
|
197
|
+
}>) => () => Promise<Optional<Array<T>>>;
|
|
198
|
+
}) => (queueUrl: string) => Promise<Array<Message>>;
|
|
199
|
+
/**
|
|
200
|
+
* A function that runs a command, validates the results, and performs cleanup operations.
|
|
201
|
+
* @typedef {Function} RunAndValidate
|
|
202
|
+
*/
|
|
203
|
+
export type RunAndValidate<State> = (command: Command, getCommands: Array<GetCommand>, maybeExpectedState: Optional<State>, expectedEvents: Array<ChiselEvent>) => Promise<Array<CommandResult<State>>>;
|
|
204
|
+
/**
|
|
205
|
+
* Runs a command, validates the results, and performs cleanup operations.
|
|
206
|
+
* @function
|
|
207
|
+
* @param deps - Dependencies for running and validating commands.
|
|
208
|
+
* @returns {RunAndValidate<State>} The run and validate function.
|
|
209
|
+
*/
|
|
210
|
+
export declare const runAndValidate: <State>(deps: {
|
|
211
|
+
sendCommand: (command: Command) => Promise<Optional<CommandResult<State>>>;
|
|
212
|
+
createQueueAndSubscribe: CreateQueueAndSubscribe;
|
|
213
|
+
receiveMessages: (queueUrl: string) => Promise<Array<Message>>;
|
|
214
|
+
cleanUp: CleanUp;
|
|
215
|
+
configuration: ChiselTestConfiguration;
|
|
216
|
+
loadState: (query: LoadStateQuery) => Promise<Optional<State>>;
|
|
217
|
+
}) => RunAndValidate<State>;
|
|
218
|
+
/**
|
|
219
|
+
* Sends a command to a queue and validates the command events and state.
|
|
220
|
+
* @function
|
|
221
|
+
* @param deps - Dependencies for running and validating async commands.
|
|
222
|
+
* @returns {RunAndValidate<State>} The run and validate function.
|
|
223
|
+
*/
|
|
224
|
+
export declare const runAndValidateAsync: <State>(deps: {
|
|
225
|
+
sendCommand: (command: Command) => Promise<Optional<boolean>>;
|
|
226
|
+
createQueueAndSubscribe: CreateQueueAndSubscribe;
|
|
227
|
+
receiveMessages: (queueUrl: string) => Promise<Array<Message>>;
|
|
228
|
+
cleanUp: CleanUp;
|
|
229
|
+
receiveErrorMessages: () => Promise<Optional<Array<DLQMessage>>>;
|
|
230
|
+
configuration: AsyncSqsChiselTestConfiguration | AsyncSnsChiselTestConfiguration;
|
|
231
|
+
loadState: (query: LoadStateQuery) => Promise<Optional<State>>;
|
|
232
|
+
}) => RunAndValidate<State>;
|
|
233
|
+
//# sourceMappingURL=utils.d.ts.map
|