@kensio/yulin 1.21.7 → 1.21.9

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.
Files changed (99) hide show
  1. package/README.md +22 -2
  2. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.js +2 -0
  3. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.js +1 -1
  4. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.d.ts +2 -0
  5. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-input.js +4 -0
  6. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping-refusals.js +0 -5
  7. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping.handler.d.ts +2 -0
  8. package/dist/service/lambda/command/event-source-mapping/create-event-source-mapping.handler.js +2 -0
  9. package/dist/service/lambda/command/event-source-mapping/sim-lambda-event-source-mapping-commands.d.ts +2 -0
  10. package/dist/service/lambda/destination/sim-lambda-destination-targets.d.ts +2 -1
  11. package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.d.ts +0 -4
  12. package/dist/service/lambda/event-source/poll/kinesis/sim-lambda-kinesis-shard-poller.js +10 -15
  13. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event-source-poller.d.ts +1 -6
  14. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-event-source-poller.js +9 -27
  15. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-polling.d.ts +19 -0
  16. package/dist/service/lambda/event-source/poll/sim-lambda-dynamodb-stream-polling.js +27 -0
  17. package/dist/service/lambda/event-source/poll/sim-lambda-event-source-function.d.ts +1 -1
  18. package/dist/service/lambda/event-source/poll/sim-lambda-event-source-function.js +3 -1
  19. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-age.d.ts +13 -0
  20. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-age.js +27 -0
  21. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-info.d.ts +15 -0
  22. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-info.js +26 -0
  23. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-outcome.d.ts +1 -0
  24. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-outcome.js +7 -1
  25. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-processing.d.ts +17 -0
  26. package/dist/service/lambda/event-source/poll/sim-lambda-stream-batch-processing.js +12 -0
  27. package/dist/service/lambda/event-source/poll/sim-lambda-stream-cursor.d.ts +15 -0
  28. package/dist/service/lambda/event-source/poll/sim-lambda-stream-cursor.js +28 -0
  29. package/dist/service/lambda/event-source/poll/sim-lambda-stream-expiry.d.ts +19 -0
  30. package/dist/service/lambda/event-source/poll/sim-lambda-stream-expiry.js +23 -0
  31. package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-context.d.ts +3 -0
  32. package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-context.js +19 -0
  33. package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-destination.d.ts +15 -0
  34. package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-destination.js +38 -0
  35. package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-record.d.ts +41 -0
  36. package/dist/service/lambda/event-source/poll/sim-lambda-stream-failure-record.js +17 -0
  37. package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress-state.d.ts +21 -0
  38. package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress-state.js +39 -0
  39. package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress.d.ts +7 -37
  40. package/dist/service/lambda/event-source/poll/sim-lambda-stream-progress.js +22 -62
  41. package/dist/service/lambda/event-source/poll/sim-lambda-stream-retry.d.ts +4 -39
  42. package/dist/service/lambda/event-source/poll/sim-lambda-stream-retry.js +12 -64
  43. package/dist/service/lambda/event-source/sim-lambda-event-source-mapping.d.ts +10 -3
  44. package/dist/service/lambda/event-source/sim-lambda-event-source-mapping.js +12 -3
  45. package/dist/service/lambda/event-source/sim-lambda-stream-destination-config.d.ts +7 -0
  46. package/dist/service/lambda/event-source/sim-lambda-stream-destination-config.js +38 -0
  47. package/dist/service/lambda/event-source/stream/kinesis/sim-kinesis-event-source-streams.js +1 -0
  48. package/dist/service/lambda/event-source/stream/sim-dynamodb-event-source-stream-reader.js +1 -0
  49. package/dist/service/lambda/event-source/stream/sim-dynamodb-event-source-stream-shard.d.ts +1 -0
  50. package/dist/service/lambda/event-source/stream/sim-dynamodb-event-source-stream-shard.js +7 -0
  51. package/dist/service/lambda/event-source/stream/sim-lambda-event-source-streams.d.ts +1 -0
  52. package/dist/service/lambda/index.d.ts +1 -0
  53. package/dist/service/lambda/sim-lambda-commands.js +1 -0
  54. package/dist/service/ses/command/authorize/sim-ses-authorizer.d.ts +9 -0
  55. package/dist/service/ses/command/authorize/sim-ses-authorizer.js +18 -2
  56. package/dist/service/ses/command/send/sim-ses-send-email.js +2 -1
  57. package/docs/README.md +7 -0
  58. package/docs/ai-skill/README.md +6 -1
  59. package/docs/sdk/README.md +15 -0
  60. package/docs/services/acm/README.md +24 -40
  61. package/docs/services/apigateway/README.md +52 -71
  62. package/docs/services/apigatewayv2/README.md +55 -74
  63. package/docs/services/athena/README.md +17 -26
  64. package/docs/services/backup/README.md +29 -39
  65. package/docs/services/bedrock/README.md +38 -52
  66. package/docs/services/cloudformation/README.md +43 -55
  67. package/docs/services/cloudfront/README.md +69 -95
  68. package/docs/services/cloudwatch/README.md +40 -54
  69. package/docs/services/cognito/README.md +30 -45
  70. package/docs/services/dynamodb/README.md +34 -51
  71. package/docs/services/ecr/README.md +36 -77
  72. package/docs/services/ecs/README.md +26 -46
  73. package/docs/services/elbv2/README.md +19 -29
  74. package/docs/services/eventbridge/README.md +14 -18
  75. package/docs/services/firehose/README.md +24 -32
  76. package/docs/services/glue/README.md +41 -78
  77. package/docs/services/iam/README.md +13 -15
  78. package/docs/services/kinesis/README.md +53 -93
  79. package/docs/services/kms/README.md +22 -32
  80. package/docs/services/lambda/README.md +112 -85
  81. package/docs/services/logs/README.md +41 -50
  82. package/docs/services/organizations/README.md +50 -85
  83. package/docs/services/personalize/README.md +28 -44
  84. package/docs/services/rekognition/README.md +26 -38
  85. package/docs/services/route53/README.md +17 -17
  86. package/docs/services/s3/README.md +47 -51
  87. package/docs/services/scheduler/README.md +41 -52
  88. package/docs/services/secretsmanager/README.md +27 -42
  89. package/docs/services/ses/README.md +24 -34
  90. package/docs/services/sns/README.md +18 -26
  91. package/docs/services/sqs/README.md +14 -14
  92. package/docs/services/ssm/README.md +13 -17
  93. package/docs/services/stepfunctions/README.md +18 -20
  94. package/docs/services/sts/README.md +32 -45
  95. package/docs/services/wafv2/README.md +12 -17
  96. package/docs/testing/README.md +228 -0
  97. package/docs/time/README.md +10 -0
  98. package/llms.txt +1 -0
  99. package/package.json +1 -1
@@ -1,12 +1,11 @@
1
1
  # Simulated SSM Parameter Store
2
2
 
3
- Yulin includes a simulated AWS Systems Manager Parameter Store for tests and local development.
4
- Parameters are stored in memory, versioned on every write, and every operation is authorized by
5
- simulated IAM.
3
+ Yulin simulates AWS Systems Manager Parameter Store for tests and local development. You can create,
4
+ read, update and delete parameters through the AWS SDK or a CloudFormation template. Parameters are
5
+ stored in memory, each write creates a version, and simulated IAM authorizes every operation.
6
6
 
7
- Only Parameter Store is simulated.
8
-
9
- SSM-specific types are imported from the `@kensio/yulin/ssm` subpath.
7
+ Other Systems Manager features, such as Run Command and Session Manager, are not simulated. Import
8
+ SSM-specific types from `@kensio/yulin/ssm`.
10
9
 
11
10
  ## Writing and reading a parameter
12
11
 
@@ -292,8 +291,7 @@ console.log(origins.length); // 2
292
291
 
293
292
  ## Parameter names
294
293
 
295
- Name validation matches real Parameter Store, because a name it accepts and AWS refuses is a
296
- deployment failure a passing test would have hidden. A name:
294
+ Parameter names use the same validation rules as AWS. A name:
297
295
 
298
296
  - may contain letters, digits, `_`, `.`, `-` and `/`
299
297
  - must start with `/` if it contains a hierarchy at all
@@ -302,8 +300,8 @@ deployment failure a passing test would have hidden. A name:
302
300
  - may not contain spaces between characters, though surrounding spaces are stripped
303
301
  - may not make an ARN longer than 1011 characters, counting the ARN prefix for the account and region
304
302
 
305
- A `String` or `StringList` value holds at most 4KB, the standard tier limit. This is the one people
306
- hit, usually by putting a whole JSON configuration blob in one parameter.
303
+ A `String` or `StringList` value holds at most 4 KB, the standard tier limit. Larger configuration
304
+ documents must be split across parameters or stored elsewhere.
307
305
 
308
306
  ## Deploying a parameter from CloudFormation
309
307
 
@@ -455,9 +453,9 @@ covers that one.
455
453
 
456
454
  ### A reference the simulation cannot answer
457
455
 
458
- Simulated CloudFormation deploys what it can. A reference naming a parameter that was never created
459
- resolves to `dummy-value-for-<name>`, and the stack carries on deploying. A template reading
460
- configuration a test does not care about is still worth deploying for everything else in it.
456
+ When a reference names a parameter that does not exist, simulated CloudFormation substitutes
457
+ `dummy-value-for-<name>` and continues the deployment. This lets a test deploy the rest of a
458
+ template without setting up unrelated configuration.
461
459
 
462
460
  The substitution is recorded on
463
461
  [`stack.ignoredProperties`](https://yulinsim.dev/services/cloudformation/#properties-a-resource-was-created-without),
@@ -998,9 +996,9 @@ console.log(read.Parameter?.Value); // "hunter2"
998
996
 
999
997
  `DescribeParameters` reports the key each `SecureString` is encrypted under as `KeyId`.
1000
998
 
1001
- ## Available functionality
999
+ ## Supported operations
1002
1000
 
1003
- Sim SSM currently supports:
1001
+ Simulated Parameter Store supports:
1004
1002
 
1005
1003
  - `PutParameterCommand`, creating a parameter or overwriting one
1006
1004
  - `GetParameterCommand`, by name, by `name:version` or by `name:label`
@@ -1026,8 +1024,6 @@ Sim SSM currently supports:
1026
1024
 
1027
1025
  ## Limitations
1028
1026
 
1029
- Current documented limitations:
1030
-
1031
1027
  - Only standard tier `SecureString` encryption is simulated, which encrypts under the KMS key
1032
1028
  directly. The advanced tier's envelope encryption through the AWS Encryption SDK is left out, and
1033
1029
  `kms:GenerateDataKey` is never needed.
@@ -1,18 +1,18 @@
1
1
  # Simulated Step Functions
2
2
 
3
- Simulated Step Functions interprets Amazon States Language and runs a state machine in the same
4
- process as the code under test. A workflow held in a template as data becomes something a test can
5
- run and assert on.
3
+ Yulin interprets Amazon States Language and runs Step Functions state machines in the same process
4
+ as the code under test. Tests can start executions, invoke simulated services, advance waits and
5
+ inspect execution history without deploying a workflow.
6
6
 
7
- Types for simulated Step Functions are imported from the `@kensio/yulin/stepfunctions` subpath.
7
+ Import Step Functions-specific types from `@kensio/yulin/stepfunctions`.
8
8
 
9
- ## What runs today
9
+ ## Supported state machine features
10
10
 
11
- Every state type Amazon States Language defines runs. `Pass`, `Task`, `Succeed`, `Fail`, `Choice`,
12
- `Wait`, `Parallel` and `Map`.
11
+ All eight state types are supported: `Pass`, `Task`, `Succeed`, `Fail`, `Choice`, `Wait`, `Parallel`
12
+ and `Map`.
13
13
 
14
- The data-flow fields run in full. `InputPath`, `Parameters`, `ResultSelector`, `ResultPath` and
15
- `OutputPath` apply in that order, reading Reference Paths and the intrinsic functions.
14
+ The data-flow fields `InputPath`, `Parameters`, `ResultSelector`, `ResultPath` and `OutputPath` run in
15
+ that order. They support Reference Paths and intrinsic functions.
16
16
 
17
17
  A `Task` state invokes a simulated Lambda function, calls an operation on any other simulated
18
18
  service, or starts another state machine. A `Resource` this simulator has no answer for is refused
@@ -114,23 +114,21 @@ console.log(described.status); // FAILED
114
114
  console.log(described.error); // NotEligible
115
115
  ```
116
116
 
117
- A failing execution is recorded on the execution, and the call returns as it would for one that
118
- succeeded. Simulated EventBridge treats an undeliverable event the same way. An execution failing is
119
- as often the thing under test as it is a fault, and raising it would fail an unrelated `advanceBy`
120
- elsewhere in the same test.
117
+ A failed execution records its status and error instead of throwing from `StartExecution`. Read it
118
+ with `DescribeExecution` or the inspection API. This keeps workflow failure available for
119
+ assertions.
121
120
 
122
121
  ## Invoking a Lambda function
123
122
 
124
123
  A `Task` state invokes a simulated Lambda function, through either of the two `Resource` forms CDK's
125
124
  `LambdaInvoke` emits.
126
125
 
127
- `arn:aws:states:::lambda:invoke` is the integration Step Functions optimises. The state is talking to
128
- the Lambda API, so its `Parameters` are an `Invoke` request (`FunctionName` names the function and
129
- `Payload` carries what it is sent) and its result is an `Invoke` response, with the handler's answer
130
- under `Payload`.
126
+ With `arn:aws:states:::lambda:invoke`, `Parameters` has the shape of a Lambda `Invoke` request.
127
+ `FunctionName` selects the function, `Payload` contains its input, and the handler result appears
128
+ under `Payload` in the task output.
131
129
 
132
- A function ARN sends the state's own input to the handler and answers with what the handler
133
- returned. CDK writes this form for `payloadResponseOnly`.
130
+ A function ARN sends the state input directly to the handler and uses the handler result as the task
131
+ output. CDK emits this form when `payloadResponseOnly` is enabled.
134
132
 
135
133
  ```typescript sim-step-functions-task
136
134
  /**
@@ -1334,7 +1332,7 @@ reference contradicts itself here, listing a differing role ARN under `StateMach
1334
1332
  while the operation's own note says the difference is ignored. The note is the more specific of the
1335
1333
  two and is what this follows.
1336
1334
 
1337
- ## Still to come
1335
+ ## Limitations
1338
1336
 
1339
1337
  - Distributed Map, with `ItemReader`, `ResultWriter` and the `ToleratedFailure` fields.
1340
1338
  - The `.sync` pattern, task tokens and activities.
@@ -1,16 +1,12 @@
1
1
  # Simulated STS
2
2
 
3
- Yulin includes a simulated STS (Security Token Service) for tests and local development.
4
-
5
- Sim STS is used through `SimAws` as `simAws.sts()`, scoped to the Account making the assume request.
6
- It simulates assuming IAM Roles. An assume request is evaluated against
7
- [simulated IAM](https://yulinsim.dev/services/iam/) policies, and a request that passes issues temporary session credentials
8
- that the rest of the simulated environment authenticates like real AWS credentials.
3
+ Yulin simulates `AssumeRole` and `GetCallerIdentity`. Access the service through `simAws.sts()` or an
4
+ intercepted `STSClient`.
9
5
 
10
6
  ## Basic usage
11
7
 
12
- Create a Role whose trust policy allows the Account to assume it, then assume it through STS. An
13
- omitted caller defaults to the Account root principal.
8
+ Create a role with a trust policy, then call `assumeRole`. A request with no caller runs as the
9
+ account root.
14
10
 
15
11
  ```typescript sim-sts-assume-role
16
12
  /**
@@ -50,23 +46,28 @@ console.log(assumeRoleOutput.Credentials?.AccessKeyId);
50
46
  console.log(assumeRoleOutput.Credentials?.Expiration);
51
47
  ```
52
48
 
53
- The output matches the AWS shape. `AssumedRoleUser.Arn` is the session ARN, such as
49
+ `AssumedRoleUser.Arn` is the session ARN, such as
54
50
  `arn:aws:sts::123456789012:assumed-role/TargetRole/test-session`, and `Credentials` carries the
55
51
  temporary `AccessKeyId`, `SecretAccessKey`, `SessionToken`, and `Expiration`.
56
52
 
57
- The issued credentials are registered with the target Account's sim IAM. They authenticate later
58
- simulated requests, for example as the `caller` of an IAM authorization attempt, where identity
59
- policies come from the underlying Role. See [the sim IAM docs](https://yulinsim.dev/services/iam/#sts-assumerole-sessions) for a
60
- full example. Credentials missing their session token, or used after `Expiration`, are rejected with
61
- an AWS-like invalid-credentials error.
53
+ Yulin registers the credentials with simulated IAM in the target account. Later requests use the
54
+ role's identity policies. See [STS sessions in simulated IAM](https://yulinsim.dev/services/iam/#sts-assumerole-sessions).
55
+ Credentials fail after `Expiration` or when the session token is missing.
56
+
57
+ `DurationSeconds` defaults to 3,600 seconds and must be a positive integer.
58
+
59
+ ## Reading the current identity
62
60
 
63
- `DurationSeconds` controls the session lifetime and defaults to 3600 seconds (one hour). It must be
64
- a positive integer.
61
+ `getCallerIdentity` reports the caller's ARN, account ID and user ID. It handles account roots, IAM
62
+ users and assumed-role sessions. The intercepted and served STS APIs also support
63
+ `GetCallerIdentityCommand`.
64
+
65
+ An unattributed request reports the configured default caller, or the account root when no default
66
+ caller is configured. An anonymous caller receives `AccessDenied`.
65
67
 
66
68
  ## Role-to-Role assumption
67
69
 
68
- Pass a caller to assume a Role as a specific principal. As in real AWS, both sides of the request
69
- are then evaluated:
70
+ Pass `caller` to assume a role as a specific principal. STS checks both sides of the request:
70
71
 
71
72
  - The target Role's trust policy must allow the caller to perform `sts:AssumeRole`
72
73
  - A non-root caller also needs an identity policy allowing `sts:AssumeRole` on the target Role's
@@ -144,33 +145,25 @@ const assumeRoleOutput = await account.sts().assumeRole(
144
145
  console.log(assumeRoleOutput.AssumedRoleUser?.Arn);
145
146
  ```
146
147
 
147
- STS throws an AWS-like access-denied error if either side denies the request, which happens when the
148
- trust policy does not cover the caller, the caller has no identity policy allowing `sts:AssumeRole`,
149
- or an explicit `Deny` matches. The error has a `403` status code and names the `sts:AssumeRole`
150
- action and the target Role ARN. No session is created.
148
+ If either check fails, STS raises a 403 access-denied error naming `sts:AssumeRole` and the target
149
+ role ARN. No session is created.
151
150
 
152
- Cross-Account assumption works the same way. Create the source and target Roles in different
153
- simulated Accounts of the same `SimAws` instance, and call `assumeRole` on the source Account's
154
- `sts()`. The issued session belongs to the target Role's Account.
151
+ Cross-account assumption uses the same checks. Call `assumeRole` through the source account. The
152
+ session belongs to the target role's account.
155
153
 
156
154
  ## Role chaining
157
155
 
158
- A process that assumes a Role and then assumes a second one from that session is chaining Roles. The
159
- caller of the second request is the session, and the Role it holds the permissions of is what both
160
- sides of the decision are written against. The trust policy of the target names that Role, and the
161
- identity policy allowing `sts:AssumeRole` belongs to it.
156
+ For role chaining, use the first session as the caller of the second `assumeRole` request. The target
157
+ trust policy names the first role, and that role needs identity permission to assume the target.
162
158
 
163
- Both ARNs of a session are matched against a `Principal`, so a trust policy naming either the Role
164
- or one particular session admits it. AWS recommends naming the Role, and a session name is often
165
- decided at run time rather than written into a policy.
159
+ A trust policy may name the role ARN or one assumed-role session ARN. Prefer the role ARN when the
160
+ session name is chosen at run time.
166
161
 
167
- Chaining over a served endpoint works the same way. Credentials from the first request sign the
168
- second, and the caller they resolve to carries the Role along with the session.
162
+ The served endpoint resolves session credentials in the same way.
169
163
 
170
164
  ## ExternalId
171
165
 
172
- A trust policy can require an external ID through the `sts:ExternalId` condition key. The
173
- `ExternalId` supplied to `AssumeRoleCommand` is matched against it.
166
+ A trust policy can require `sts:ExternalId`. Pass the matching `ExternalId` to `AssumeRoleCommand`.
174
167
 
175
168
  ```typescript sim-sts-external-id
176
169
  /**
@@ -214,14 +207,14 @@ const assumeRoleOutput = await account.sts().assumeRole(
214
207
  console.log(assumeRoleOutput.AssumedRoleUser?.Arn);
215
208
  ```
216
209
 
217
- An omitted or mismatched `ExternalId` leaves the trust-policy condition unmatched. The assume
218
- request is denied.
210
+ An omitted or mismatched value denies the request.
219
211
 
220
212
  ## Available functionality
221
213
 
222
214
  Sim STS currently supports:
223
215
 
224
216
  - `AssumeRoleCommand`
217
+ - `GetCallerIdentityCommand`
225
218
  - Trust-policy evaluation against the target Role's assume-role policy document
226
219
  - Identity-policy evaluation of the source caller, requiring `sts:AssumeRole` permission on the
227
220
  target Role
@@ -231,15 +224,9 @@ Sim STS currently supports:
231
224
  - Temporary credentials registered with the target Account's sim IAM, including session-token and
232
225
  expiry validation
233
226
 
234
- Unsupported STS options may be ignored or may throw errors depending on whether the simulator needs
235
- them to model the requested behaviour.
236
-
237
227
  ## Limitations
238
228
 
239
- Sim STS models Role assumption. Notable gaps:
240
-
241
- - `AssumeRoleCommand` is the only supported command. There is no `GetCallerIdentity`, federation, or
242
- web-identity support
229
+ - Federation, web identity and session-token commands are unsupported.
243
230
  - Session policies (`Policy` / `PolicyArns`), tags, and `SourceIdentity` requests are not evaluated
244
231
  - Condition support in trust policies is limited to the operators supported by
245
232
  [sim IAM](https://yulinsim.dev/services/iam/#policy-conditions)
@@ -1,16 +1,11 @@
1
1
  # Simulated WAFv2
2
2
 
3
- Yulin includes a simulated AWS WAFv2 for tests and local development. It holds web ACLs, IP sets and
4
- regex pattern sets, and it evaluates a request against a web ACL's rules to reach a decision. A test
5
- can assert that a request to `/admin` is blocked and one to `/` is allowed, without an AWS account
6
- and without a distribution in front of anything.
3
+ Yulin simulates AWS WAFv2 web ACLs, IP sets and regex pattern sets for tests and local development.
4
+ You can evaluate a `Request` directly or associate a web ACL with a simulated API Gateway REST API,
5
+ Cognito user pool or CloudFront distribution. Each request is checked against the web ACL before
6
+ the protected service handles it.
7
7
 
8
- A web ACL can also go in front of what serves the requests. A simulated API Gateway REST API stage
9
- and a simulated Cognito user pool each take one through `AssociateWebACL`, and a simulated
10
- CloudFront distribution takes one through its own `WebACLId`. The requests that stage, pool or
11
- distribution serves are then put through the web ACL's rules.
12
-
13
- WAFv2 specific types are imported from the `@kensio/yulin/wafv2` subpath.
8
+ Import WAFv2-specific types from `@kensio/yulin/wafv2`.
14
9
 
15
10
  ## Deciding what happens to a request
16
11
 
@@ -91,11 +86,11 @@ carrying the status, the body and any headers the rule named.
91
86
 
92
87
  ## Rules run in priority order
93
88
 
94
- Rules are evaluated in ascending `Priority` and not in the order the list was written. The first
95
- rule that matches and carries a terminating action (`Allow` or `Block`) decides the request.
89
+ Rules are evaluated by ascending `Priority`, regardless of their order in the input list. The first
90
+ matching rule with an `Allow` or `Block` action decides the request.
96
91
 
97
- A `Count` action records the match and lets the next rule have a look. That is how a rule is staged
98
- before it is turned on, and `countedRuleNames` is what a test asserts against.
92
+ A `Count` action records the match and continues to the next rule. Tests can inspect
93
+ `countedRuleNames` before changing a rule to `Allow` or `Block`.
99
94
 
100
95
  ```typescript sim-wafv2-count
101
96
  /**
@@ -154,8 +149,8 @@ whatever serves the request has usually read it by the time WAF gets a look.
154
149
 
155
150
  ## What a statement can inspect
156
151
 
157
- A statement reads one part of the request, applies the rule's text transformations to it, and tests
158
- what comes out.
152
+ A statement selects part of the request, applies its text transformations, and then tests the
153
+ result.
159
154
 
160
155
  The parts a statement can be pointed at are `UriPath`, `QueryString`, `SingleQueryArgument`,
161
156
  `AllQueryArguments`, `SingleHeader`, `Headers`, `Cookies`, `Method` and `Body`. `Headers` and
@@ -1371,7 +1366,7 @@ Tags, logging, sampled requests and CloudWatch metrics for a web ACL are not sim
1371
1366
  `AssociationConfig`, `DataProtectionConfig`, `OnSourceDDoSProtectionConfig` and `ApplicationConfig`
1372
1367
  are refused for the same reason, each naming what it would have configured.
1373
1368
 
1374
- ## Simulated commands
1369
+ ## Supported operations
1375
1370
 
1376
1371
  `CreateWebACL`, `GetWebACL`, `UpdateWebACL`, `ListWebACLs`, `DeleteWebACL`, `CreateIPSet`,
1377
1372
  `GetIPSet`, `UpdateIPSet`, `ListIPSets`, `DeleteIPSet`, `CreateRegexPatternSet`,
@@ -0,0 +1,228 @@
1
+ # Test suite setup
2
+
3
+ Run one Yulin environment for an application's test suite. Create the simulation, deploy the
4
+ application's infrastructure, and install AWS SDK interception once. Every test then interacts with
5
+ the same simulated account and resources.
6
+
7
+ This is the recommended setup. It matches the way a suite uses a shared AWS account or a
8
+ container-based simulator such as LocalStack. Creating a new Yulin environment for every test or
9
+ test file is supported, but it should be reserved for cases that need a blank simulated account.
10
+
11
+ The simulated clock is the main exception. A suite-wide `SimAws` has one clock, so a test that moves
12
+ it changes time for every resource in that environment. Keep the majority of tests in the shared
13
+ environment without changing its clock. Put clock-controlling tests in a smaller isolated group.
14
+
15
+ ## Split the Vitest suite
16
+
17
+ Yulin holds state in the process that created it. Vitest must run the Yulin tests in one worker for
18
+ all shared files to reach the same environment. Give that project disabled file parallelism and file
19
+ isolation, then load a setup module before each test file.
20
+
21
+ The second project below matches files ending in `.clock.test.ts`. Those tests do not load the shared
22
+ setup and can create isolated Yulin environments:
23
+
24
+ ```typescript testing-vitest-config
25
+ import { defineConfig } from "vitest/config";
26
+
27
+ export default defineConfig({
28
+ test: {
29
+ environment: "node",
30
+ projects: [
31
+ {
32
+ extends: true,
33
+ test: {
34
+ name: "shared Yulin",
35
+ include: ["test/**/*.test.ts"],
36
+ exclude: ["test/**/*.clock.test.ts"],
37
+ fileParallelism: false,
38
+ isolate: false,
39
+ setupFiles: ["./test/setup-yulin.ts"],
40
+ },
41
+ },
42
+ {
43
+ extends: true,
44
+ test: {
45
+ name: "isolated Yulin clock",
46
+ include: ["test/**/*.clock.test.ts"],
47
+ },
48
+ },
49
+ ],
50
+ },
51
+ });
52
+ ```
53
+
54
+ Vitest executes a `setupFiles` entry before every test file. With isolation disabled, modules
55
+ imported by that entry stay cached in the worker. Put the Yulin initialization in an imported module
56
+ to make it run once.
57
+
58
+ See Vitest's documentation for [`setupFiles`](https://vitest.dev/config/setupfiles),
59
+ [`fileParallelism`](https://vitest.dev/config/fileparallelism), and
60
+ [`isolate`](https://vitest.dev/config/isolate).
61
+
62
+ ## Create and deploy the shared environment
63
+
64
+ Put the suite environment in a module such as `test/yulin-environment.ts`. Intercept client classes
65
+ used by the application and deploy its synthesized CDK cloud assembly:
66
+
67
+ ```typescript testing-shared-yulin-environment
68
+ import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
69
+ import { S3Client } from "@aws-sdk/client-s3";
70
+ import type { SimAws } from "@kensio/yulin";
71
+ import { SimSdk } from "@kensio/yulin/sdk";
72
+
73
+ interface YulinTestEnvironment {
74
+ readonly simAws: SimAws;
75
+ readonly simSdk: SimSdk;
76
+ readonly uploadsBucketName: string;
77
+ }
78
+
79
+ type YulinTestGlobal = typeof globalThis & {
80
+ yulinEnvironment?: Promise<YulinTestEnvironment>;
81
+ };
82
+
83
+ const testGlobal = globalThis as YulinTestGlobal;
84
+
85
+ // oxlint-disable-next-line unicorn-js/prefer-top-level-await -- The shared promise prevents setup from running again before another test file.
86
+ export const yulin = await (testGlobal.yulinEnvironment ??= startYulin());
87
+
88
+ async function startYulin(): Promise<YulinTestEnvironment> {
89
+ const simSdk = new SimSdk();
90
+ simSdk.intercept(DynamoDBClient);
91
+ simSdk.intercept(S3Client);
92
+
93
+ const stacks = await simSdk.simAws.cloudFormation().deployCdkOut({
94
+ directoryPath: "cdk.out",
95
+ stackNames: ["ApplicationStack"],
96
+ });
97
+ const appStack = stacks.get("ApplicationStack");
98
+
99
+ if (appStack === undefined) {
100
+ throw new Error("ApplicationStack was not deployed");
101
+ }
102
+
103
+ process.once("exit", () => {
104
+ simSdk.restoreAll();
105
+ });
106
+
107
+ return {
108
+ simAws: simSdk.simAws,
109
+ simSdk,
110
+ uploadsBucketName: appStack.output("UploadsBucketName"),
111
+ };
112
+ }
113
+ ```
114
+
115
+ Use the same templates that the application deploys. `deployCdkOut(...)` can deploy the whole cloud
116
+ assembly or the named application Stacks. Read generated resource names from stack outputs or
117
+ resource accessors after deployment.
118
+
119
+ The configured setup entry only needs to import that module:
120
+
121
+ ```typescript
122
+ // test/setup-yulin.ts
123
+ import "./yulin-environment.js";
124
+ ```
125
+
126
+ Do not put the initialization directly in `setup-yulin.ts`. Vitest executes that file for every test
127
+ file, even when isolation is disabled.
128
+
129
+ ## Use the environment from every test
130
+
131
+ Application code continues to construct and send through ordinary AWS SDK clients. Class-level
132
+ interception routes all of them to the suite's Yulin environment.
133
+
134
+ A test that needs direct access can import the shared environment:
135
+
136
+ ```typescript
137
+ import { randomUUID } from "node:crypto";
138
+
139
+ import {
140
+ GetObjectCommand,
141
+ PutObjectCommand,
142
+ S3Client,
143
+ } from "@aws-sdk/client-s3";
144
+ import { expect, it } from "vitest";
145
+
146
+ import { yulin } from "../yulin-environment.js";
147
+
148
+ it("stores an upload", async () => {
149
+ const key = `test-uploads/${randomUUID()}.txt`;
150
+ const s3 = new S3Client({ region: "eu-west-2" });
151
+
152
+ await s3.send(
153
+ new PutObjectCommand({
154
+ Bucket: yulin.uploadsBucketName,
155
+ Key: key,
156
+ Body: "an upload",
157
+ }),
158
+ );
159
+
160
+ const stored = await yulin.simAws
161
+ .region("eu-west-2")
162
+ .s3()
163
+ .getObject(
164
+ new GetObjectCommand({
165
+ Bucket: yulin.uploadsBucketName,
166
+ Key: key,
167
+ }),
168
+ );
169
+
170
+ expect(await stored?.Body?.transformToString()).toBe("an upload");
171
+ });
172
+ ```
173
+
174
+ The `SimAws` object is mainly useful for preparing input state and reading state back in assertions.
175
+ Exercise the application through its normal interfaces whenever possible.
176
+
177
+ ## Keep tests independent in shared state
178
+
179
+ Shared infrastructure does not require tests to depend on one another. Give each test's records,
180
+ object keys, user names, and other mutable data unique values. Read CloudFormation-generated names
181
+ from the deployed stack. Avoid assertions that assume the simulated account contains no other data.
182
+
183
+ Keep `beforeEach` for the records a test needs. A per-file `beforeAll` can prepare data used by every
184
+ test in that file. Leave the suite's stacks and SDK interception in place until the worker exits.
185
+
186
+ Tests run sequentially with `fileParallelism: false`. If a test uses `it.concurrent`, its data still
187
+ needs unique identifiers because those cases share the same environment at the same time.
188
+
189
+ ## Give clock-controlling tests their own environment
190
+
191
+ Every service in a `SimAws` reads the same simulated clock. Calling `advanceBy(...)` can expire
192
+ credentials, delete resources whose retention period has passed, and run scheduled work anywhere in
193
+ the environment. Resetting the clock afterwards cannot reverse those changes.
194
+
195
+ Tests in the shared project should treat the clock as read-only. Put a test that calls `freeze()`,
196
+ `setTo(...)`, `advanceBy(...)`, or `resume()` in a `.clock.test.ts` file and create a fresh environment
197
+ inside the test:
198
+
199
+ ```typescript
200
+ import { SimAws, SimFixedClock } from "@kensio/yulin";
201
+ import { it } from "vitest";
202
+
203
+ it("expires a session", async () => {
204
+ const simAws = new SimAws({
205
+ clock: new SimFixedClock(new Date("2026-09-04T09:00:00.000Z")),
206
+ });
207
+
208
+ // Deploy only the infrastructure this clock-controlling test needs.
209
+
210
+ await simAws.clock().advanceBy({ minutes: 20 });
211
+
212
+ // Assert the behaviour after the time change.
213
+ });
214
+ ```
215
+
216
+ Create a `SimSdk` around that `SimAws` when application code uses SDK clients. Restore its
217
+ interceptions at the end of the test. The [simulated time guide](https://yulinsim.dev/time/) describes
218
+ what moving the clock runs and changes.
219
+
220
+ ## When to create another environment
221
+
222
+ A fresh `SimAws` or `SimSdk` is useful when the empty environment is part of the behaviour under
223
+ test, or when the test needs to control simulated time. Yulin's own service unit tests are another
224
+ example because they test resource creation and account isolation directly.
225
+
226
+ Vitest workers cannot share an in-memory `SimAws`. A suite that keeps file parallelism creates one
227
+ environment per worker. Put Yulin-based application tests in a Vitest project with
228
+ `fileParallelism: false` when the rest of the unit suite should remain parallel.
@@ -3,6 +3,16 @@
3
3
  Each `SimAws` has its own clock. Yulin uses that clock for resource timestamps, expiry checks, and
4
4
  scheduled work.
5
5
 
6
+ ## Isolate tests that control time
7
+
8
+ A shared [test suite environment](https://yulinsim.dev/testing/) also has one shared clock. Most
9
+ tests should use that environment without calling `freeze()`, `setTo(...)`, `advanceBy(...)`, or
10
+ `resume()`.
11
+
12
+ Put tests that control simulated time in a separate test group. Give each of those tests its own
13
+ `SimAws` or `SimSdk`, along with the infrastructure it needs. A clock change then affects only that
14
+ test's environment. The rest of the suite can keep sharing one deployment and SDK interception.
15
+
6
16
  ## Start at a known time
7
17
 
8
18
  A new simulation follows the system clock by default. Pass a `SimFixedClock` when a test needs an
package/llms.txt CHANGED
@@ -57,4 +57,5 @@ The same pages are on the web at https://yulinsim.dev/ for whichever release is
57
57
  - [Non-AWS dependencies](docs/non-aws-dependencies/README.md): Dependencies Yulin does not simulate usage docs
58
58
  - [Serving on localhost](docs/serve/README.md): Serving simulated AWS on localhost usage docs
59
59
  - [Simulated time](docs/time/README.md): Simulated time usage docs
60
+ - [Test suite setup](docs/testing/README.md): Sharing one Yulin environment across a test suite
60
61
  - [Terraform](docs/terraform/README.md): Deploying Terraform into simulated AWS usage docs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kensio/yulin",
3
- "version": "1.21.7",
3
+ "version": "1.21.9",
4
4
  "description": "AWS system behaviour simulation for isolated unit testing",
5
5
  "repository": "https://github.com/KensioSoftware/yulin",
6
6
  "homepage": "https://yulinsim.dev/",