From 51c893d55dc67441c7515105347eb04082cae729 Mon Sep 17 00:00:00 2001 From: jeff-lewis Date: Sun, 17 Jul 2016 23:55:50 -0400 Subject: [PATCH 01/12] fix: tap tests except fs.tap.js --- .gitignore | 1 + .../runConfigurations/bind_emitter_tap_js.xml | 2 +- .idea/runConfigurations/namespace_test.xml | 9 --- .idea/runConfigurations/namespaces_tap_js.xml | 2 +- .idea/runConfigurations/promises_tap_js.xml | 2 +- .idea/runConfigurations/run_tap_tests.xml | 2 +- context.js | 22 +++----- test/tap/dns.tap.js | 2 +- test/tap/error-handling.tap.js | 12 ++-- test/tap/fs.tap.js | 2 +- test/tap/monkeypatching.tap.js | 55 ------------------- test/tap/namespaces-multiple-values.tap.js | 2 +- 12 files changed, 23 insertions(+), 90 deletions(-) delete mode 100644 .idea/runConfigurations/namespace_test.xml delete mode 100644 test/tap/monkeypatching.tap.js diff --git a/.gitignore b/.gitignore index c3d08a2..3684b67 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ .idea/ !.idea/runConfigurations +npm-debug.log diff --git a/.idea/runConfigurations/bind_emitter_tap_js.xml b/.idea/runConfigurations/bind_emitter_tap_js.xml index c60ce5d..6fc65bd 100644 --- a/.idea/runConfigurations/bind_emitter_tap_js.xml +++ b/.idea/runConfigurations/bind_emitter_tap_js.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/namespace_test.xml b/.idea/runConfigurations/namespace_test.xml deleted file mode 100644 index 768bcca..0000000 --- a/.idea/runConfigurations/namespace_test.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/namespaces_tap_js.xml b/.idea/runConfigurations/namespaces_tap_js.xml index 0c313f0..811145a 100644 --- a/.idea/runConfigurations/namespaces_tap_js.xml +++ b/.idea/runConfigurations/namespaces_tap_js.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/promises_tap_js.xml b/.idea/runConfigurations/promises_tap_js.xml index 59e7135..e58e4e9 100644 --- a/.idea/runConfigurations/promises_tap_js.xml +++ b/.idea/runConfigurations/promises_tap_js.xml @@ -1,5 +1,5 @@ - + diff --git a/.idea/runConfigurations/run_tap_tests.xml b/.idea/runConfigurations/run_tap_tests.xml index 6b43d8b..2b8b13a 100644 --- a/.idea/runConfigurations/run_tap_tests.xml +++ b/.idea/runConfigurations/run_tap_tests.xml @@ -1,5 +1,5 @@ - + diff --git a/context.js b/context.js index bec5e21..1232a10 100644 --- a/context.js +++ b/context.js @@ -104,7 +104,7 @@ Namespace.prototype.bind = function bind(fn, context) { } let self = this; - return function () { + return function() { self.enter(context); try { return fn.apply(this, arguments); @@ -152,10 +152,6 @@ Namespace.prototype.exit = function exit(context) { debug2('??ERROR?? context exiting but not entered - ignoring: ' + util.inspect(context)); } assert.ok(index >= 0, 'context not currently entered; can\'t exit. \n' + util.inspect(this) + '\n' + util.inspect(context)); - /*let len = trace.length; - for (let i = 0; i < len; i++) { - console.log(trace[i]); - }*/ } else { assert.ok(index, 'can\'t remove top context'); this._set.splice(index, 1); @@ -191,7 +187,7 @@ Namespace.prototype.bindEmitter = function bindEmitter(emitter) { let wrapped = unwrapped; let unwrappedContexts = unwrapped[CONTEXTS_SYMBOL]; - Object.keys(unwrappedContexts).forEach(function (name) { + Object.keys(unwrappedContexts).forEach(function(name) { let thunk = unwrappedContexts[name]; wrapped = thunk.namespace.bind(wrapped, thunk.context); }); @@ -306,7 +302,7 @@ function destroyNamespace(name) { function reset() { // must unregister async listeners if (process.namespaces) { - Object.keys(process.namespaces).forEach(function (name) { + Object.keys(process.namespaces).forEach(function(name) { destroyNamespace(name); }); } @@ -327,12 +323,12 @@ function debug2(msg) { /*function debug(from, ns) { - process._rawDebug('DEBUG: ' + util.inspect({ - from: from, - currentUid: currentUid, - context: ns ? ns._contexts.get(currentUid) : 'no ns' - }, true, 2, true)); -}*/ + process._rawDebug('DEBUG: ' + util.inspect({ + from: from, + currentUid: currentUid, + context: ns ? ns._contexts.get(currentUid) : 'no ns' + }, true, 2, true)); + }*/ module.exports = { diff --git a/test/tap/dns.tap.js b/test/tap/dns.tap.js index 627b017..fe4aa72 100644 --- a/test/tap/dns.tap.js +++ b/test/tap/dns.tap.js @@ -3,7 +3,7 @@ var dns = require('dns') , tap = require('tap') , test = tap.test - , createNamespace = require('../context.js').createNamespace + , createNamespace = require('./../../context.js').createNamespace ; test("continuation-local state with MakeCallback and DNS module", function (t) { diff --git a/test/tap/error-handling.tap.js b/test/tap/error-handling.tap.js index 9501cce..bad8573 100644 --- a/test/tap/error-handling.tap.js +++ b/test/tap/error-handling.tap.js @@ -85,7 +85,7 @@ test("synchronous throw checks if error exists", function (t) { test("throw in process.nextTick attaches the context", function (t) { t.plan(3); - var namespace = cls.createNamespace('cls@nexttick'); + var namespace = cls.createNamespace('cls@nexttick2'); var d = domain.create(); d.once('error', function (e) { @@ -93,7 +93,7 @@ test("throw in process.nextTick attaches the context", function (t) { t.equal(namespace.fromException(e)['value'], 'transaction set', "found the inner value"); - cls.destroyNamespace('cls@nexttick'); + cls.destroyNamespace('cls@nexttick2'); }); namespace.run(function () { @@ -103,7 +103,7 @@ test("throw in process.nextTick attaches the context", function (t) { process.nextTick(d.bind(function () { namespace.run(function () { namespace.set('value', 'transaction set'); - throw new Error("cls@nexttick explosion"); + throw new Error("cls@nexttick2 explosion"); }); })); @@ -114,7 +114,7 @@ test("throw in process.nextTick attaches the context", function (t) { test("throw in setTimeout attaches the context", function (t) { t.plan(3); - var namespace = cls.createNamespace('cls@nexttick'); + var namespace = cls.createNamespace('cls@nexttick3'); var d = domain.create(); d.once('error', function (e) { @@ -122,7 +122,7 @@ test("throw in setTimeout attaches the context", function (t) { t.equal(namespace.fromException(e)['value'], 'transaction set', "found the inner value"); - cls.destroyNamespace('cls@nexttick'); + cls.destroyNamespace('cls@nexttick3'); }); namespace.run(function () { @@ -132,7 +132,7 @@ test("throw in setTimeout attaches the context", function (t) { setTimeout(d.bind(function () { namespace.run(function () { namespace.set('value', 'transaction set'); - throw new Error("cls@nexttick explosion"); + throw new Error("cls@nexttick3 explosion"); }); })); diff --git a/test/tap/fs.tap.js b/test/tap/fs.tap.js index 9b8cff0..accdc32 100644 --- a/test/tap/fs.tap.js +++ b/test/tap/fs.tap.js @@ -1,6 +1,6 @@ 'use strict'; -var createNamespace = require('../context.js').createNamespace +var createNamespace = require('./../../context.js').createNamespace , fs = require('fs') , path = require('path') , exec = require('child_process').exec diff --git a/test/tap/monkeypatching.tap.js b/test/tap/monkeypatching.tap.js deleted file mode 100644 index 80b3575..0000000 --- a/test/tap/monkeypatching.tap.js +++ /dev/null @@ -1,55 +0,0 @@ -'use strict'; -var test = require('tap').test; - -if (!process.addAsyncListener) { - test("overwriting startup.processNextTick", function (t) { - t.plan(2); - - t.doesNotThrow(function () { require('../context.js'); }); - - t.ok(process.nextTick.__wrapped, "should wrap process.nextTick()"); - }); - - test("overwriting domain helpers", function (t) { - // domain helpers were only in 0.10.x - if (!(process._nextDomainTick && process._tickDomainCallback)) { - return t.end(); - } - - t.plan(2); - - t.ok(process._nextDomainTick.__wrapped, - "should wrap process._nextDomainTick()"); - t.ok(process._tickDomainCallback.__wrapped, - "should wrap process._tickDomainCallback()"); - }); - - test("overwriting timers", function (t) { - t.plan(2); - - var timers = require('timers'); - t.ok(timers.setTimeout.__wrapped, "should wrap setTimeout()"); - t.ok(timers.setInterval.__wrapped, "should wrap setInterval()"); - - /* It would be nice to test that monkeypatching preserves the status quo - * ante, but assert thinks setTimeout !== global.setTimeout (why?) and both of - * those are a wrapper around NativeModule.require("timers").setTimeout, - * presumably to try to prevent the kind of "fun" I'm having here. - */ - }); - - test("overwriting setImmediate", function (t) { - // setTimeout's a johnny-come-lately - if (!global.setImmediate) return t.end(); - - t.plan(1); - - t.ok(require('timers').setImmediate.__wrapped, "should wrap setImmediate()"); - - /* It would be nice to test that monkeypatching preserves the status quo - * ante, but assert thinks setTimeout !== global.setTimeout (why?) and both of - * those are a wrapper around NativeModule.require("timers").setTimeout, - * presumably to try to prevent the kind of "fun" I'm having here. - */ - }); -} diff --git a/test/tap/namespaces-multiple-values.tap.js b/test/tap/namespaces-multiple-values.tap.js index f5d1407..5fb2c25 100644 --- a/test/tap/namespaces-multiple-values.tap.js +++ b/test/tap/namespaces-multiple-values.tap.js @@ -3,7 +3,7 @@ const test = require('tap').test; const util = require('util'); -const cls = require('../../context.js'); +const cls = require('./../../context.js'); test("multiple namespaces handles them correctly", function(t) { t.plan(4); From 50b7cf51f4908c3386a80dd149eba0f64022a11c Mon Sep 17 00:00:00 2001 From: jeff-lewis Date: Mon, 18 Jul 2016 00:08:02 -0400 Subject: [PATCH 02/12] add func names for callstacks --- context.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/context.js b/context.js index 1232a10..532d737 100644 --- a/context.js +++ b/context.js @@ -93,7 +93,7 @@ Namespace.prototype.run = function run(fn) { } }; -Namespace.prototype.bind = function bind(fn, context) { +Namespace.prototype.bind = function bindFactory(fn, context) { if (!context) { if (!this.active) { context = this.createContext(); @@ -104,7 +104,7 @@ Namespace.prototype.bind = function bind(fn, context) { } let self = this; - return function() { + return function clsBind() { self.enter(context); try { return fn.apply(this, arguments); From 4e23ae8bf4945ab4412383807afdda0e7bd71d29 Mon Sep 17 00:00:00 2001 From: jeff-lewis Date: Mon, 25 Jul 2016 14:45:26 -0400 Subject: [PATCH 03/12] updated comment, reordered exports. --- context.js | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/context.js b/context.js index 532d737..980d52b 100644 --- a/context.js +++ b/context.js @@ -19,6 +19,15 @@ const DEBUG_CLS_HOOKED = process.env.DEBUG_CLS_HOOKED; let currentUid = -1; +module.exports = { + getNamespace: getNamespace, + createNamespace: createNamespace, + destroyNamespace: destroyNamespace, + reset: reset, + //trace: trace, + ERROR_SYMBOL: ERROR_SYMBOL +}; + function Namespace(name) { this.name = name; // changed in 2.7: no default context @@ -222,12 +231,15 @@ function createNamespace(name) { asyncHook.addHooks({ init(uid, handle, provider, parentUid, parentHandle) { - //currentUid = parentUid || uid; // Suggested usage but appears to work better for tracing modules. + //parentUid = parentUid || currentUid; // Suggested usage but appears to work better for tracing modules. currentUid = uid; //CHAIN Parent's Context onto child if none exists. This is needed to pass net-events.spec if (parentUid) { namespace._contexts.set(uid, namespace._contexts.get(parentUid)); + if (DEBUG_CLS_HOOKED) { + debug2('PARENTID: ' + name + ' uid:' + uid + ' parent:' + parentUid + ' provider:' + provider); + } } else { namespace._contexts.set(currentUid, namespace.active); } @@ -237,12 +249,6 @@ function createNamespace(name) { + ' active:' + util.inspect(namespace.active, true)); } - if (parentUid) { - if (DEBUG_CLS_HOOKED) { - debug2('PARENTID: ' + name + ' uid:' + uid + ' parent:' + parentUid + ' provider:' + provider); - } - } - }, pre(uid, handle) { currentUid = uid; @@ -331,15 +337,6 @@ function debug2(msg) { }*/ -module.exports = { - getNamespace: getNamespace, - createNamespace: createNamespace, - destroyNamespace: destroyNamespace, - reset: reset, - //trace: trace, - ERROR_SYMBOL: ERROR_SYMBOL -}; - function getFunctionName(fn) { if (!fn) { return fn; From 3f807a8814cf8540e1c5737639bb859253d49342 Mon Sep 17 00:00:00 2001 From: jeff-lewis Date: Mon, 8 Aug 2016 15:30:15 -0400 Subject: [PATCH 04/12] (test): do not run fs.tap tests on Windows. --- test/tap/fs.tap.js | 138 ++++++++++++++++++++++++--------------------- 1 file changed, 74 insertions(+), 64 deletions(-) diff --git a/test/tap/fs.tap.js b/test/tap/fs.tap.js index accdc32..6f9af2b 100644 --- a/test/tap/fs.tap.js +++ b/test/tap/fs.tap.js @@ -1,24 +1,26 @@ 'use strict'; +var os = require('os'); + var createNamespace = require('./../../context.js').createNamespace - , fs = require('fs') - , path = require('path') - , exec = require('child_process').exec - , tap = require('tap') - , test = tap.test + , fs = require('fs') + , path = require('path') + , exec = require('child_process').exec + , tap = require('tap') + , test = tap.test ; // CONSTANTS -var FILENAME = '__testfile' - , DIRNAME = '__TESTDIR' - , LINKNAME = '__testlink' +var FILENAME = '__testfile' + , DIRNAME = '__TESTDIR' + , LINKNAME = '__testlink' , HARDLINKNAME = '__testhardlink' ; function createFile(assert) { var contents = new Buffer("UHOH") - , file = fs.openSync(FILENAME, 'w') - , written = fs.writeSync(file, contents, 0, contents.length, 0) + , file = fs.openSync(FILENAME, 'w') + , written = fs.writeSync(file, contents, 0, contents.length, 0) ; assert.equals(written, contents.length, "whole buffer was written"); var rc = fs.closeSync(file); @@ -27,7 +29,9 @@ function createFile(assert) { return rc; } -function deleteFile() { return fs.unlinkSync(FILENAME); } +function deleteFile() { + return fs.unlinkSync(FILENAME); +} function createLink(assert) { @@ -50,7 +54,9 @@ function createDirectory(assert) { assert.ok(fs.existsSync(DIRNAME), "directory was created"); } -function deleteDirectory() { return fs.rmdirSync(DIRNAME); } +function deleteDirectory() { + return fs.rmdirSync(DIRNAME); +} function mapIds(username, groupname, callback) { @@ -74,6 +80,12 @@ function mapIds(username, groupname, callback) { } test("continuation-local state with MakeCallback and fs module", function (t) { + + if(os.platform() === 'win32'){ + t.plan(0); + return; + } + t.plan(33); var namespace = createNamespace('fs'); @@ -90,7 +102,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { fs.rename(FILENAME, '__renamed', function (error) { t.notOk(error, "renaming shouldn't error"); t.equal(namespace.get('test'), 'rename', - "mutated state has persisted to fs.rename's callback"); + "mutated state has persisted to fs.rename's callback"); fs.unlinkSync('__renamed'); t.end(); @@ -115,7 +127,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.equal(stats.size, 0, "file has been truncated"); t.equal(namespace.get('test'), 'truncate', - "mutated state has persisted to fs.truncate's callback"); + "mutated state has persisted to fs.truncate's callback"); deleteFile(); t.end(); @@ -142,7 +154,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.equal(stats.size, 0, "file has been truncated"); t.equal(namespace.get('test'), 'ftruncate', - "mutated state has persisted to fs.ftruncate's callback"); + "mutated state has persisted to fs.ftruncate's callback"); deleteFile(); t.end(); @@ -166,7 +178,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.ok(error, "changing ownership will error for non-root users"); t.equal(namespace.get('test'), 'chown', - "mutated state has persisted to fs.chown's callback"); + "mutated state has persisted to fs.chown's callback"); deleteFile(); t.end(); @@ -192,7 +204,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.ok(error, "changing ownership will error for non-root users"); t.equal(namespace.get('test'), 'fchown', - "mutated state has persisted to fs.fchown's callback"); + "mutated state has persisted to fs.fchown's callback"); fs.closeSync(file); deleteFile(); @@ -219,7 +231,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.ok(error, "changing ownership will error for non-root users"); t.equal(namespace.get('test'), 'lchown', - "mutated state has persisted to fs.lchown's callback"); + "mutated state has persisted to fs.lchown's callback"); deleteLink(); t.end(); @@ -239,7 +251,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "changing mode shouldn't error"); t.equal(namespace.get('test'), 'chmod', - "mutated state has persisted to fs.chmod's callback"); + "mutated state has persisted to fs.chmod's callback"); var stats = fs.statSync(FILENAME); t.equal(stats.mode.toString(8), '100700', "extra access bits are stripped"); @@ -262,7 +274,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "changing mode shouldn't error"); t.equal(namespace.get('test'), 'fchmod', - "mutated state has persisted to fs.fchmod's callback"); + "mutated state has persisted to fs.fchmod's callback"); fs.closeSync(file); var stats = fs.statSync(FILENAME); @@ -286,7 +298,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "changing mode shouldn't error"); t.equal(namespace.get('test'), 'lchmod', - "mutated state has persisted to fs.lchmod's callback"); + "mutated state has persisted to fs.lchmod's callback"); var stats = fs.lstatSync(LINKNAME); t.equal(stats.mode.toString(8), '120700', "extra access bits are stripped"); @@ -308,7 +320,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "reading stats shouldn't error"); t.equal(namespace.get('test'), 'stat', - "mutated state has persisted to fs.stat's callback"); + "mutated state has persisted to fs.stat's callback"); t.equal(stats.mode.toString(8), '100666', "permissions should be as created"); @@ -330,7 +342,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "reading stats shouldn't error"); t.equal(namespace.get('test'), 'fstat', - "mutated state has persisted to fs.fstat's callback"); + "mutated state has persisted to fs.fstat's callback"); t.equal(stats.mode.toString(8), '100666', "permissions should be as created"); @@ -352,7 +364,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "reading stats shouldn't error"); t.equal(namespace.get('test'), 'lstat', - "mutated state has persisted to fs.lstat's callback"); + "mutated state has persisted to fs.lstat's callback"); t.equal( stats.mode.toString(8), @@ -377,9 +389,9 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "creating a link shouldn't error"); t.equal(namespace.get('test'), 'link', - "mutated state has persisted to fs.link's callback"); + "mutated state has persisted to fs.link's callback"); - var orig = fs.statSync(FILENAME) + var orig = fs.statSync(FILENAME) , linked = fs.statSync(HARDLINKNAME) ; t.equal(orig.ino, linked.ino, "entries should point to same file"); @@ -402,7 +414,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "creating a symlink shouldn't error"); t.equal(namespace.get('test'), 'symlink', - "mutated state has persisted to fs.symlink's callback"); + "mutated state has persisted to fs.symlink's callback"); var pointed = fs.readlinkSync(LINKNAME); t.equal(pointed, FILENAME, "symlink points back to original file"); @@ -425,7 +437,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "reading symlink shouldn't error"); t.equal(namespace.get('test'), 'readlink', - "mutated state has persisted to fs.readlink's callback"); + "mutated state has persisted to fs.readlink's callback"); t.equal(pointed, FILENAME, "symlink points back to original file"); @@ -446,7 +458,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "deleting file shouldn't error"); t.equal(namespace.get('test'), 'unlink', - "mutated state has persisted to fs.unlink's callback"); + "mutated state has persisted to fs.unlink's callback"); t.notOk(fs.exists(FILENAME), "file should be gone"); t.end(); @@ -465,7 +477,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "deleting file shouldn't error"); t.equal(namespace.get('test'), 'realpath', - "mutated state has persisted to fs.realpath's callback"); + "mutated state has persisted to fs.realpath's callback"); t.equal(real, path.resolve(FILENAME), "no funny business with the real path"); @@ -484,7 +496,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "creating directory shouldn't error"); t.equal(namespace.get('test'), 'mkdir', - "mutated state has persisted to fs.mkdir's callback"); + "mutated state has persisted to fs.mkdir's callback"); t.ok(fs.existsSync(DIRNAME), "directory was created"); @@ -505,7 +517,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "deleting directory shouldn't error"); t.equal(namespace.get('test'), 'rmdir', - "mutated state has persisted to fs.rmdir's callback"); + "mutated state has persisted to fs.rmdir's callback"); t.notOk(fs.existsSync(DIRNAME), "directory was removed"); @@ -537,7 +549,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "reading directory shouldn't error"); t.equal(namespace.get('test'), 'readdir', - "mutated state has persisted to fs.readdir's callback"); + "mutated state has persisted to fs.readdir's callback"); t.equal(contents.length, 3, "3 files were found"); @@ -558,19 +570,19 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.equal(namespace.get('test'), 'watch', "state has been mutated"); var watcher = fs.watch(FILENAME, - {persistent : false, interval : 200}, - function (event) { - t.equal(namespace.get('test'), 'watch', - "mutated state has persisted to fs.watch's callback"); - - t.equal(event, 'change', "file was changed"); - - watcher.close(); - process.nextTick(function cleanup() { - deleteFile(); - t.end(); + {persistent: false, interval: 200}, + function (event) { + t.equal(namespace.get('test'), 'watch', + "mutated state has persisted to fs.watch's callback"); + + t.equal(event, 'change', "file was changed"); + + watcher.close(); + process.nextTick(function cleanup() { + deleteFile(); + t.end(); + }); }); - }); setTimeout(function poke() { fs.writeFileSync(FILENAME, 'still a test'); @@ -598,7 +610,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "setting utimes shouldn't error"); t.equal(namespace.get('test'), 'utimes', - "mutated state has persisted to fs.utimes's callback"); + "mutated state has persisted to fs.utimes's callback"); var after = fs.statSync(FILENAME); t.deepEqual(after.atime, PASTIME, "access time of newly-created file is reset"); @@ -634,7 +646,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { fs.closeSync(file); t.equal(namespace.get('test'), 'futimes', - "mutated state has persisted to fs.futimes's callback"); + "mutated state has persisted to fs.futimes's callback"); var after = fs.statSync(FILENAME); t.deepEqual(after.atime, PASTIME, "access time of newly-created file is reset"); @@ -660,7 +672,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "syncing the file shouldn't error"); t.equal(namespace.get('test'), 'fsync', - "mutated state has persisted to fs.fsync's callback"); + "mutated state has persisted to fs.fsync's callback"); fs.closeSync(file); deleteFile(); @@ -680,7 +692,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "opening the file shouldn't error"); t.equal(namespace.get('test'), 'open', - "mutated state has persisted to fs.open's callback"); + "mutated state has persisted to fs.open's callback"); var contents = new Buffer(4); @@ -706,7 +718,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "closing the file shouldn't error"); t.equal(namespace.get('test'), 'close', - "mutated state has persisted to fs.close's callback"); + "mutated state has persisted to fs.close's callback"); deleteFile(); t.end(); @@ -721,14 +733,14 @@ test("continuation-local state with MakeCallback and fs module", function (t) { namespace.set('test', 'read'); t.equal(namespace.get('test'), 'read', "state has been mutated"); - var file = fs.openSync(FILENAME, 'r') + var file = fs.openSync(FILENAME, 'r') , contents = new Buffer(4) ; fs.read(file, contents, 0, 4, 0, function (error) { t.notOk(error, "reading from the file shouldn't error"); t.equal(namespace.get('test'), 'read', - "mutated state has persisted to fs.read's callback"); + "mutated state has persisted to fs.read's callback"); t.equal(contents.toString(), 'UHOH', "contents are still available"); @@ -746,14 +758,14 @@ test("continuation-local state with MakeCallback and fs module", function (t) { namespace.set('test', 'write'); t.equal(namespace.get('test'), 'write', "state has been mutated"); - var file = fs.openSync(FILENAME, 'w') + var file = fs.openSync(FILENAME, 'w') , contents = new Buffer('yeap') ; fs.write(file, contents, 0, 4, 0, function (error) { t.notOk(error, "writing to the file shouldn't error"); t.equal(namespace.get('test'), 'write', - "mutated state has persisted to fs.write's callback"); + "mutated state has persisted to fs.write's callback"); fs.closeSync(file); @@ -777,7 +789,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "reading from the file shouldn't error"); t.equal(namespace.get('test'), 'readFile', - "mutated state has persisted to fs.readFile's callback"); + "mutated state has persisted to fs.readFile's callback"); t.equal(contents.toString(), 'UHOH', "contents are still available"); @@ -798,7 +810,7 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "rewriting the file shouldn't error"); t.equal(namespace.get('test'), 'writeFile', - "mutated state has persisted to fs.writeFile's callback"); + "mutated state has persisted to fs.writeFile's callback"); var readback = fs.readFileSync(FILENAME); t.equal(readback.toString(), 'woopwoop', "rewritten contents are available"); @@ -820,11 +832,11 @@ test("continuation-local state with MakeCallback and fs module", function (t) { t.notOk(error, "appending to the file shouldn't error"); t.equal(namespace.get('test'), 'appendFile', - "mutated state has persisted to fs.appendFile's callback"); + "mutated state has persisted to fs.appendFile's callback"); var readback = fs.readFileSync(FILENAME); t.equal(readback.toString(), 'UHOH/jk', - "appended contents are still available"); + "appended contents are still available"); deleteFile(); t.end(); @@ -841,13 +853,13 @@ test("continuation-local state with MakeCallback and fs module", function (t) { fs.exists(FILENAME, function (yep) { t.equal(namespace.get('test'), 'exists', - "mutated state has persisted to fs.exists's callback"); + "mutated state has persisted to fs.exists's callback"); t.ok(yep, "precreated file does indeed exist."); fs.exists('NOPENOWAY', function (nope) { t.equal(namespace.get('test'), 'exists', - "mutated state continues to persist to fs.exists's second callback"); + "mutated state continues to persist to fs.exists's second callback"); t.notOk(nope, "nonexistent file doesn't exist."); @@ -865,11 +877,9 @@ test("continuation-local state with MakeCallback and fs module", function (t) { namespace.set('test', 'watchFile'); t.equal(namespace.get('test'), 'watchFile', "state has been mutated"); - fs.watchFile(FILENAME, - {persistent : false, interval : 20}, - function (before, after) { + fs.watchFile(FILENAME, {persistent: false, interval: 1}, function (before, after) { t.equal(namespace.get('test'), 'watchFile', - "mutated state has persisted to fs.watchFile's callback"); + "mutated state has persisted to fs.watchFile's callback"); t.ok(before.ino, "file has an entry"); t.equal(before.ino, after.ino, "file is at the same location"); From bb06357dbdf85f42a3ca87981da3c3dfbe466c2d Mon Sep 17 00:00:00 2001 From: jeff-lewis Date: Mon, 8 Aug 2016 15:32:23 -0400 Subject: [PATCH 05/12] package: update dependencies. Run mocha & tap tests --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index e2a5f33..5b77239 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "context.js" ], "scripts": { - "test": "mocha test/*.js", + "test": "mocha test/*.js & tap test/tap/*.tap.js", "test-tap": "tap test/tap/*.tap.js" }, "repository": { @@ -28,17 +28,17 @@ "license": "BSD-2-Clause", "engineStrict": true, "engines": { - "node": "^6.2.2" + "node": "^6.3.1" }, "devDependencies": { "chai": "^3.5.0", - "mocha": "^2.5.3", + "mocha": "^3.0.2", "sinon": "^1.17.4", "sinon-chai": "^2.8.0", "stack-chain": "^1.3.7", "superagent": "^2.0.0", "tap": "^6.2.0", - "tap-mocha-reporter": "0.0.25" + "tap-mocha-reporter": "0.0.27" }, "dependencies": { "async-hook": "^1.5.1", From 781a66f9941129105208aaa944cdef5ed665c507 Mon Sep 17 00:00:00 2001 From: jeff-lewis Date: Mon, 8 Aug 2016 15:33:02 -0400 Subject: [PATCH 06/12] (docs): update CHANGELOG and README --- CHANGELOG.md | 25 +++++++++++++++++-------- README.md | 6 ++++++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34aaf01..8b06868 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,24 @@ + +### v4.1.0 +* Feature: add `runAndReturn` method to get return value of `func` (from ). + + +### v4.0.1 +* Same API but major change to implementation. Uses **unofficial** [AsyncWrap](https://github.com/nodejs/node-eps/blob/async-wrap-ep/XXX-asyncwrap-api.md) instead of [async-listener](https://github.com/othiym23/async-listener). + + ### v3.1.0 (2014-07-28): * Updated to use `async-listener@0.4.7` to pick up bug fixes. ### v3.0.0 (2013-12-14): -* Removed the notion of a "default" or "global" context per namespace. It only - existed to create a simpler interface for developing and testing the module, - and created the potential for nasty information disclosure bugs (see [issue - #14](https://github.com/othiym23/node-continuation-local-storage/issues/14) - for details). This is potentially a breaking change, if you're depending on - the global context, so semver says we have to bump the major version. +* Removed the notion of a "default" or "global" context per namespace. + It only existed to create a simpler interface for developing and testing the module, + and created the potential for nasty information disclosure bugs + (see [issue #14](https://github.com/othiym23/node-continuation-local-storage/issues/14) + for details). This is potentially a breaking change, if you're depending on the global context, + so semver says we have to bump the major version. * Added this changelog. ### v2.6.2 (2013-12-07): @@ -18,8 +27,8 @@ ### v2.6.1 (2013-11-29): -* `emitter-listener` has been extracted from `shimmer` into a standalone - module for `namespace.bindEmitter()`. +* `emitter-listener` has been extracted from `shimmer` into a standalone module + for `namespace.bindEmitter()`. ### v2.6.0 (2013-11-27): diff --git a/README.md b/README.md index 871ec9a..43ef228 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,13 @@ [![NPM](https://nodei.co/npm/cls-hooked.png?downloads=true&stars=true)](https://nodei.co/npm/cls-hooked/) +[![travis-ci Build Status](https://travis-ci.org/Jeff-Lewis/cls-hooked.svg?branch=master)](https://travis-ci.org/Jeff-Lewis/cls-hooked) + # Continuation-Local Storage ( Hooked ) +### This is a fork of [CLS](https://github.com/othiym23/node-continuation-local-storage) using [AsyncWrap](https://github.com/nodejs/node-eps/blob/async-wrap-ep/XXX-asyncwrap-api.md) instead of [async-listener](https://github.com/othiym23/async-listener). ### + +#### Thanks to [@trevnorris](https://github.com/trevnorris) for [AsyncWrap](https://github.com/nodejs/node-eps/blob/async-wrap-ep/XXX-asyncwrap-api.md) and all the async work in Node and [@AndreasMadsen](https://github.com/AndreasMadsen) for [async-hook](https://github.com/AndreasMadsen/async-hook). ### + Continuation-local storage works like thread-local storage in threaded programming, but is based on chains of Node-style callbacks instead of threads. The standard Node convention of functions calling functions is very similar to From 9dd4e2651dc965d47db5d7ff51c74e4cda0d1831 Mon Sep 17 00:00:00 2001 From: jeff-lewis Date: Mon, 8 Aug 2016 15:41:33 -0400 Subject: [PATCH 07/12] `namespace.runAndReturn` method (cherry picked from commit 875d8731c5e7c4de4cf7adefd48302fff70935fe) # Conflicts: # context.js --- README.md | 13 +++++++++++++ context.js | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/README.md b/README.md index 43ef228..a53aace 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,19 @@ that take callbacks themselves) from the provided callback within the scope of that namespace. The new context is passed as an argument to the callback when it's called. +### namespace.runAndReturn(callback) + +* return: the return value of the callback + +Create a new context on which values can be set or read. Run all the functions +that are called (either directly, or indirectly through asynchronous functions +that take callbacks themselves) from the provided callback within the scope of +that namespace. The new context is passed as an argument to the callback +when it's called. + +Same as `namespace.run()` but returns the return value of the callback rather +than the context. + ### namespace.bind(callback, [context]) * return: a callback wrapped up in a context closure diff --git a/context.js b/context.js index 980d52b..7fedae3 100644 --- a/context.js +++ b/context.js @@ -102,6 +102,14 @@ Namespace.prototype.run = function run(fn) { } }; +Namespace.prototype.runAndReturn = function (fn) { + var value; + this.run(function (context) { + value = fn(context); + }); + return value; +}; + Namespace.prototype.bind = function bindFactory(fn, context) { if (!context) { if (!this.active) { From 54bbe77920d66822b0b06f9dc398a937cb9333f2 Mon Sep 17 00:00:00 2001 From: jeff-lewis Date: Mon, 8 Aug 2016 15:42:11 -0400 Subject: [PATCH 08/12] Test for `namespace.runAndReturn` (cherry picked from commit 2a3fc391c14b70cf04b09df642a4e9e77f2a3c06) --- test/run-and-return.tap.js | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 test/run-and-return.tap.js diff --git a/test/run-and-return.tap.js b/test/run-and-return.tap.js new file mode 100644 index 0000000..41d5708 --- /dev/null +++ b/test/run-and-return.tap.js @@ -0,0 +1,40 @@ +'use strict'; + +// stdlib +var tap = require('tap'); +var test = tap.test; +var EventEmitter = require('events').EventEmitter; + +// module under test +var context = require('../context.js'); + +// multiple contexts in use +var tracer = context.createNamespace('tracer'); + + +test("simple tracer built on contexts", function (t) { + t.plan(7); + + var harvester = new EventEmitter(); + + harvester.on('finished', function (transaction) { + t.ok(transaction, "transaction should have been passed in"); + t.equal(transaction.status, 'ok', "transaction should have finished OK"); + t.equal(Object.keys(process.namespaces).length, 1, "Should only have one namespace."); + }); + + var returnValue = {}; + + var returnedValue = tracer.runAndReturn(function(context) { + t.ok(tracer.active, "tracer should have an active context"); + tracer.set('transaction', {status : 'ok'}); + t.ok(tracer.get('transaction'), "can retrieve newly-set value"); + t.equal(tracer.get('transaction').status, 'ok', "value should be correct"); + + harvester.emit('finished', context.transaction); + + return returnValue; + }); + + t.equal(returnedValue, returnValue, "method should pass through return value of function run in scope"); +}); From 9a02ca67b839697534f64bf7a90f6487711b9db7 Mon Sep 17 00:00:00 2001 From: jeff-lewis Date: Mon, 8 Aug 2016 15:45:08 -0400 Subject: [PATCH 09/12] add .travis.yml --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..140594b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +script: + - "npm test" + +language: node_js + +node_js: + - "4" + - "6" + +sudo: false From 96212392831aac438f95a304366e86f6a0c360a2 Mon Sep 17 00:00:00 2001 From: jeff-lewis Date: Mon, 8 Aug 2016 15:50:35 -0400 Subject: [PATCH 10/12] (test): limit travis to node 6.x --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 140594b..833a1f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ script: language: node_js node_js: - - "4" - "6" sudo: false From 7f5135022df293143edbbbd74e7c6033a998e0be Mon Sep 17 00:00:00 2001 From: jeff-lewis Date: Mon, 8 Aug 2016 15:51:20 -0400 Subject: [PATCH 11/12] (test): move run-and-return.tap.js to tap folder --- test/{ => tap}/run-and-return.tap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename test/{ => tap}/run-and-return.tap.js (96%) diff --git a/test/run-and-return.tap.js b/test/tap/run-and-return.tap.js similarity index 96% rename from test/run-and-return.tap.js rename to test/tap/run-and-return.tap.js index 41d5708..6c04150 100644 --- a/test/run-and-return.tap.js +++ b/test/tap/run-and-return.tap.js @@ -6,7 +6,7 @@ var test = tap.test; var EventEmitter = require('events').EventEmitter; // module under test -var context = require('../context.js'); +var context = require('../../context.js'); // multiple contexts in use var tracer = context.createNamespace('tracer'); From 657264054c11311fe63eac67268f7dbf8156b3ec Mon Sep 17 00:00:00 2001 From: jeff-lewis Date: Mon, 8 Aug 2016 15:55:26 -0400 Subject: [PATCH 12/12] update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a53aace..6fe0b06 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -[![NPM](https://nodei.co/npm/cls-hooked.png?downloads=true&stars=true)](https://nodei.co/npm/cls-hooked/) +[![NPM](https://nodei.co/npm/cls-hooked.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/cls-hooked/) -[![travis-ci Build Status](https://travis-ci.org/Jeff-Lewis/cls-hooked.svg?branch=master)](https://travis-ci.org/Jeff-Lewis/cls-hooked) +[![Build Status](https://travis-ci.org/Jeff-Lewis/cls-hooked.svg?branch=master)](https://travis-ci.org/Jeff-Lewis/cls-hooked) # Continuation-Local Storage ( Hooked )