1'use strict'; 2 3const common = require('../common'); 4const assert = require('assert'); 5const dc = require('diagnostics_channel'); 6const { AsyncLocalStorage } = require('async_hooks'); 7 8let n = 0; 9const thisArg = new Date(); 10const inputs = [ 11 { foo: 'bar' }, 12 { baz: 'buz' }, 13]; 14 15const channel = dc.channel('test'); 16 17// Bind a storage directly to published data 18const store1 = new AsyncLocalStorage(); 19channel.bindStore(store1); 20let store1bound = true; 21 22// Bind a store with transformation of published data 23const store2 = new AsyncLocalStorage(); 24channel.bindStore(store2, common.mustCall((data) => { 25 assert.strictEqual(data, inputs[n]); 26 return { data }; 27}, 4)); 28 29// Regular subscribers should see publishes from runStores calls 30channel.subscribe(common.mustCall((data) => { 31 if (store1bound) { 32 assert.deepStrictEqual(data, store1.getStore()); 33 } 34 assert.deepStrictEqual({ data }, store2.getStore()); 35 assert.strictEqual(data, inputs[n]); 36}, 4)); 37 38// Verify stores are empty before run 39assert.strictEqual(store1.getStore(), undefined); 40assert.strictEqual(store2.getStore(), undefined); 41 42channel.runStores(inputs[n], common.mustCall(function(a, b) { 43 // Verify this and argument forwarding 44 assert.strictEqual(this, thisArg); 45 assert.strictEqual(a, 1); 46 assert.strictEqual(b, 2); 47 48 // Verify store 1 state matches input 49 assert.strictEqual(store1.getStore(), inputs[n]); 50 51 // Verify store 2 state has expected transformation 52 assert.deepStrictEqual(store2.getStore(), { data: inputs[n] }); 53 54 // Should support nested contexts 55 n++; 56 channel.runStores(inputs[n], common.mustCall(function() { 57 // Verify this and argument forwarding 58 assert.strictEqual(this, undefined); 59 60 // Verify store 1 state matches input 61 assert.strictEqual(store1.getStore(), inputs[n]); 62 63 // Verify store 2 state has expected transformation 64 assert.deepStrictEqual(store2.getStore(), { data: inputs[n] }); 65 })); 66 n--; 67 68 // Verify store 1 state matches input 69 assert.strictEqual(store1.getStore(), inputs[n]); 70 71 // Verify store 2 state has expected transformation 72 assert.deepStrictEqual(store2.getStore(), { data: inputs[n] }); 73}), thisArg, 1, 2); 74 75// Verify stores are empty after run 76assert.strictEqual(store1.getStore(), undefined); 77assert.strictEqual(store2.getStore(), undefined); 78 79// Verify unbinding works 80assert.ok(channel.unbindStore(store1)); 81store1bound = false; 82 83// Verify unbinding a store that is not bound returns false 84assert.ok(!channel.unbindStore(store1)); 85 86n++; 87channel.runStores(inputs[n], common.mustCall(() => { 88 // Verify after unbinding store 1 will remain undefined 89 assert.strictEqual(store1.getStore(), undefined); 90 91 // Verify still bound store 2 receives expected data 92 assert.deepStrictEqual(store2.getStore(), { data: inputs[n] }); 93})); 94 95// Contain transformer errors and emit on next tick 96const fail = new Error('fail'); 97channel.bindStore(store1, () => { 98 throw fail; 99}); 100 101let calledRunStores = false; 102process.once('uncaughtException', common.mustCall((err) => { 103 assert.strictEqual(calledRunStores, true); 104 assert.strictEqual(err, fail); 105})); 106 107channel.runStores(inputs[n], common.mustCall()); 108calledRunStores = true; 109