@kensio/yulin 1.21.6 → 1.21.8

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 (74) hide show
  1. package/README.md +22 -2
  2. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-creator.js +1 -0
  3. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-properties.d.ts +4 -0
  4. package/dist/service/eventbridge/cfn/bus/sim-cfn-event-bus-properties.js +26 -1
  5. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-creator.js +3 -1
  6. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-properties.d.ts +0 -7
  7. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-properties.js +0 -20
  8. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-unsimulated-properties.d.ts +13 -0
  9. package/dist/service/eventbridge/cfn/rule/sim-cfn-event-rule-unsimulated-properties.js +59 -0
  10. package/dist/service/eventbridge/cfn/sim-cfn-event-bridge-resource-error.d.ts +1 -1
  11. package/dist/service/eventbridge/cfn/sim-cfn-event-bridge-resource-error.js +1 -1
  12. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-properties.js +1 -1
  13. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.d.ts +3 -2
  14. package/dist/service/lambda/cfn/event-source-mapping/sim-cfn-lambda-event-source-mapping-property-rules.js +25 -3
  15. package/dist/service/ses/command/authorize/sim-ses-authorizer.d.ts +9 -0
  16. package/dist/service/ses/command/authorize/sim-ses-authorizer.js +18 -2
  17. package/dist/service/ses/command/send/sim-ses-send-email.js +2 -1
  18. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-creator.js +1 -0
  19. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-properties.d.ts +9 -4
  20. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-properties.js +18 -6
  21. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-property-names.d.ts +10 -0
  22. package/dist/service/sns/cfn/topic/sim-cfn-sns-topic-property-names.js +16 -1
  23. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-creator.js +1 -1
  24. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-properties.d.ts +11 -6
  25. package/dist/service/ssm/cfn/parameter/sim-cfn-ssm-parameter-properties.js +18 -9
  26. package/docs/README.md +40 -4
  27. package/docs/ai-skill/README.md +57 -54
  28. package/docs/cli/README.md +84 -94
  29. package/docs/factories/README.md +42 -54
  30. package/docs/lint/README.md +41 -67
  31. package/docs/non-aws-dependencies/README.md +72 -168
  32. package/docs/sdk/README.md +109 -95
  33. package/docs/serve/README.md +192 -898
  34. package/docs/services/acm/README.md +24 -40
  35. package/docs/services/apigateway/README.md +52 -71
  36. package/docs/services/apigatewayv2/README.md +55 -74
  37. package/docs/services/athena/README.md +17 -26
  38. package/docs/services/backup/README.md +29 -39
  39. package/docs/services/bedrock/README.md +38 -52
  40. package/docs/services/cloudformation/README.md +43 -55
  41. package/docs/services/cloudfront/README.md +69 -95
  42. package/docs/services/cloudwatch/README.md +40 -54
  43. package/docs/services/cognito/README.md +30 -45
  44. package/docs/services/dynamodb/README.md +34 -51
  45. package/docs/services/ecr/README.md +36 -77
  46. package/docs/services/ecs/README.md +26 -46
  47. package/docs/services/elbv2/README.md +19 -29
  48. package/docs/services/eventbridge/README.md +24 -20
  49. package/docs/services/firehose/README.md +24 -32
  50. package/docs/services/glue/README.md +41 -78
  51. package/docs/services/iam/README.md +13 -15
  52. package/docs/services/kinesis/README.md +53 -93
  53. package/docs/services/kms/README.md +22 -32
  54. package/docs/services/lambda/README.md +60 -80
  55. package/docs/services/logs/README.md +41 -50
  56. package/docs/services/organizations/README.md +50 -85
  57. package/docs/services/personalize/README.md +28 -44
  58. package/docs/services/rekognition/README.md +26 -38
  59. package/docs/services/route53/README.md +17 -17
  60. package/docs/services/s3/README.md +47 -51
  61. package/docs/services/scheduler/README.md +41 -52
  62. package/docs/services/secretsmanager/README.md +27 -42
  63. package/docs/services/ses/README.md +24 -34
  64. package/docs/services/sns/README.md +31 -33
  65. package/docs/services/sqs/README.md +14 -14
  66. package/docs/services/ssm/README.md +19 -21
  67. package/docs/services/stepfunctions/README.md +18 -20
  68. package/docs/services/sts/README.md +32 -45
  69. package/docs/services/wafv2/README.md +12 -17
  70. package/docs/terraform/README.md +108 -126
  71. package/docs/testing/README.md +228 -0
  72. package/docs/time/README.md +87 -117
  73. package/llms.txt +2 -1
  74. package/package.json +1 -1
@@ -1,24 +1,22 @@
1
1
  # Simulated time
2
2
 
3
- Every timestamp a simulated AWS service produces comes from that simulation's own clock, and that
4
- clock can be moved. Time can be frozen, set to an instant, or advanced by a duration. Behaviour that
5
- depends on time passing, such as a temporary session expiring, can be tested without waiting for it.
3
+ Each `SimAws` has its own clock. Yulin uses that clock for resource timestamps, expiry checks, and
4
+ scheduled work.
6
5
 
7
- Time belongs to a `SimAws` instance. Moving it affects that instance only. The host clock, another
8
- simulation running in the same test file, and any other code in the process all carry on unchanged.
6
+ ## Isolate tests that control time
9
7
 
10
- ## Reading the time
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
11
 
12
- `simAws.now()` is what the simulation means by "now". The host clock may say something different. It
13
- also stamps simulated resources, such as an IAM User's `CreateDate` and an `AssumeRole` session's
14
- `Expiration`.
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
15
 
16
- By default a new `SimAws` runs in step with the real system clock.
16
+ ## Start at a known time
17
17
 
18
- ## Starting at a known instant
19
-
20
- Pass a clock to start somewhere specific. `SimFixedClock` is the usual choice, since it reports one
21
- instant and stays there:
18
+ A new simulation follows the system clock by default. Pass a `SimFixedClock` when a test needs an
19
+ exact starting time:
22
20
 
23
21
  ```typescript sim-clock-freeze-and-advance
24
22
  /**
@@ -47,41 +45,33 @@ console.log(simAws.now()); // 2026-07-26T11:30:00.000Z
47
45
  simAws.clock().resume();
48
46
  ```
49
47
 
50
- Simulated time is layered over whatever clock is supplied. A simulation started at a fixed instant
51
- is still free to move from there, and it stays measured against that clock. Resuming a simulation
52
- built on a `SimFixedClock` puts it back in running mode, and its time then moves whenever the clock
53
- underneath moves. A fixed clock stays where it is. Leave the default real clock in place for a
54
- simulation whose time should pass by itself.
48
+ `simAws.now()` returns the current simulated time. Services use the same value when they create
49
+ timestamps such as an IAM user's `CreateDate`.
55
50
 
56
- ## Frozen and running
51
+ The controllable clock sits on top of the clock passed to `SimAws`. Calling `resume()` makes time
52
+ follow that underlying clock again. A `SimFixedClock` never moves, so resuming it still reports a
53
+ fixed time. Keep the default system clock when resumed time should move normally.
57
54
 
58
- There are two modes:
55
+ ## Frozen and running
59
56
 
60
- - **Frozen**: simulated time only moves when something moves it. A frozen clock reports the same
61
- instant however long the host takes, and a slow test holds the state it set up. This is what a
62
- deterministic assertion wants.
63
- - **Running**: simulated time tracks the clock underneath, offset from it. On the default real clock
64
- time passes by itself. Use it to jump forward an hour and carry on.
57
+ Call `freeze()` to stop the clock at its current time. Both `setTo(...)` and `advanceBy(...)` also
58
+ leave the clock frozen at the resulting time. This keeps timestamps stable while the test makes its
59
+ assertions.
65
60
 
66
- Moving time deliberately freezes it. `setTo(...)` and `advanceBy(...)` both leave the clock stopped
67
- where they put it. A test that asked for a specific instant then asserts on that instant, however
68
- long the assertion takes. `resume()` is the way back to running, and it carries on from where the
69
- clock stopped.
61
+ Call `resume()` to let the underlying clock move time again. Any offset remains in place. For
62
+ example, a simulation advanced by one hour continues to run one hour ahead of the system clock.
70
63
 
71
- `simAws.clock().isFrozen` reports which mode the clock is in.
64
+ Read `simAws.clock().isFrozen` to check the current mode.
72
65
 
73
66
  ## Advancing time
74
67
 
75
- `advanceBy(...)` takes a duration written as any combination of `days`, `hours`, `minutes`,
76
- `seconds` and `milliseconds`, which add together. A bare number counts milliseconds, as it does for
77
- `setTimeout`, and `advanceBy(3_600_000)` moves an hour. Durations are never negative, since time
78
- passing only runs forwards. `setTo(...)` is the explicit way to move a clock back.
68
+ `advanceBy(...)` accepts days, hours, minutes, seconds, and milliseconds. The values are added
69
+ together. A number means milliseconds, so `advanceBy(3_600_000)` advances by one hour. Durations
70
+ must be zero or greater. Use `setTo(...)` to move to an earlier time.
79
71
 
80
- Advancing moves the clock, and it runs whatever the passage of time should have caused. Work
81
- scheduled for an instant inside the interval is dispatched in due order, each task running with the
82
- clock reading its own due time. Further work it schedules settles before `advanceBy` returns where
83
- that work is itself due by the new time, and stays queued where it falls later. So a test can
84
- advance and then assert, with no additional waiting:
72
+ Advancing the clock also runs scheduled work due within the interval. Yulin runs each task at its
73
+ due time and waits for the simulation to settle before returning. The test can assert on the result
74
+ immediately:
85
75
 
86
76
  ```typescript sim-clock-session-expiry
87
77
  /**
@@ -138,31 +128,16 @@ try {
138
128
  }
139
129
  ```
140
130
 
141
- Work triggered by advancing that fails throws from `advanceBy(...)`, where the caller can see it.
142
- The clock is left at the point it failed, and anything still queued stays queued.
143
-
144
- Delivery to a target is the exception, and deliberately so. An EventBridge rule or a Scheduler
145
- schedule that cannot reach its target records the failure instead of throwing. Real AWS reports a
146
- failed delivery to nobody, and one rejected delivery would otherwise fail an unrelated
147
- `advanceBy(...)` elsewhere in the same test. Read the failures from `eventBridge().deliveryFailures`
148
- and `scheduler().deliveryFailures`.
149
-
150
- A Step Functions execution works the same way. A state that fails while the clock is being advanced
151
- is recorded on the execution, and `DescribeExecution` reports it once the advance has returned.
131
+ If scheduled work throws, `advanceBy(...)` throws the same failure. The clock stops at the failed
132
+ task's due time, and later work remains queued.
152
133
 
153
- Several parts of the simulator schedule work on the clock. Advancing time does more than change what
154
- timestamps and expiry checks see. A scheduled EventBridge rule fires, an EventBridge Scheduler
155
- schedule invokes its target, a DynamoDB item passes its time to live, a Secrets Manager deletion
156
- falls due, a Step Functions execution moves on from a `Wait` state, and a Lambda event source
157
- mapping polls again. Each of those runs at its own due instant inside the interval, in the order
158
- they fall due.
134
+ EventBridge and EventBridge Scheduler delivery failures are recorded instead. Read them from
135
+ `eventBridge().deliveryFailures` or `scheduler().deliveryFailures`. Step Functions also records a
136
+ failed state on the execution for `DescribeExecution` to return.
159
137
 
160
- ## Time inside a simulated Lambda handler
138
+ ## Read simulated time in a Lambda handler
161
139
 
162
- A simulated Lambda function runs on its simulation's clock, and that reaches the JavaScript clock
163
- the function code itself reads. `Date.now()` and `new Date()` inside a handler report simulated
164
- time. Code stamping an expiry or building a date-partitioned key can be tested against a clock the
165
- test controls:
140
+ Inside a simulated Lambda invocation, `Date.now()` and `new Date()` read the simulation's clock:
166
141
 
167
142
  ```typescript sim-clock-lambda-handler
168
143
  /**
@@ -203,30 +178,22 @@ const second = await lambda.invoke(
203
178
  console.log(Buffer.from(second.Payload!).toString()); // {"at":"2026-07-26T11:00:00.000Z"}
204
179
  ```
205
180
 
206
- How that is arranged depends on where the function code runs. One of the two touches a process
207
- global:
181
+ Zip code runs in a VM with a `Date` constructor connected to the simulation. An in-process handler
182
+ uses the same simulated time during its invocation. Code outside the invocation continues to read
183
+ the system clock, including code running concurrently in another simulation.
208
184
 
209
- - **Zip code** runs in a vm sandbox owning its own globals, and is handed a `Date` bound to the
210
- simulation's clock. The globals outside the sandbox are left alone.
211
- - **A real in-process handler function** is a closure over the module scope it was written in, and
212
- reads the global `Date` like everything else in the test run. So the global is substituted for one
213
- reporting the invocation's clock while an invocation is running, and the host clock otherwise,
214
- tracked with `AsyncLocalStorage` so concurrent invocations of different simulations stay apart. It
215
- is installed on the first in-process invocation and never removed, and with no invocation running
216
- it behaves exactly as the host's own `Date` does.
185
+ Only calls that ask for the current time are changed. `new Date("2020-03-12")`, `Date.parse(...)`,
186
+ `Date.UTC(...)`, and `instanceof Date` keep their usual behaviour.
217
187
 
218
- Only the current time comes from the clock. `new Date("2020-03-12")`, `Date.parse(...)`,
219
- `Date.UTC(...)` and `instanceof Date` all behave as they always did.
220
-
221
- Under a frozen clock `Date.now()` returns the same number for the whole invocation, and handler code
222
- that waits for it to change never finishes. Call `resume()` before invoking if the code under test
223
- polls the clock.
188
+ The global `setTimeout`, `clearTimeout`, `setInterval`, and `clearInterval` functions also use the
189
+ simulation's clock during an invocation. Start an invocation without awaiting it, advance the
190
+ clock past the timer delay, then await the invocation. Lambda's configured timeout and
191
+ `context.getRemainingTimeInMillis()` use the same clock.
224
192
 
225
193
  ### Where real AWS gets the time
226
194
 
227
- Real Lambda has no current-time API. The context object carries no timestamp, only
228
- `getRemainingTimeInMillis()`, and no environment variable holds one. Handler code reading `new
229
- Date()` is reading the machine clock. AWS does provide the time on the event:
195
+ Real Lambda has no current-time API. A production handler gets the current time from the machine
196
+ clock or from a timestamp in its event:
230
197
 
231
198
  | Event source | Field |
232
199
  | ------------------------- | ------------------------------------------------- |
@@ -236,49 +203,52 @@ Date()` is reading the machine clock. AWS does provide the time on the event:
236
203
  | SNS | `Records[].Sns.Timestamp` |
237
204
  | SQS | `Records[].attributes.SentTimestamp` |
238
205
 
239
- For a scheduled invocation AWS advises reading the event's `time` in preference to the system clock,
240
- because a retry or a delayed delivery runs later than the time the work was for. Simulated Lambda
241
- follows the same rule where it builds events. A Function URL request carries simulated time in
242
- `requestContext.time` and `requestContext.timeEpoch`.
243
-
244
- An SQS event source mapping does the same. The `SentTimestamp` and
245
- `ApproximateFirstReceiveTimestamp` attributes on a delivered record are simulated time, and a
246
- handler reading the event's time reads the clock the test controls. See
247
- [simulated Lambda](https://yulinsim.dev/services/lambda/#triggering-a-function-from-an-sqs-queue "Simulated Lambda event source mapping docs").
206
+ Yulin puts simulated time into the events it builds. Function URL events include
207
+ `requestContext.time` and `requestContext.timeEpoch`. SQS records include simulated
208
+ `SentTimestamp` and `ApproximateFirstReceiveTimestamp` values. The
209
+ [Lambda documentation](https://yulinsim.dev/services/lambda/#triggering-a-function-from-an-sqs-queue "Simulated Lambda event source mapping docs")
210
+ describes the event source mapping behaviour.
248
211
 
249
- Handler code that takes a clock as a dependency stays the most testable option, on real AWS and
250
- here, and needs none of the machinery above.
212
+ A handler can also accept a clock as a dependency. That approach works without Lambda-specific
213
+ clock handling.
251
214
 
252
215
  ## Time over HTTP
253
216
 
254
- A simulation served over HTTP, through `serveSimAws` or `SimAwsHttp.fetch(...)`, stamps every
255
- response with simulated time in its `Date` header, as real AWS stamps every API response with server
256
- time. Advancing the clock changes what that header reports. A client talking to the simulation sees
257
- the same "now" the simulation does, with no need to know it is talking to a simulator.
217
+ A simulation served through `serveSimAws` or `SimAwsHttp.fetch(...)` uses simulated time in each
218
+ response's `Date` header. Advancing the clock changes the header on later responses.
258
219
 
259
220
  ## Time and SDK interception
260
221
 
261
- A `SimSdk` owns a simulated AWS environment, available as `simSdk.simAws`. Intercepted SDK code runs
262
- on a clock a test can control with `await simSdk.simAws.clock().advanceBy({ hours: 1 })`.
222
+ A `SimSdk` exposes its simulation as `simSdk.simAws`. Advance its clock with
223
+ `await simSdk.simAws.clock().advanceBy({ hours: 1 })`.
224
+
225
+ ## Uses of simulated time
226
+
227
+ Yulin uses the clock for:
228
+
229
+ - Resource timestamps and expiry checks
230
+ - EventBridge rules and EventBridge Scheduler schedules
231
+ - DynamoDB time to live and scheduled Secrets Manager deletion
232
+ - Step Functions `Wait` states
233
+ - Lambda event source polling and event timestamps
234
+ - `Date`, global timers, and invocation deadlines inside a simulated Lambda invocation
235
+ - HTTP response `Date` headers
263
236
 
264
237
  ## Limitations
265
238
 
266
- - Advancing the clock is the only thing that fires a scheduled
267
- [EventBridge rule](https://yulinsim.dev/services/eventbridge/#rules-that-fire-on-a-schedule). Nothing runs on the
268
- host's clock. A simulation left alone in real time fires nothing however long it is left.
269
- - Advancing the clock is also the only thing that fires an
270
- [EventBridge Scheduler schedule](https://yulinsim.dev/services/scheduler/#firing-a-schedule), including a one-time
271
- `at(...)` one.
272
- - Only `SimAws` exposes time control. Services constructed standalone, such as `new SimS3()`, get
273
- their own real clock and no way to move it.
274
- - A `SimAws` constructed with a `background` scheduler of its own cannot control time, because that
275
- scheduler brings its own clock. `simAws.clock()` throws a diagnostic error saying so.
276
- - Simulated time reaches JavaScript's own clock inside a simulated Lambda invocation, and nowhere
277
- else. `Date.now()` and `new Date()` in code under test that is not running as a simulated Lambda
278
- function still report real time.
279
- - Timers are not simulated. `setTimeout` inside a handler is a host timer. A sleeping handler waits
280
- in real time, and advancing the clock leaves it asleep.
281
- - A time already read cannot be reached. A handler module doing `const startedAt = Date.now()` at
282
- module scope read it when the test file imported the module, long before any invocation.
283
- - Advancing time does not re-evaluate simulated state that was already computed, such as an ACM
284
- certificate that has finished validating. It changes what is read from the clock next.
239
+ - Scheduled [EventBridge rules](https://yulinsim.dev/services/eventbridge/#rules-that-fire-on-a-schedule)
240
+ and [EventBridge Scheduler schedules](https://yulinsim.dev/services/scheduler/#firing-a-schedule)
241
+ run when `advanceBy(...)` or a forward `setTo(...)` reaches their due time. Elapsed system time
242
+ does not run them.
243
+ - Time control is available through `SimAws`. A standalone service such as `new SimS3()` uses the
244
+ system clock and has no clock controls.
245
+ - A `SimAws` created with a custom `background` scheduler cannot control time because the scheduler
246
+ owns its clock. Calling `simAws.clock()` throws `SimAwsTimeNotControllable`.
247
+ - JavaScript's `Date` and global timer functions use simulated time only during a simulated Lambda
248
+ invocation. Other application code continues to use system time.
249
+ - Lambda code imported from `node:timers` or `node:timers/promises` uses system time. The same is
250
+ true of `util.promisify(setTimeout)`.
251
+ - A module-level `Date.now()` runs when the module is imported, before the Lambda invocation begins.
252
+ It reads system time.
253
+ - Moving the clock does not recalculate state that has already been computed. For example, it does
254
+ not restart validation for an ACM certificate that is already issued.
package/llms.txt CHANGED
@@ -47,7 +47,7 @@ The same pages are on the web at https://yulinsim.dev/ for whichever release is
47
47
  - [STS](docs/services/sts/README.md): Simulated STS usage docs
48
48
  - [WAFv2](docs/services/wafv2/README.md): Simulated WAFv2 usage docs
49
49
 
50
- ## Feature documentation
50
+ ## Feature guides
51
51
 
52
52
  - [AI skill](docs/ai-skill/README.md): Yulin AI skill usage docs
53
53
  - [The AWS CLI](docs/cli/README.md): The AWS CLI against simulated AWS usage docs
@@ -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.6",
3
+ "version": "1.21.8",
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/",