@bluelibs/runner 3.4.2 → 4.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/AI.md +621 -0
- package/README.md +1024 -577
- package/dist/context.d.ts +4 -8
- package/dist/context.js +5 -12
- package/dist/context.js.map +1 -1
- package/dist/define.d.ts +9 -113
- package/dist/define.js +29 -358
- package/dist/define.js.map +1 -1
- package/dist/definers/defineEvent.d.ts +2 -0
- package/dist/definers/defineEvent.js +23 -0
- package/dist/definers/defineEvent.js.map +1 -0
- package/dist/definers/defineHook.d.ts +6 -0
- package/dist/definers/defineHook.js +24 -0
- package/dist/definers/defineHook.js.map +1 -0
- package/dist/definers/defineOverride.d.ts +14 -0
- package/dist/definers/defineOverride.js +13 -0
- package/dist/definers/defineOverride.js.map +1 -0
- package/dist/definers/defineResource.d.ts +2 -0
- package/dist/definers/defineResource.js +69 -0
- package/dist/definers/defineResource.js.map +1 -0
- package/dist/definers/defineResourceMiddleware.d.ts +2 -0
- package/dist/definers/defineResourceMiddleware.js +42 -0
- package/dist/definers/defineResourceMiddleware.js.map +1 -0
- package/dist/definers/defineTag.d.ts +12 -0
- package/dist/definers/defineTag.js +106 -0
- package/dist/definers/defineTag.js.map +1 -0
- package/dist/definers/defineTask.d.ts +15 -0
- package/dist/definers/defineTask.js +42 -0
- package/dist/definers/defineTask.js.map +1 -0
- package/dist/definers/defineTaskMiddleware.d.ts +2 -0
- package/dist/definers/defineTaskMiddleware.js +42 -0
- package/dist/definers/defineTaskMiddleware.js.map +1 -0
- package/dist/definers/tools.d.ts +45 -0
- package/dist/definers/tools.js +75 -0
- package/dist/definers/tools.js.map +1 -0
- package/dist/defs.d.ts +16 -424
- package/dist/defs.js +26 -38
- package/dist/defs.js.map +1 -1
- package/dist/errors.d.ts +23 -8
- package/dist/errors.js +50 -10
- package/dist/errors.js.map +1 -1
- package/dist/globals/globalEvents.d.ts +15 -39
- package/dist/globals/globalEvents.js +20 -81
- package/dist/globals/globalEvents.js.map +1 -1
- package/dist/globals/globalMiddleware.d.ts +24 -17
- package/dist/globals/globalMiddleware.js +12 -4
- package/dist/globals/globalMiddleware.js.map +1 -1
- package/dist/globals/globalResources.d.ts +13 -28
- package/dist/globals/globalResources.js +15 -7
- package/dist/globals/globalResources.js.map +1 -1
- package/dist/globals/globalTags.d.ts +9 -0
- package/dist/globals/globalTags.js +23 -0
- package/dist/globals/globalTags.js.map +1 -0
- package/dist/globals/middleware/cache.middleware.d.ts +10 -17
- package/dist/globals/middleware/cache.middleware.js +4 -16
- package/dist/globals/middleware/cache.middleware.js.map +1 -1
- package/dist/globals/middleware/requireContext.middleware.d.ts +1 -1
- package/dist/globals/middleware/requireContext.middleware.js +5 -14
- package/dist/globals/middleware/requireContext.middleware.js.map +1 -1
- package/dist/globals/middleware/retry.middleware.d.ts +2 -1
- package/dist/globals/middleware/retry.middleware.js +32 -5
- package/dist/globals/middleware/retry.middleware.js.map +1 -1
- package/dist/globals/middleware/timeout.middleware.d.ts +2 -1
- package/dist/globals/middleware/timeout.middleware.js +31 -5
- package/dist/globals/middleware/timeout.middleware.js.map +1 -1
- package/dist/globals/resources/debug/debug.resource.d.ts +7 -0
- package/dist/globals/resources/debug/debug.resource.js +29 -0
- package/dist/globals/resources/debug/debug.resource.js.map +1 -0
- package/dist/globals/resources/debug/debug.tag.d.ts +2 -0
- package/dist/globals/resources/debug/debug.tag.js +12 -0
- package/dist/globals/resources/debug/debug.tag.js.map +1 -0
- package/dist/globals/resources/debug/debugConfig.resource.d.ts +22 -0
- package/dist/globals/resources/debug/debugConfig.resource.js +20 -0
- package/dist/globals/resources/debug/debugConfig.resource.js.map +1 -0
- package/dist/globals/resources/debug/executionTracker.middleware.d.ts +50 -0
- package/dist/globals/resources/debug/executionTracker.middleware.js +87 -0
- package/dist/globals/resources/debug/executionTracker.middleware.js.map +1 -0
- package/dist/globals/resources/debug/globalEvent.hook.d.ts +27 -0
- package/dist/globals/resources/debug/globalEvent.hook.js +38 -0
- package/dist/globals/resources/debug/globalEvent.hook.js.map +1 -0
- package/dist/globals/resources/debug/hook.hook.d.ts +25 -0
- package/dist/globals/resources/debug/hook.hook.js +42 -0
- package/dist/globals/resources/debug/hook.hook.js.map +1 -0
- package/dist/globals/resources/debug/index.d.ts +6 -0
- package/dist/{types → globals/resources/debug}/index.js +6 -11
- package/dist/globals/resources/debug/index.js.map +1 -0
- package/dist/globals/resources/debug/middleware.hook.d.ts +25 -0
- package/dist/globals/resources/debug/middleware.hook.js +71 -0
- package/dist/globals/resources/debug/middleware.hook.js.map +1 -0
- package/dist/globals/resources/debug/types.d.ts +25 -0
- package/dist/globals/resources/debug/types.js +65 -0
- package/dist/globals/resources/debug/types.js.map +1 -0
- package/dist/globals/resources/debug/utils.d.ts +2 -0
- package/dist/globals/resources/debug/utils.js +9 -0
- package/dist/globals/resources/debug/utils.js.map +1 -0
- package/dist/globals/resources/queue.resource.d.ts +3 -3
- package/dist/globals/resources/queue.resource.js.map +1 -1
- package/dist/globals/types.d.ts +1 -0
- package/dist/{task.types.js → globals/types.js} +2 -7
- package/dist/globals/types.js.map +1 -0
- package/dist/index.d.ts +58 -85
- package/dist/index.js +23 -10
- package/dist/index.js.map +1 -1
- package/dist/models/DependencyProcessor.d.ts +8 -6
- package/dist/models/DependencyProcessor.js +116 -33
- package/dist/models/DependencyProcessor.js.map +1 -1
- package/dist/models/EventManager.d.ts +127 -7
- package/dist/models/EventManager.js +251 -78
- package/dist/models/EventManager.js.map +1 -1
- package/dist/models/LogPrinter.d.ts +55 -0
- package/dist/models/LogPrinter.js +196 -0
- package/dist/models/LogPrinter.js.map +1 -0
- package/dist/models/Logger.d.ts +47 -27
- package/dist/models/Logger.js +133 -155
- package/dist/models/Logger.js.map +1 -1
- package/dist/models/MiddlewareManager.d.ts +86 -0
- package/dist/models/MiddlewareManager.js +409 -0
- package/dist/models/MiddlewareManager.js.map +1 -0
- package/dist/models/OverrideManager.d.ts +3 -3
- package/dist/models/OverrideManager.js +22 -7
- package/dist/models/OverrideManager.js.map +1 -1
- package/dist/models/ResourceInitializer.d.ts +4 -3
- package/dist/models/ResourceInitializer.js +12 -68
- package/dist/models/ResourceInitializer.js.map +1 -1
- package/dist/models/RunResult.d.ts +35 -0
- package/dist/models/RunResult.js +68 -0
- package/dist/models/RunResult.js.map +1 -0
- package/dist/models/Store.d.ts +30 -17
- package/dist/models/Store.js +87 -25
- package/dist/models/Store.js.map +1 -1
- package/dist/models/StoreRegistry.d.ts +34 -19
- package/dist/models/StoreRegistry.js +248 -100
- package/dist/models/StoreRegistry.js.map +1 -1
- package/dist/models/StoreValidator.d.ts +5 -7
- package/dist/models/StoreValidator.js +50 -17
- package/dist/models/StoreValidator.js.map +1 -1
- package/dist/models/TaskRunner.d.ts +3 -2
- package/dist/models/TaskRunner.js +6 -103
- package/dist/models/TaskRunner.js.map +1 -1
- package/dist/models/UnhandledError.d.ts +11 -0
- package/dist/models/UnhandledError.js +30 -0
- package/dist/models/UnhandledError.js.map +1 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.js +3 -0
- package/dist/models/index.js.map +1 -1
- package/dist/{tools → models/utils}/findCircularDependencies.js +8 -16
- package/dist/models/utils/findCircularDependencies.js.map +1 -0
- package/dist/models/utils/safeStringify.d.ts +3 -0
- package/dist/models/utils/safeStringify.js +45 -0
- package/dist/models/utils/safeStringify.js.map +1 -0
- package/dist/processHooks.d.ts +2 -0
- package/dist/processHooks.js +70 -0
- package/dist/processHooks.js.map +1 -0
- package/dist/run.d.ts +14 -27
- package/dist/run.js +100 -36
- package/dist/run.js.map +1 -1
- package/dist/testing.d.ts +5 -4
- package/dist/testing.js +3 -2
- package/dist/testing.js.map +1 -1
- package/dist/tools/getCallerFile.d.ts +0 -8
- package/dist/tools/getCallerFile.js +0 -51
- package/dist/tools/getCallerFile.js.map +1 -1
- package/dist/types/contracts.d.ts +55 -0
- package/dist/types/contracts.js +4 -0
- package/dist/types/contracts.js.map +1 -0
- package/dist/types/event.d.ts +26 -7
- package/dist/types/event.js +1 -1
- package/dist/types/event.js.map +1 -1
- package/dist/types/hook.d.ts +21 -0
- package/dist/{models/StoreTypes.js → types/hook.js} +2 -1
- package/dist/types/hook.js.map +1 -0
- package/dist/types/meta.d.ts +6 -1
- package/dist/types/meta.js +4 -2
- package/dist/types/meta.js.map +1 -1
- package/dist/types/resource.d.ts +40 -52
- package/dist/types/resource.js +1 -0
- package/dist/types/resource.js.map +1 -1
- package/dist/types/resourceMiddleware.d.ts +47 -0
- package/dist/{middleware.types.js → types/resourceMiddleware.js} +1 -1
- package/dist/types/resourceMiddleware.js.map +1 -0
- package/dist/types/runner.d.ts +37 -0
- package/dist/types/{base.js → runner.js} +1 -1
- package/dist/types/runner.js.map +1 -0
- package/dist/types/storeTypes.d.ts +40 -0
- package/dist/types/{metadata.js → storeTypes.js} +1 -1
- package/dist/types/storeTypes.js.map +1 -0
- package/dist/types/symbols.d.ts +10 -21
- package/dist/types/symbols.js +17 -22
- package/dist/types/symbols.js.map +1 -1
- package/dist/types/tag.d.ts +46 -0
- package/dist/{resource.types.js → types/tag.js} +2 -1
- package/dist/types/tag.js.map +1 -0
- package/dist/types/task.d.ts +28 -52
- package/dist/types/task.js +1 -0
- package/dist/types/task.js.map +1 -1
- package/dist/types/taskMiddleware.d.ts +48 -0
- package/dist/{event.types.js → types/taskMiddleware.js} +1 -1
- package/dist/types/taskMiddleware.js.map +1 -0
- package/dist/types/utilities.d.ts +105 -6
- package/dist/types/utilities.js +16 -2
- package/dist/types/utilities.js.map +1 -1
- package/package.json +14 -5
- package/dist/cli/extract-docs.d.ts +0 -2
- package/dist/cli/extract-docs.js +0 -88
- package/dist/cli/extract-docs.js.map +0 -1
- package/dist/common.types.d.ts +0 -20
- package/dist/common.types.js +0 -4
- package/dist/common.types.js.map +0 -1
- package/dist/defs/core.d.ts +0 -144
- package/dist/defs/core.js +0 -6
- package/dist/defs/core.js.map +0 -1
- package/dist/defs/symbols.d.ts +0 -42
- package/dist/defs/symbols.js +0 -45
- package/dist/defs/symbols.js.map +0 -1
- package/dist/defs/tags.d.ts +0 -70
- package/dist/defs/tags.js +0 -6
- package/dist/defs/tags.js.map +0 -1
- package/dist/defs.returnTag.d.ts +0 -36
- package/dist/defs.returnTag.js +0 -4
- package/dist/defs.returnTag.js.map +0 -1
- package/dist/docs/introspect.d.ts +0 -7
- package/dist/docs/introspect.js +0 -199
- package/dist/docs/introspect.js.map +0 -1
- package/dist/docs/markdown.d.ts +0 -2
- package/dist/docs/markdown.js +0 -148
- package/dist/docs/markdown.js.map +0 -1
- package/dist/docs/model.d.ts +0 -62
- package/dist/docs/model.js +0 -33
- package/dist/docs/model.js.map +0 -1
- package/dist/event.types.d.ts +0 -18
- package/dist/event.types.js.map +0 -1
- package/dist/examples/express-mongo/index.d.ts +0 -0
- package/dist/examples/express-mongo/index.js +0 -3
- package/dist/examples/express-mongo/index.js.map +0 -1
- package/dist/examples/registrator-example.d.ts +0 -122
- package/dist/examples/registrator-example.js +0 -147
- package/dist/examples/registrator-example.js.map +0 -1
- package/dist/express/docsRouter.d.ts +0 -12
- package/dist/express/docsRouter.js +0 -54
- package/dist/express/docsRouter.js.map +0 -1
- package/dist/globalEvents.d.ts +0 -40
- package/dist/globalEvents.js +0 -94
- package/dist/globalEvents.js.map +0 -1
- package/dist/globalResources.d.ts +0 -10
- package/dist/globalResources.js +0 -43
- package/dist/globalResources.js.map +0 -1
- package/dist/middleware.types.d.ts +0 -40
- package/dist/middleware.types.js.map +0 -1
- package/dist/models/StoreConstants.d.ts +0 -14
- package/dist/models/StoreConstants.js +0 -19
- package/dist/models/StoreConstants.js.map +0 -1
- package/dist/models/StoreTypes.d.ts +0 -21
- package/dist/models/StoreTypes.js.map +0 -1
- package/dist/models/VarStore.d.ts +0 -17
- package/dist/models/VarStore.js +0 -60
- package/dist/models/VarStore.js.map +0 -1
- package/dist/resource.types.d.ts +0 -31
- package/dist/resource.types.js.map +0 -1
- package/dist/symbols.d.ts +0 -24
- package/dist/symbols.js +0 -29
- package/dist/symbols.js.map +0 -1
- package/dist/t1.d.ts +0 -1
- package/dist/t1.js +0 -13
- package/dist/t1.js.map +0 -1
- package/dist/task.types.d.ts +0 -55
- package/dist/task.types.js.map +0 -1
- package/dist/tools/findCircularDependencies.js.map +0 -1
- package/dist/tools/registratorId.d.ts +0 -4
- package/dist/tools/registratorId.js +0 -40
- package/dist/tools/registratorId.js.map +0 -1
- package/dist/tools/simpleHash.d.ts +0 -9
- package/dist/tools/simpleHash.js +0 -34
- package/dist/tools/simpleHash.js.map +0 -1
- package/dist/types/base-interfaces.d.ts +0 -18
- package/dist/types/base-interfaces.js +0 -6
- package/dist/types/base-interfaces.js.map +0 -1
- package/dist/types/base.d.ts +0 -13
- package/dist/types/base.js.map +0 -1
- package/dist/types/dependencies.d.ts +0 -51
- package/dist/types/dependencies.js +0 -3
- package/dist/types/dependencies.js.map +0 -1
- package/dist/types/dependency-core.d.ts +0 -14
- package/dist/types/dependency-core.js +0 -5
- package/dist/types/dependency-core.js.map +0 -1
- package/dist/types/events.d.ts +0 -52
- package/dist/types/events.js +0 -6
- package/dist/types/events.js.map +0 -1
- package/dist/types/hooks.d.ts +0 -16
- package/dist/types/hooks.js +0 -5
- package/dist/types/hooks.js.map +0 -1
- package/dist/types/index.d.ts +0 -8
- package/dist/types/index.js.map +0 -1
- package/dist/types/metadata.d.ts +0 -75
- package/dist/types/metadata.js.map +0 -1
- package/dist/types/middleware.d.ts +0 -63
- package/dist/types/middleware.js +0 -3
- package/dist/types/middleware.js.map +0 -1
- package/dist/types/registerable.d.ts +0 -10
- package/dist/types/registerable.js +0 -5
- package/dist/types/registerable.js.map +0 -1
- package/dist/types/resources.d.ts +0 -44
- package/dist/types/resources.js +0 -5
- package/dist/types/resources.js.map +0 -1
- package/dist/types/tasks.d.ts +0 -41
- package/dist/types/tasks.js +0 -5
- package/dist/types/tasks.js.map +0 -1
- package/src/__tests__/benchmark/benchmark.test.ts +0 -148
- package/src/__tests__/benchmark/task-benchmark.test.ts +0 -132
- package/src/__tests__/context.test.ts +0 -91
- package/src/__tests__/createTestResource.test.ts +0 -139
- package/src/__tests__/errors.test.ts +0 -341
- package/src/__tests__/globalEvents.test.ts +0 -542
- package/src/__tests__/globals/cache.middleware.test.ts +0 -772
- package/src/__tests__/globals/queue.resource.test.ts +0 -141
- package/src/__tests__/globals/requireContext.middleware.test.ts +0 -98
- package/src/__tests__/globals/retry.middleware.test.ts +0 -157
- package/src/__tests__/globals/timeout.middleware.test.ts +0 -88
- package/src/__tests__/index.helper.test.ts +0 -55
- package/src/__tests__/models/EventManager.test.ts +0 -585
- package/src/__tests__/models/Logger.test.ts +0 -519
- package/src/__tests__/models/Queue.test.ts +0 -189
- package/src/__tests__/models/ResourceInitializer.test.ts +0 -148
- package/src/__tests__/models/Semaphore.test.ts +0 -713
- package/src/__tests__/models/Store.test.ts +0 -227
- package/src/__tests__/models/TaskRunner.test.ts +0 -221
- package/src/__tests__/override.test.ts +0 -104
- package/src/__tests__/recursion/README.md +0 -3
- package/src/__tests__/recursion/a.resource.ts +0 -25
- package/src/__tests__/recursion/b.resource.ts +0 -33
- package/src/__tests__/recursion/c.resource.ts +0 -18
- package/src/__tests__/run.anonymous.test.ts +0 -706
- package/src/__tests__/run.dynamic-register-and-dependencies.test.ts +0 -1185
- package/src/__tests__/run.middleware.test.ts +0 -549
- package/src/__tests__/run.overrides.test.ts +0 -424
- package/src/__tests__/run.test.ts +0 -1040
- package/src/__tests__/setOutput.test.ts +0 -244
- package/src/__tests__/tags.test.ts +0 -396
- package/src/__tests__/tools/findCircularDependencies.test.ts +0 -217
- package/src/__tests__/tools/getCallerFile.test.ts +0 -179
- package/src/__tests__/typesafety.test.ts +0 -423
- package/src/__tests__/validation-edge-cases.test.ts +0 -111
- package/src/__tests__/validation-interface.test.ts +0 -428
- package/src/context.ts +0 -86
- package/src/define.ts +0 -480
- package/src/defs.returnTag.ts +0 -91
- package/src/defs.ts +0 -596
- package/src/errors.ts +0 -105
- package/src/globals/globalEvents.ts +0 -125
- package/src/globals/globalMiddleware.ts +0 -16
- package/src/globals/globalResources.ts +0 -53
- package/src/globals/middleware/cache.middleware.ts +0 -115
- package/src/globals/middleware/requireContext.middleware.ts +0 -36
- package/src/globals/middleware/retry.middleware.ts +0 -56
- package/src/globals/middleware/timeout.middleware.ts +0 -46
- package/src/globals/resources/queue.resource.ts +0 -34
- package/src/index.ts +0 -39
- package/src/models/DependencyProcessor.ts +0 -257
- package/src/models/EventManager.ts +0 -210
- package/src/models/Logger.ts +0 -282
- package/src/models/OverrideManager.ts +0 -79
- package/src/models/Queue.ts +0 -66
- package/src/models/ResourceInitializer.ts +0 -165
- package/src/models/Semaphore.ts +0 -208
- package/src/models/Store.ts +0 -193
- package/src/models/StoreConstants.ts +0 -18
- package/src/models/StoreRegistry.ts +0 -253
- package/src/models/StoreTypes.ts +0 -47
- package/src/models/StoreValidator.ts +0 -43
- package/src/models/TaskRunner.ts +0 -203
- package/src/models/index.ts +0 -8
- package/src/run.ts +0 -116
- package/src/testing.ts +0 -66
- package/src/tools/findCircularDependencies.ts +0 -69
- package/src/tools/getCallerFile.ts +0 -96
- /package/dist/{tools → models/utils}/findCircularDependencies.d.ts +0 -0
|
@@ -1,519 +0,0 @@
|
|
|
1
|
-
import { Logger, ILog, LogLevels } from "../../models/Logger";
|
|
2
|
-
import { EventManager } from "../../models/EventManager";
|
|
3
|
-
import { globalEvents } from "../../globals/globalEvents";
|
|
4
|
-
|
|
5
|
-
describe("Logger", () => {
|
|
6
|
-
let logger: Logger;
|
|
7
|
-
let mockEventManager: jest.Mocked<EventManager>;
|
|
8
|
-
let originalEnv: any;
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
// Save original environment
|
|
12
|
-
originalEnv = { ...process.env };
|
|
13
|
-
|
|
14
|
-
// Clear environment variables that might affect tests
|
|
15
|
-
delete process.env.RUNNER_DISABLE_LOGS;
|
|
16
|
-
delete process.env.RUNNER_LOG_LEVEL;
|
|
17
|
-
|
|
18
|
-
mockEventManager = new EventManager() as jest.Mocked<EventManager>;
|
|
19
|
-
logger = new Logger(mockEventManager);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
// Restore original environment
|
|
24
|
-
process.env = originalEnv;
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe("log method", () => {
|
|
28
|
-
it("should emit a log event with correct data", async () => {
|
|
29
|
-
const testData = "Test log message";
|
|
30
|
-
const testLevel = "info";
|
|
31
|
-
mockEventManager.emit = jest.fn().mockResolvedValue(undefined);
|
|
32
|
-
mockEventManager.hasListeners = jest.fn().mockReturnValue(true);
|
|
33
|
-
|
|
34
|
-
logger.log(testLevel, testData);
|
|
35
|
-
|
|
36
|
-
// Wait for setImmediate to execute
|
|
37
|
-
await new Promise(setImmediate);
|
|
38
|
-
|
|
39
|
-
expect(mockEventManager.emit).toHaveBeenCalledWith(
|
|
40
|
-
globalEvents.log,
|
|
41
|
-
expect.objectContaining({
|
|
42
|
-
level: testLevel,
|
|
43
|
-
message: testData,
|
|
44
|
-
timestamp: expect.any(Date),
|
|
45
|
-
}),
|
|
46
|
-
"unknown"
|
|
47
|
-
);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("should handle different log levels", async () => {
|
|
51
|
-
const levels: Array<LogLevels> = [
|
|
52
|
-
"trace",
|
|
53
|
-
"debug",
|
|
54
|
-
"info",
|
|
55
|
-
"warn",
|
|
56
|
-
"error",
|
|
57
|
-
"critical",
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
mockEventManager.emit = jest.fn().mockResolvedValue(undefined);
|
|
61
|
-
mockEventManager.hasListeners = jest.fn().mockReturnValue(true);
|
|
62
|
-
|
|
63
|
-
for (const level of levels) {
|
|
64
|
-
logger.log(level, `Test ${level} message`, { source: "testSource" });
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Wait for setImmediate to execute
|
|
68
|
-
await new Promise(setImmediate);
|
|
69
|
-
|
|
70
|
-
// Check all calls were made
|
|
71
|
-
expect(mockEventManager.emit).toHaveBeenCalledTimes(levels.length);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it("should not emit events when there are no listeners", () => {
|
|
75
|
-
mockEventManager.emit = jest.fn().mockResolvedValue(undefined);
|
|
76
|
-
mockEventManager.hasListeners = jest.fn().mockReturnValue(false);
|
|
77
|
-
|
|
78
|
-
logger.log("info", "Test message");
|
|
79
|
-
|
|
80
|
-
// Should not emit events when no listeners
|
|
81
|
-
expect(mockEventManager.emit).not.toHaveBeenCalled();
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe("print method", () => {
|
|
86
|
-
let consoleLogSpy: jest.SpyInstance;
|
|
87
|
-
|
|
88
|
-
beforeEach(() => {
|
|
89
|
-
consoleLogSpy = jest.spyOn(console, "log").mockImplementation();
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
afterEach(() => {
|
|
93
|
-
consoleLogSpy.mockRestore();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it("should print log messages correctly", async () => {
|
|
97
|
-
const testLog: ILog = {
|
|
98
|
-
level: "info",
|
|
99
|
-
source: "test",
|
|
100
|
-
message: "Test log message",
|
|
101
|
-
timestamp: new Date("2023-01-01T00:00:00Z"),
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
await logger.print(testLog);
|
|
105
|
-
|
|
106
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
107
|
-
expect.stringContaining("INFO")
|
|
108
|
-
);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it("should handle Error objects in log data", () => {
|
|
112
|
-
const testError = new Error("Test error");
|
|
113
|
-
const testLog: ILog = {
|
|
114
|
-
level: "error",
|
|
115
|
-
message: "Operation failed",
|
|
116
|
-
error: {
|
|
117
|
-
name: testError.name,
|
|
118
|
-
message: testError.message,
|
|
119
|
-
stack: testError.stack,
|
|
120
|
-
},
|
|
121
|
-
timestamp: new Date("2023-01-01T00:00:00Z"),
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
logger.print(testLog);
|
|
125
|
-
|
|
126
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
127
|
-
expect.stringContaining("ERROR")
|
|
128
|
-
);
|
|
129
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
130
|
-
expect.stringContaining("Error: Error")
|
|
131
|
-
);
|
|
132
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
133
|
-
expect.stringContaining("Test error")
|
|
134
|
-
);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it("should handle error objects without stack trace", () => {
|
|
138
|
-
const testLog: ILog = {
|
|
139
|
-
level: "error",
|
|
140
|
-
message: "Operation failed",
|
|
141
|
-
error: {
|
|
142
|
-
name: "CustomError",
|
|
143
|
-
message: "Something went wrong",
|
|
144
|
-
},
|
|
145
|
-
timestamp: new Date("2023-01-01T00:00:00Z"),
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
logger.print(testLog);
|
|
149
|
-
|
|
150
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
151
|
-
expect.stringContaining("ERROR")
|
|
152
|
-
);
|
|
153
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
154
|
-
expect.stringContaining("Error: CustomError")
|
|
155
|
-
);
|
|
156
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
157
|
-
expect.stringContaining("Something went wrong")
|
|
158
|
-
);
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it("should pretty-print structured data", () => {
|
|
162
|
-
const testObject = { key: "value", nested: { foo: "bar" } };
|
|
163
|
-
const testLog: ILog = {
|
|
164
|
-
level: "debug",
|
|
165
|
-
message: "Debug info",
|
|
166
|
-
data: testObject,
|
|
167
|
-
timestamp: new Date("2023-01-01T00:00:00Z"),
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
logger.print(testLog);
|
|
171
|
-
|
|
172
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
173
|
-
expect.stringContaining("DEBUG")
|
|
174
|
-
);
|
|
175
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
176
|
-
expect.stringContaining('"key": "value"')
|
|
177
|
-
);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it("should handle object message by stringifying it", () => {
|
|
181
|
-
const objectMessage = { type: "user", action: "login" };
|
|
182
|
-
const testLog: ILog = {
|
|
183
|
-
level: "info",
|
|
184
|
-
message: objectMessage as any,
|
|
185
|
-
timestamp: new Date("2023-01-01T00:00:00Z"),
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
logger.print(testLog);
|
|
189
|
-
|
|
190
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
191
|
-
expect.stringContaining("INFO")
|
|
192
|
-
);
|
|
193
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
194
|
-
expect.stringContaining(JSON.stringify(objectMessage, null, 2))
|
|
195
|
-
);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it("should print context information when present", () => {
|
|
199
|
-
const context = { userId: "123", requestId: "abc-def" };
|
|
200
|
-
const testLog: ILog = {
|
|
201
|
-
level: "warn",
|
|
202
|
-
message: "Warning message",
|
|
203
|
-
data: context,
|
|
204
|
-
timestamp: new Date("2023-01-01T00:00:00Z"),
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
logger.print(testLog);
|
|
208
|
-
|
|
209
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
210
|
-
expect.stringContaining("WARN")
|
|
211
|
-
);
|
|
212
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
213
|
-
expect.stringContaining('"userId": "123"')
|
|
214
|
-
);
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it("should print context from context field", () => {
|
|
218
|
-
const context = { userId: "456", feature: "login", source: "auth" };
|
|
219
|
-
const testLog: ILog = {
|
|
220
|
-
level: "info",
|
|
221
|
-
message: "User action",
|
|
222
|
-
context: context,
|
|
223
|
-
timestamp: new Date("2023-01-01T00:00:00Z"),
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
logger.print(testLog);
|
|
227
|
-
|
|
228
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
229
|
-
expect.stringContaining("INFO")
|
|
230
|
-
);
|
|
231
|
-
// Should show context but filter out 'source' since it's shown separately
|
|
232
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
233
|
-
expect.stringContaining("Context:")
|
|
234
|
-
);
|
|
235
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
236
|
-
expect.stringContaining('"userId": "456"')
|
|
237
|
-
);
|
|
238
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
239
|
-
expect.stringContaining('"feature": "login"')
|
|
240
|
-
);
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
it("should handle empty context gracefully", () => {
|
|
244
|
-
const testLog: ILog = {
|
|
245
|
-
level: "debug",
|
|
246
|
-
message: "Debug message",
|
|
247
|
-
context: {},
|
|
248
|
-
timestamp: new Date("2023-01-01T00:00:00Z"),
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
logger.print(testLog);
|
|
252
|
-
|
|
253
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
254
|
-
expect.stringContaining("DEBUG")
|
|
255
|
-
);
|
|
256
|
-
// Should not print context section for empty context
|
|
257
|
-
expect(consoleLogSpy).not.toHaveBeenCalledWith(
|
|
258
|
-
expect.stringContaining("Context:")
|
|
259
|
-
);
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it("should handle unknown log levels gracefully", () => {
|
|
263
|
-
const testLog: ILog = {
|
|
264
|
-
level: "unknown" as any,
|
|
265
|
-
message: "Unknown level message",
|
|
266
|
-
timestamp: new Date("2023-01-01T00:00:00Z"),
|
|
267
|
-
};
|
|
268
|
-
|
|
269
|
-
logger.print(testLog);
|
|
270
|
-
|
|
271
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
272
|
-
expect.stringContaining("UNKNOWN")
|
|
273
|
-
);
|
|
274
|
-
});
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
describe("log level methods", () => {
|
|
278
|
-
const testLevels: Array<LogLevels> = [
|
|
279
|
-
"trace",
|
|
280
|
-
"debug",
|
|
281
|
-
"info",
|
|
282
|
-
"warn",
|
|
283
|
-
"error",
|
|
284
|
-
"critical",
|
|
285
|
-
];
|
|
286
|
-
|
|
287
|
-
for (const level of testLevels) {
|
|
288
|
-
it(`should call log method with ${level} level`, () => {
|
|
289
|
-
const logSpy = jest.spyOn(logger, "log").mockImplementation();
|
|
290
|
-
|
|
291
|
-
logger[level]("Test log message");
|
|
292
|
-
|
|
293
|
-
expect(logSpy).toHaveBeenCalledWith(
|
|
294
|
-
level,
|
|
295
|
-
"Test log message",
|
|
296
|
-
{} // the LogInfo parameter
|
|
297
|
-
);
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
describe("with method", () => {
|
|
303
|
-
it("should create a new logger with additional context", () => {
|
|
304
|
-
const initialContext = { source: "initial" };
|
|
305
|
-
const loggerWithContext = new Logger(mockEventManager, initialContext);
|
|
306
|
-
|
|
307
|
-
const additionalContext = { userId: "123", feature: "auth" };
|
|
308
|
-
const newLogger = loggerWithContext.with(additionalContext);
|
|
309
|
-
|
|
310
|
-
expect(newLogger).toBeInstanceOf(Logger);
|
|
311
|
-
expect(newLogger).not.toBe(loggerWithContext);
|
|
312
|
-
|
|
313
|
-
// Test that the context is merged by checking the log call
|
|
314
|
-
const logSpy = jest.spyOn(newLogger, "log").mockImplementation();
|
|
315
|
-
newLogger.info("test message");
|
|
316
|
-
|
|
317
|
-
expect(logSpy).toHaveBeenCalledWith("info", "test message", {});
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
it("should override context values when keys overlap", () => {
|
|
321
|
-
const initialContext = { source: "initial", common: "old" };
|
|
322
|
-
const loggerWithContext = new Logger(mockEventManager, initialContext);
|
|
323
|
-
|
|
324
|
-
const newContext = { source: "override", newProp: "value" };
|
|
325
|
-
const newLogger = loggerWithContext.with(newContext);
|
|
326
|
-
|
|
327
|
-
// The new logger should have the overridden context
|
|
328
|
-
expect(newLogger).toBeInstanceOf(Logger);
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
it("should use bound context in log calls", async () => {
|
|
332
|
-
const boundContext = { source: "testSource", userId: "123" };
|
|
333
|
-
const loggerWithContext = new Logger(mockEventManager, boundContext);
|
|
334
|
-
|
|
335
|
-
mockEventManager.emit = jest.fn().mockResolvedValue(undefined);
|
|
336
|
-
mockEventManager.hasListeners = jest.fn().mockReturnValue(true);
|
|
337
|
-
|
|
338
|
-
loggerWithContext.log("info", "Test message");
|
|
339
|
-
|
|
340
|
-
await new Promise(setImmediate);
|
|
341
|
-
|
|
342
|
-
expect(mockEventManager.emit).toHaveBeenCalledWith(
|
|
343
|
-
globalEvents.log,
|
|
344
|
-
expect.objectContaining({
|
|
345
|
-
source: "testSource",
|
|
346
|
-
context: boundContext,
|
|
347
|
-
}),
|
|
348
|
-
"testSource"
|
|
349
|
-
);
|
|
350
|
-
});
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
describe("error handling", () => {
|
|
354
|
-
it("should handle event emission errors gracefully", async () => {
|
|
355
|
-
const consoleErrorSpy = jest.spyOn(console, "error").mockImplementation();
|
|
356
|
-
const emitError = new Error("Event emission failed");
|
|
357
|
-
|
|
358
|
-
mockEventManager.emit = jest.fn().mockRejectedValue(emitError);
|
|
359
|
-
mockEventManager.hasListeners = jest.fn().mockReturnValue(true);
|
|
360
|
-
|
|
361
|
-
logger.log("error", "Test error message");
|
|
362
|
-
|
|
363
|
-
// Wait for setImmediate and promise rejection to be handled
|
|
364
|
-
await new Promise(setImmediate);
|
|
365
|
-
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
366
|
-
|
|
367
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
368
|
-
"Logger event emission failed:",
|
|
369
|
-
emitError
|
|
370
|
-
);
|
|
371
|
-
|
|
372
|
-
consoleErrorSpy.mockRestore();
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
it("should extract error information from Error objects", async () => {
|
|
376
|
-
mockEventManager.emit = jest.fn().mockResolvedValue(undefined);
|
|
377
|
-
mockEventManager.hasListeners = jest.fn().mockReturnValue(true);
|
|
378
|
-
|
|
379
|
-
const testError = new Error("Test error message");
|
|
380
|
-
testError.name = "CustomError";
|
|
381
|
-
|
|
382
|
-
logger.log("error", "Operation failed", { error: testError });
|
|
383
|
-
|
|
384
|
-
// Wait for setImmediate to execute
|
|
385
|
-
await new Promise(setImmediate);
|
|
386
|
-
|
|
387
|
-
expect(mockEventManager.emit).toHaveBeenCalledWith(
|
|
388
|
-
globalEvents.log,
|
|
389
|
-
expect.objectContaining({
|
|
390
|
-
level: "error",
|
|
391
|
-
message: "Operation failed",
|
|
392
|
-
error: {
|
|
393
|
-
name: "CustomError",
|
|
394
|
-
message: "Test error message",
|
|
395
|
-
stack: expect.any(String),
|
|
396
|
-
},
|
|
397
|
-
timestamp: expect.any(Date),
|
|
398
|
-
}),
|
|
399
|
-
"unknown"
|
|
400
|
-
);
|
|
401
|
-
});
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
describe("default print threshold", () => {
|
|
405
|
-
it("should default to 'info' level when no environment variables are set", () => {
|
|
406
|
-
const logger = new Logger(mockEventManager);
|
|
407
|
-
expect(logger.printThreshold).toBe("info");
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
it("should respect RUNNER_DISABLE_LOGS=true to disable logging", () => {
|
|
411
|
-
process.env.RUNNER_DISABLE_LOGS = "true";
|
|
412
|
-
const logger = new Logger(mockEventManager);
|
|
413
|
-
expect(logger.printThreshold).toBeNull();
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
it("should respect RUNNER_DISABLE_LOGS=1 to disable logging", () => {
|
|
417
|
-
process.env.RUNNER_DISABLE_LOGS = "1";
|
|
418
|
-
const logger = new Logger(mockEventManager);
|
|
419
|
-
expect(logger.printThreshold).toBeNull();
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
it("should respect RUNNER_LOG_LEVEL environment variable", () => {
|
|
423
|
-
process.env.RUNNER_LOG_LEVEL = "error";
|
|
424
|
-
const logger = new Logger(mockEventManager);
|
|
425
|
-
expect(logger.printThreshold).toBe("error");
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
it("should ignore invalid RUNNER_LOG_LEVEL and use default", () => {
|
|
429
|
-
process.env.RUNNER_LOG_LEVEL = "invalid_level";
|
|
430
|
-
const logger = new Logger(mockEventManager);
|
|
431
|
-
expect(logger.printThreshold).toBe("info");
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
it("should prioritize RUNNER_DISABLE_LOGS over RUNNER_LOG_LEVEL", () => {
|
|
435
|
-
process.env.RUNNER_DISABLE_LOGS = "true";
|
|
436
|
-
process.env.RUNNER_LOG_LEVEL = "debug";
|
|
437
|
-
const logger = new Logger(mockEventManager);
|
|
438
|
-
expect(logger.printThreshold).toBeNull();
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
it("should print info level logs by default", () => {
|
|
442
|
-
const consoleLogSpy = jest.spyOn(console, "log").mockImplementation();
|
|
443
|
-
|
|
444
|
-
const logger = new Logger(mockEventManager);
|
|
445
|
-
logger.log("info", "This should be printed by default");
|
|
446
|
-
|
|
447
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
448
|
-
expect.stringContaining("This should be printed by default")
|
|
449
|
-
);
|
|
450
|
-
|
|
451
|
-
consoleLogSpy.mockRestore();
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
it("should not print debug level logs by default", () => {
|
|
455
|
-
const consoleLogSpy = jest.spyOn(console, "log").mockImplementation();
|
|
456
|
-
|
|
457
|
-
const logger = new Logger(mockEventManager);
|
|
458
|
-
logger.log("debug", "This should not be printed by default");
|
|
459
|
-
|
|
460
|
-
expect(consoleLogSpy).not.toHaveBeenCalledWith(
|
|
461
|
-
expect.stringContaining("This should not be printed by default")
|
|
462
|
-
);
|
|
463
|
-
|
|
464
|
-
consoleLogSpy.mockRestore();
|
|
465
|
-
});
|
|
466
|
-
});
|
|
467
|
-
|
|
468
|
-
it("should auto-print logs based on autoPrintLogsAfter option", () => {
|
|
469
|
-
const autoPrintLevel: LogLevels = "warn";
|
|
470
|
-
logger.setPrintThreshold(autoPrintLevel);
|
|
471
|
-
const consoleLogSpy = jest.spyOn(console, "log").mockImplementation();
|
|
472
|
-
|
|
473
|
-
const levels: Array<LogLevels> = [
|
|
474
|
-
"trace",
|
|
475
|
-
"debug",
|
|
476
|
-
"info",
|
|
477
|
-
"warn",
|
|
478
|
-
"error",
|
|
479
|
-
"critical",
|
|
480
|
-
];
|
|
481
|
-
|
|
482
|
-
for (const level of levels) {
|
|
483
|
-
logger.setPrintThreshold(level);
|
|
484
|
-
logger.log(level, `Test ${level} message`);
|
|
485
|
-
|
|
486
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
487
|
-
expect.stringContaining(`Test ${level} message`)
|
|
488
|
-
);
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
// ensure events with a higher level thatn auto print level are printed, and lower levels are not
|
|
492
|
-
logger.setPrintThreshold("error");
|
|
493
|
-
logger.log("info", "xx Test info message");
|
|
494
|
-
logger.log("error", "xx Test error message");
|
|
495
|
-
|
|
496
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
497
|
-
expect.stringContaining("xx Test error message")
|
|
498
|
-
);
|
|
499
|
-
|
|
500
|
-
expect(consoleLogSpy).not.toHaveBeenCalledWith(
|
|
501
|
-
expect.stringContaining("xx Test info message")
|
|
502
|
-
);
|
|
503
|
-
|
|
504
|
-
consoleLogSpy.mockRestore();
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
it("should disable auto-printing when setPrintThreshold is set to null", () => {
|
|
508
|
-
const consoleLogSpy = jest.spyOn(console, "log").mockImplementation();
|
|
509
|
-
|
|
510
|
-
// Set to null to disable auto-printing
|
|
511
|
-
logger.setPrintThreshold(null);
|
|
512
|
-
|
|
513
|
-
logger.log("error", "Should not be printed");
|
|
514
|
-
|
|
515
|
-
expect(consoleLogSpy).not.toHaveBeenCalled();
|
|
516
|
-
|
|
517
|
-
consoleLogSpy.mockRestore();
|
|
518
|
-
});
|
|
519
|
-
});
|
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
// queue.test.ts
|
|
2
|
-
import { Queue } from "../.."; // <-- adjust path if needed
|
|
3
|
-
|
|
4
|
-
/* ------------------------------------------------------------------ */
|
|
5
|
-
/* Helpers */
|
|
6
|
-
/* ------------------------------------------------------------------ */
|
|
7
|
-
|
|
8
|
-
/** Flush native micro‑tasks once (Promise jobs / process.nextTick). */
|
|
9
|
-
const flushMicroTasks = () => Promise.resolve();
|
|
10
|
-
|
|
11
|
-
/** Small delay helper for tests */
|
|
12
|
-
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
13
|
-
|
|
14
|
-
/* ------------------------------------------------------------------ */
|
|
15
|
-
/* Tests */
|
|
16
|
-
/* ------------------------------------------------------------------ */
|
|
17
|
-
|
|
18
|
-
describe("Queue", () => {
|
|
19
|
-
it("runs tasks sequentially and returns their results in order", async () => {
|
|
20
|
-
const q = new Queue();
|
|
21
|
-
|
|
22
|
-
const started: number[] = [];
|
|
23
|
-
const finished: number[] = [];
|
|
24
|
-
let concurrent = 0;
|
|
25
|
-
let maxConcurrent = 0;
|
|
26
|
-
|
|
27
|
-
const taskFactory = (id: number) => async () => {
|
|
28
|
-
started.push(id);
|
|
29
|
-
concurrent++;
|
|
30
|
-
maxConcurrent = Math.max(maxConcurrent, concurrent);
|
|
31
|
-
|
|
32
|
-
// simulate async work with a real small delay
|
|
33
|
-
await delay(1);
|
|
34
|
-
|
|
35
|
-
finished.push(id);
|
|
36
|
-
concurrent--;
|
|
37
|
-
return id;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const p1 = q.run(taskFactory(1));
|
|
41
|
-
const p2 = q.run(taskFactory(2));
|
|
42
|
-
const p3 = q.run(taskFactory(3));
|
|
43
|
-
|
|
44
|
-
const results = await Promise.all([p1, p2, p3]);
|
|
45
|
-
|
|
46
|
-
expect(results).toEqual([1, 2, 3]);
|
|
47
|
-
expect(started).toEqual([1, 2, 3]);
|
|
48
|
-
expect(finished).toEqual([1, 2, 3]);
|
|
49
|
-
expect(maxConcurrent).toBe(1); // never overlapped
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("detects dead‑lock when a queued task enqueues another task", async () => {
|
|
53
|
-
const q = new Queue();
|
|
54
|
-
|
|
55
|
-
const deadlock = () => q.run(async () => "nested"); // <-- illegal
|
|
56
|
-
|
|
57
|
-
await expect(q.run(deadlock)).rejects.toThrow(/Dead‑lock/);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it("dispose() drains pending tasks and rejects new ones", async () => {
|
|
61
|
-
const q = new Queue();
|
|
62
|
-
|
|
63
|
-
const task = async () => {
|
|
64
|
-
await delay(1);
|
|
65
|
-
return "ok";
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const p1 = q.run(task);
|
|
69
|
-
const p2 = q.run(task);
|
|
70
|
-
|
|
71
|
-
const disposeDone = q.dispose(); // default => { cancel: false }
|
|
72
|
-
|
|
73
|
-
await expect(disposeDone).resolves.toBeUndefined();
|
|
74
|
-
await expect(p1).resolves.toBe("ok");
|
|
75
|
-
await expect(p2).resolves.toBe("ok");
|
|
76
|
-
|
|
77
|
-
await expect(q.run(task)).rejects.toThrow(/disposed/);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("dispose({ cancel: true }) aborts the running task", async () => {
|
|
81
|
-
jest.useFakeTimers();
|
|
82
|
-
|
|
83
|
-
const q = new Queue();
|
|
84
|
-
|
|
85
|
-
/** Long‑running task that cooperates with AbortSignal. */
|
|
86
|
-
const longTask = async (signal: AbortSignal) =>
|
|
87
|
-
new Promise<void>((_res, rej) => {
|
|
88
|
-
const tid = setTimeout(_res, 100); // never actually fires
|
|
89
|
-
signal.addEventListener("abort", () => {
|
|
90
|
-
clearTimeout(tid);
|
|
91
|
-
rej(new Error("aborted"));
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const p = q.run(longTask);
|
|
96
|
-
|
|
97
|
-
// Let the task start
|
|
98
|
-
jest.advanceTimersByTime(0);
|
|
99
|
-
await flushMicroTasks();
|
|
100
|
-
|
|
101
|
-
const disposeDone = q.dispose({ cancel: true });
|
|
102
|
-
|
|
103
|
-
await flushMicroTasks(); // allow rejection to propagate
|
|
104
|
-
|
|
105
|
-
await expect(p).rejects.toThrow(/aborted/);
|
|
106
|
-
await expect(disposeDone).resolves.toBeUndefined();
|
|
107
|
-
|
|
108
|
-
jest.useRealTimers();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it("dispose() is idempotent - multiple calls should be safe", async () => {
|
|
112
|
-
const q = new Queue();
|
|
113
|
-
|
|
114
|
-
const task = async () => {
|
|
115
|
-
await delay(1);
|
|
116
|
-
return "ok";
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
const p = q.run(task);
|
|
120
|
-
|
|
121
|
-
// First dispose call
|
|
122
|
-
const dispose1 = q.dispose();
|
|
123
|
-
// Second dispose call should return immediately (if (this.disposed) return;)
|
|
124
|
-
const dispose2 = q.dispose();
|
|
125
|
-
// Third dispose call should also return immediately
|
|
126
|
-
const dispose3 = q.dispose();
|
|
127
|
-
|
|
128
|
-
await expect(dispose1).resolves.toBeUndefined();
|
|
129
|
-
await expect(dispose2).resolves.toBeUndefined();
|
|
130
|
-
await expect(dispose3).resolves.toBeUndefined();
|
|
131
|
-
await expect(p).resolves.toBe("ok");
|
|
132
|
-
|
|
133
|
-
// Further dispose calls after everything is settled should also be safe
|
|
134
|
-
const dispose4 = q.dispose();
|
|
135
|
-
await expect(dispose4).resolves.toBeUndefined();
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it("dispose() properly handles rejected tail promises", async () => {
|
|
139
|
-
const q = new Queue();
|
|
140
|
-
|
|
141
|
-
// Run a task first to establish the normal tail chain
|
|
142
|
-
await q.run(async () => "setup");
|
|
143
|
-
|
|
144
|
-
// Directly set the tail to a promise that will reject
|
|
145
|
-
// This simulates an internal error scenario where the tail becomes rejected
|
|
146
|
-
const rejectingPromise = Promise.reject(
|
|
147
|
-
new Error("Simulated tail rejection")
|
|
148
|
-
);
|
|
149
|
-
(q as any).tail = rejectingPromise;
|
|
150
|
-
|
|
151
|
-
// Spy on the rejecting promise to verify the catch is called
|
|
152
|
-
const catchSpy = jest.spyOn(rejectingPromise, "catch");
|
|
153
|
-
|
|
154
|
-
// The dispose method should handle this rejection with: await this.tail.catch(() => {})
|
|
155
|
-
// This specifically tests the line: await this.tail.catch(() => {});
|
|
156
|
-
await expect(q.dispose()).resolves.toBeUndefined();
|
|
157
|
-
|
|
158
|
-
// Verify that the catch method was called (meaning the tail.catch() line was executed)
|
|
159
|
-
expect(catchSpy).toHaveBeenCalledWith(expect.any(Function));
|
|
160
|
-
|
|
161
|
-
// Verify the queue is properly disposed
|
|
162
|
-
await expect(q.run(async () => "test")).rejects.toThrow(/disposed/);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it("should propagate task exceptions to the caller", async () => {
|
|
166
|
-
const q = new Queue();
|
|
167
|
-
|
|
168
|
-
// Test that exceptions are propagated, not swallowed
|
|
169
|
-
const errorTask = async () => {
|
|
170
|
-
await delay(1);
|
|
171
|
-
throw new Error("Task exception");
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
const successTask = async () => {
|
|
175
|
-
await delay(1);
|
|
176
|
-
return "success";
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
// Exception should be catchable by the caller
|
|
180
|
-
await expect(q.run(errorTask)).rejects.toThrow("Task exception");
|
|
181
|
-
|
|
182
|
-
// Queue should still work for subsequent tasks
|
|
183
|
-
await expect(q.run(successTask)).resolves.toBe("success");
|
|
184
|
-
|
|
185
|
-
// Multiple exceptions should all be catchable
|
|
186
|
-
await expect(q.run(errorTask)).rejects.toThrow("Task exception");
|
|
187
|
-
await expect(q.run(errorTask)).rejects.toThrow("Task exception");
|
|
188
|
-
});
|
|
189
|
-
});
|