-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This fixes #73 Adds a "Debug Zone" that provides debugging information for when a Task fails to complete. it is used in conjunction with the Timeout Zone.
- Loading branch information
Showing
4 changed files
with
210 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module.exports = require("./lib/zones/debug"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
var Zone = require("../zone"); | ||
var timeoutZone = require("./timeout"); | ||
|
||
var EOL = "\n"; | ||
if(typeof process === "object" && {}.toString.call(process) === "[object process]") { | ||
var r = require; | ||
EOL = r("os").EOL; | ||
} | ||
|
||
module.exports = function(data){ | ||
|
||
var taskFns = {}; | ||
var queue = []; | ||
|
||
return { | ||
created: function(){ | ||
eachTask(function(name, value, tasks){ | ||
taskFns[name] = value; | ||
tasks[name] = function(){ | ||
var fn = value.apply(this, arguments); | ||
return function(){ | ||
var e = new Error(); | ||
var waitFor = Zone.prototype.waitFor; | ||
Zone.prototype.waitFor = function(){ | ||
var waitFn = waitFor.apply(this, arguments); | ||
var wrapped = function(){ | ||
var idx = queue.indexOf(wrapped); | ||
queue.splice(idx, 1); | ||
return waitFn.apply(this, arguments); | ||
}; | ||
wrapped.__debugInfo = { | ||
e: e, | ||
task: getTaskName(name) | ||
}; | ||
queue.push(wrapped); | ||
return wrapped; | ||
}; | ||
var res = fn.apply(this, arguments); | ||
Zone.prototype.waitFor = waitFor; | ||
return res; | ||
}; | ||
}; | ||
}); | ||
}, | ||
|
||
ended: function(){ | ||
eachTask(function(name, value, tasks){ | ||
tasks[name] = taskFns[name]; | ||
}); | ||
}, | ||
|
||
beforeTimeout: function(){ | ||
var infos = queue.map(function(fn){ | ||
var info = fn.__debugInfo; | ||
return { | ||
task: info.task, | ||
// Deleting the first two lines because it has our own | ||
// function calls | ||
stack: deleteLines(info.e.stack, [1,2]) | ||
}; | ||
}); | ||
data.debugInfo = infos; | ||
queue = []; | ||
}, | ||
|
||
plugins: [timeoutZone] | ||
}; | ||
}; | ||
|
||
var taskNameMap = { | ||
then: "Promise" | ||
}; | ||
function getTaskName(name) { | ||
return taskNameMap[name] || name; | ||
} | ||
|
||
function eachTask(callback){ | ||
var tasks = Zone.tasks; | ||
for(var t in tasks) { | ||
callback(t, tasks[t], tasks); | ||
} | ||
} | ||
|
||
function deleteLines(str, lines){ | ||
var parts = str.split(EOL); | ||
// v8 Includes an "Error" line by itself but Firefox does not | ||
// This determines where we start deleting lines from. | ||
var hasPrecedingMsg = parts[0] !== "Error"; | ||
var haveCut = false; | ||
|
||
while(lines.length) { | ||
var line = lines.shift(); | ||
if(haveCut) { | ||
line--; | ||
} | ||
if(hasPrecedingMsg) { | ||
line--; | ||
} | ||
parts.splice(line, 1); | ||
haveCut = true; | ||
} | ||
|
||
return parts.join(EOL); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
var assert = require("assert"); | ||
var debugZone = require("../debug"); | ||
|
||
describe("Debug Zone", function(){ | ||
it("Depends on the timeoutZone", function(){ | ||
var zone = new Zone(debugZone); | ||
assert.equal(typeof zone.timeout, "function", | ||
"timeoutZone is being used"); | ||
}); | ||
|
||
describe("Wrapping tasks", function(){ | ||
beforeEach(function(){ | ||
this.taskSetTimeout = Zone.tasks.setTimeout; | ||
}); | ||
|
||
it("Cleans up after itself", function(done){ | ||
var zone = new Zone(debugZone); | ||
var test = this; | ||
|
||
zone.run(function(){}).then(function(){ | ||
assert.equal(Zone.tasks.setTimeout, test.taskSetTimeout, | ||
"was reset"); | ||
done(); | ||
}); | ||
|
||
}); | ||
|
||
}); | ||
|
||
it("Gives you a stack trace", function(done){ | ||
var zone = new Zone(debugZone); | ||
var timeout = zone.timeout(30); | ||
|
||
zone.run(function(){ | ||
function someFunc(){ | ||
setTimeout(function(){}, 50); | ||
} | ||
someFunc(); | ||
}); | ||
|
||
timeout.then(function(data){ | ||
var info = data.debugInfo; | ||
|
||
assert.ok(info, "Zone has a debugInfo"); | ||
assert.equal(info.length, 1, "has one info"); | ||
assert.equal(info[0].task, "setTimeout", "has info on a setTimeout"); | ||
assert.ok(/someFunc/.test(info[0].stack), "has someFunc in the stack"); | ||
}).then(done, done); | ||
}); | ||
|
||
it("Doesn't include debug info when a task does complete", function(done){ | ||
var zone = new Zone(debugZone); | ||
var timeout = zone.timeout(10); | ||
|
||
zone.run(function(){ | ||
setTimeout(function(){}); | ||
setTimeout(function(){}, 30); | ||
}); | ||
|
||
timeout.then(function(data){ | ||
var info = data.debugInfo; | ||
|
||
assert.equal(info.length, 1, "There is only 1 item in the debug info"); | ||
}).then(done, done); | ||
}); | ||
|
||
it("Includes debug info for the tasks that did not complete", function(done){ | ||
var zone = new Zone(debugZone); | ||
var timeout = zone.timeout(20); | ||
|
||
zone.run(function(){ | ||
setTimeout(function(){}, 10); | ||
|
||
function someFunc(){ | ||
setTimeout(function(){}, 30); | ||
} | ||
someFunc(); | ||
|
||
function makePromise(){ | ||
var p = new Promise(function(){}); | ||
return p.then(function(){ | ||
Zone.current.data.failed = true; | ||
}); | ||
} | ||
makePromise(); | ||
}); | ||
|
||
timeout.then(function(data){ | ||
var info = data.debugInfo; | ||
|
||
assert.equal(info.length, 2, "There were two timed out tasks"); | ||
|
||
var stInfo = info[0]; | ||
assert.equal(stInfo.task, "setTimeout", "this is for the setTimeout"); | ||
assert.ok(/someFunc/.test(stInfo.stack), "contains right function call"); | ||
|
||
var pInfo = info[1]; | ||
assert.equal(pInfo.task, "Promise", "this is for the Promise"); | ||
assert.ok(/makePromise/.test(pInfo.stack), "contains the right function call"); | ||
}).then(done, done); | ||
|
||
}); | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters