| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,66 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const common = require('../common'); | ||
| 3 | + const assert = require('node:assert'); | ||
| 4 | + const dc = require('node:diagnostics_channel'); | ||
| 5 | + const { AsyncLocalStorage } = require('node:async_hooks'); | ||
| 6 | + | ||
| 7 | + // Test BoundedChannel.run() with store transform error | ||
| 8 | + // Transform errors are scheduled via process.nextTick(triggerUncaughtException) | ||
| 9 | + | ||
| 10 | + const boundedChannel = dc.boundedChannel('test-run-transform-error'); | ||
| 11 | + const store = new AsyncLocalStorage(); | ||
| 12 | + const events = []; | ||
| 13 | + | ||
| 14 | + const transformError = new Error('transform failed'); | ||
| 15 | + | ||
| 16 | + // Set up uncaughtException handler to catch the transform error | ||
| 17 | + process.on('uncaughtException', common.mustCall((err) => { | ||
| 18 | + assert.strictEqual(err, transformError); | ||
| 19 | + events.push('uncaughtException'); | ||
| 20 | + })); | ||
| 21 | + | ||
| 22 | + boundedChannel.subscribe({ | ||
| 23 | + start(message) { | ||
| 24 | + events.push({ type: 'start', data: message }); | ||
| 25 | + }, | ||
| 26 | + end(message) { | ||
| 27 | + events.push({ type: 'end', data: message }); | ||
| 28 | + }, | ||
| 29 | + }); | ||
| 30 | + | ||
| 31 | + // Bind store with a transform that throws | ||
| 32 | + boundedChannel.start.bindStore(store, () => { | ||
| 33 | + throw transformError; | ||
| 34 | + }); | ||
| 35 | + | ||
| 36 | + // Store should remain undefined since transform will fail | ||
| 37 | + assert.strictEqual(store.getStore(), undefined); | ||
| 38 | + | ||
| 39 | + const result = boundedChannel.run({ operationId: '123' }, common.mustCall(() => { | ||
| 40 | + // Store should still be undefined because transform threw | ||
| 41 | + assert.strictEqual(store.getStore(), undefined); | ||
| 42 | + | ||
| 43 | + events.push('inside-run'); | ||
| 44 | + | ||
| 45 | + return 42; | ||
| 46 | + })); | ||
| 47 | + | ||
| 48 | + // Should still return the result despite transform error | ||
| 49 | + assert.strictEqual(result, 42); | ||
| 50 | + | ||
| 51 | + // Store should still be undefined after run | ||
| 52 | + assert.strictEqual(store.getStore(), undefined); | ||
| 53 | + | ||
| 54 | + // Start and end events should still be published despite transform error | ||
| 55 | + assert.strictEqual(events.length, 3); | ||
| 56 | + assert.strictEqual(events[0].type, 'start'); | ||
| 57 | + assert.strictEqual(events[0].data.operationId, '123'); | ||
| 58 | + assert.strictEqual(events[1], 'inside-run'); | ||
| 59 | + assert.strictEqual(events[2].type, 'end'); | ||
| 60 | + assert.strictEqual(events[2].data.operationId, '123'); | ||
| 61 | + | ||
| 62 | + // Validate uncaughtException was triggered via nextTick | ||
| 63 | + process.on('beforeExit', common.mustCall(() => { | ||
| 64 | + assert.strictEqual(events.length, 4); | ||
| 65 | + assert.strictEqual(events[3], 'uncaughtException'); | ||
| 66 | + })); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,125 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + require('../common'); | ||
| 3 | + const assert = require('node:assert'); | ||
| 4 | + const dc = require('node:diagnostics_channel'); | ||
| 5 | + const { AsyncLocalStorage } = require('node:async_hooks'); | ||
| 6 | + | ||
| 7 | + // Test basic run functionality | ||
| 8 | + { | ||
| 9 | + const boundedChannel = dc.boundedChannel('test-run-basic'); | ||
| 10 | + const events = []; | ||
| 11 | + | ||
| 12 | + boundedChannel.subscribe({ | ||
| 13 | + start(message) { | ||
| 14 | + events.push({ type: 'start', data: message }); | ||
| 15 | + }, | ||
| 16 | + end(message) { | ||
| 17 | + events.push({ type: 'end', data: message }); | ||
| 18 | + }, | ||
| 19 | + }); | ||
| 20 | + | ||
| 21 | + const context = { id: 123 }; | ||
| 22 | + const result = boundedChannel.run(context, () => { | ||
| 23 | + return 'success'; | ||
| 24 | + }); | ||
| 25 | + | ||
| 26 | + assert.strictEqual(result, 'success'); | ||
| 27 | + assert.strictEqual(events.length, 2); | ||
| 28 | + assert.deepStrictEqual(events, [ | ||
| 29 | + { type: 'start', data: { id: 123 } }, | ||
| 30 | + { type: 'end', data: { id: 123 } }, | ||
| 31 | + ]); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + // Test run with error | ||
| 35 | + { | ||
| 36 | + const boundedChannel = dc.boundedChannel('test-run-error'); | ||
| 37 | + const events = []; | ||
| 38 | + | ||
| 39 | + boundedChannel.subscribe({ | ||
| 40 | + start(message) { | ||
| 41 | + events.push({ type: 'start', data: message }); | ||
| 42 | + }, | ||
| 43 | + end(message) { | ||
| 44 | + events.push({ type: 'end', data: message }); | ||
| 45 | + }, | ||
| 46 | + }); | ||
| 47 | + | ||
| 48 | + const context = { id: 456 }; | ||
| 49 | + const testError = new Error('test error'); | ||
| 50 | + | ||
| 51 | + assert.throws(() => { | ||
| 52 | + boundedChannel.run(context, () => { | ||
| 53 | + throw testError; | ||
| 54 | + }); | ||
| 55 | + }, testError); | ||
| 56 | + | ||
| 57 | + // BoundedChannel does not handle errors - they just propagate | ||
| 58 | + // Only start and end events are published | ||
| 59 | + assert.strictEqual(events.length, 2); | ||
| 60 | + assert.deepStrictEqual(events, [ | ||
| 61 | + { type: 'start', data: { id: 456 } }, | ||
| 62 | + { type: 'end', data: { id: 456 } }, | ||
| 63 | + ]); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + // Test run with thisArg and args | ||
| 67 | + { | ||
| 68 | + const boundedChannel = dc.boundedChannel('test-run-args'); | ||
| 69 | + | ||
| 70 | + const obj = { value: 10 }; | ||
| 71 | + const result = boundedChannel.run({}, function(a, b) { | ||
| 72 | + return this.value + a + b; | ||
| 73 | + }, obj, 5, 15); | ||
| 74 | + | ||
| 75 | + assert.strictEqual(result, 30); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + // Test run with AsyncLocalStorage | ||
| 79 | + { | ||
| 80 | + const boundedChannel = dc.boundedChannel('test-run-store'); | ||
| 81 | + const store = new AsyncLocalStorage(); | ||
| 82 | + const events = []; | ||
| 83 | + | ||
| 84 | + boundedChannel.start.bindStore(store, (context) => { | ||
| 85 | + return { traceId: context.traceId }; | ||
| 86 | + }); | ||
| 87 | + | ||
| 88 | + boundedChannel.subscribe({ | ||
| 89 | + start(message) { | ||
| 90 | + events.push({ type: 'start', store: store.getStore() }); | ||
| 91 | + }, | ||
| 92 | + end(message) { | ||
| 93 | + events.push({ type: 'end', store: store.getStore() }); | ||
| 94 | + }, | ||
| 95 | + }); | ||
| 96 | + | ||
| 97 | + const result = boundedChannel.run({ traceId: 'abc123' }, () => { | ||
| 98 | + events.push({ type: 'inside', store: store.getStore() }); | ||
| 99 | + return 'result'; | ||
| 100 | + }); | ||
| 101 | + | ||
| 102 | + assert.strictEqual(result, 'result'); | ||
| 103 | + assert.strictEqual(events.length, 3); | ||
| 104 | + | ||
| 105 | + // Innert events should have store set | ||
| 106 | + assert.deepStrictEqual(events, [ | ||
| 107 | + { type: 'start', store: { traceId: 'abc123' } }, | ||
| 108 | + { type: 'inside', store: { traceId: 'abc123' } }, | ||
| 109 | + { type: 'end', store: { traceId: 'abc123' } }, | ||
| 110 | + ]); | ||
| 111 | + | ||
| 112 | + // Store should be undefined outside | ||
| 113 | + assert.strictEqual(store.getStore(), undefined); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + // Test run without subscribers | ||
| 117 | + { | ||
| 118 | + const boundedChannel = dc.boundedChannel('test-run-no-subs'); | ||
| 119 | + | ||
| 120 | + const result = boundedChannel.run({}, () => { | ||
| 121 | + return 'fast path'; | ||
| 122 | + }); | ||
| 123 | + | ||
| 124 | + assert.strictEqual(result, 'fast path'); | ||
| 125 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,90 @@ | |||
| 1 | + /* eslint-disable no-unused-vars */ | ||
| 2 | + 'use strict'; | ||
| 3 | + require('../common'); | ||
| 4 | + const assert = require('node:assert'); | ||
| 5 | + const dc = require('node:diagnostics_channel'); | ||
| 6 | + const { AsyncLocalStorage } = require('node:async_hooks'); | ||
| 7 | + | ||
| 8 | + // Test scope with thrown error | ||
| 9 | + { | ||
| 10 | + const boundedChannel = dc.boundedChannel('test-scope-throw'); | ||
| 11 | + const events = []; | ||
| 12 | + | ||
| 13 | + boundedChannel.subscribe({ | ||
| 14 | + start(message) { | ||
| 15 | + events.push({ type: 'start', data: message }); | ||
| 16 | + }, | ||
| 17 | + end(message) { | ||
| 18 | + events.push({ type: 'end', data: message }); | ||
| 19 | + }, | ||
| 20 | + }); | ||
| 21 | + | ||
| 22 | + const context = { id: 1 }; | ||
| 23 | + const testError = new Error('thrown error'); | ||
| 24 | + | ||
| 25 | + assert.throws(() => { | ||
| 26 | + using scope = boundedChannel.withScope(context); | ||
| 27 | + context.result = 'partial'; | ||
| 28 | + throw testError; | ||
| 29 | + }, testError); | ||
| 30 | + | ||
| 31 | + // End event should still be published | ||
| 32 | + assert.strictEqual(events.length, 2); | ||
| 33 | + assert.strictEqual(events[0].type, 'start'); | ||
| 34 | + assert.strictEqual(events[1].type, 'end'); | ||
| 35 | + | ||
| 36 | + // Context should have partial result but no error from throw | ||
| 37 | + assert.strictEqual(context.result, 'partial'); | ||
| 38 | + assert.strictEqual(context.error, undefined); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + // Test store restoration on error | ||
| 42 | + { | ||
| 43 | + const boundedChannel = dc.boundedChannel('test-scope-store-error'); | ||
| 44 | + const store = new AsyncLocalStorage(); | ||
| 45 | + | ||
| 46 | + boundedChannel.start.bindStore(store, (context) => context.value); | ||
| 47 | + | ||
| 48 | + boundedChannel.subscribe({ | ||
| 49 | + start() {}, | ||
| 50 | + end() {}, | ||
| 51 | + }); | ||
| 52 | + | ||
| 53 | + store.enterWith('before'); | ||
| 54 | + assert.strictEqual(store.getStore(), 'before'); | ||
| 55 | + | ||
| 56 | + const testError = new Error('test'); | ||
| 57 | + | ||
| 58 | + assert.throws(() => { | ||
| 59 | + using scope = boundedChannel.withScope({ value: 'during' }); | ||
| 60 | + assert.strictEqual(store.getStore(), 'during'); | ||
| 61 | + throw testError; | ||
| 62 | + }, testError); | ||
| 63 | + | ||
| 64 | + // Store should be restored even after error | ||
| 65 | + assert.strictEqual(store.getStore(), 'before'); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + // Test dispose during exception handling | ||
| 69 | + { | ||
| 70 | + const boundedChannel = dc.boundedChannel('test-scope-dispose-exception'); | ||
| 71 | + const events = []; | ||
| 72 | + | ||
| 73 | + boundedChannel.subscribe({ | ||
| 74 | + start() { | ||
| 75 | + events.push('start'); | ||
| 76 | + }, | ||
| 77 | + end() { | ||
| 78 | + events.push('end'); | ||
| 79 | + }, | ||
| 80 | + }); | ||
| 81 | + | ||
| 82 | + // Dispose should complete even when exception is thrown | ||
| 83 | + assert.throws(() => { | ||
| 84 | + using scope = boundedChannel.withScope({}); | ||
| 85 | + throw new Error('original error'); | ||
| 86 | + }, /original error/); | ||
| 87 | + | ||
| 88 | + // End event should have been called | ||
| 89 | + assert.deepStrictEqual(events, ['start', 'end']); | ||
| 90 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments