Skip to content
This repository was archived by the owner on Jun 18, 2021. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add a test case for passing an Error object to triggerReport
Update the API docs for getReport and triggerReport.
Fix crash when error object does not include a stack trace.
  • Loading branch information
hhellyer committed Apr 24, 2017
commit c73968a8d58b508a5ca099049bf65d3245127870
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ can be specified as a parameter on the `triggerReport()` call.
nodereport.triggerReport("myReportName");
```

Both triggerReport() and getReport() can take an optional Error object as a parameter. If an Error object is provided the message and stack trace from the object will be included in the report in the `JavaScript Exception Details` section. When using node-report to handle errors in a callback or an exception handler this allows the report to include the location of the original error as well as where it was handled.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrap to 80 columns. markup triggerReport() and getReport() with backticks

Copy link
Copy Markdown
Contributor Author

@hhellyer hhellyer Apr 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've wrapped Error as well since it's naming a particular type.

If both a filename and Error object are passed to triggerReport() the Error object should be the second parameter.

```js
fs.stat('/usr/local/fake/fake.txt', (err, stats) => {
if(err) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space after "if"

nodereport.triggerReport(err);
}
...
});
```

## Configuration

Additional configuration is available using the following APIs:
Expand Down
4 changes: 4 additions & 0 deletions src/node_report.cc
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,10 @@ static void PrintJavaScriptErrorStack(std::ostream& out, Isolate* isolate, v8::M
out << *message_str << "\n";

Local<StackTrace> stack = v8::Exception::GetStackTrace(error.ToLocalChecked());
if (stack.IsEmpty()) {
out << "\nNo stack trace available from Exception::GetStackTrace()\n";
return;
}
// Print the stack trace, adding in the pc values from GetStackSample() if available
for (int i = 0; i < stack->GetFrameCount(); i++) {
PrintStackFrame(out, isolate, stack->GetFrame(i), i, nullptr);
Expand Down
13 changes: 12 additions & 1 deletion test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,18 @@ exports.validateContent = function validateContent(data, t, options) {
const expectedVersions = options ?
options.expectedVersions || nodeComponents :
nodeComponents;
var plan = REPORT_SECTIONS.length + nodeComponents.length + 5;
const expectedException = options.expectedException;
if (options.expectedException) {
REPORT_SECTIONS.push('JavaScript Exception Details');
}

let plan = REPORT_SECTIONS.length + nodeComponents.length + 5;
if (options.commandline) plan++;
if (options.expectedException) plan++;
const glibcRE = /\(glibc:\s([\d.]+)/;
const nodeReportSection = getSection(reportContents, 'Node Report');
const sysInfoSection = getSection(reportContents, 'System Information');
const exceptionSection = getSection(reportContents, 'JavaScript Exception Details');
const libcPath = getLibcPath(sysInfoSection);
const libcVersion = getLibcVersion(libcPath);
if (glibcRE.test(nodeReportSection) && libcVersion) plan++;
Expand All @@ -84,6 +91,10 @@ exports.validateContent = function validateContent(data, t, options) {
new RegExp('Node.js version: ' + process.version),
'Node Report header section contains expected Node.js version');
}
if( options && options.expectedException) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spacing around if(

t.match(exceptionSection, new RegExp('Uncaught Error: ' + options.expectedException),
'Node Report JavaScript Exception contains expected message');
}
if (options && options.commandline) {
if (this.isWindows()) {
// On Windows we need to strip double quotes from the command line in
Expand Down
29 changes: 29 additions & 0 deletions test/test-api-pass-error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

// Testcase for passing an error object to the API call.

if (process.argv[2] === 'child') {
const nodereport = require('../');
try {
throw new Error("Testing error handling");
} catch (err) {
nodereport.triggerReport(err);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation looks off here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rnchamberlain what happened to #46? It would prevent this.

}
} else {
const common = require('./common.js');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can just be common instead of common.js

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested, it looks like it can. @sam-github had other comments about the test structure. At the moment it matches all the other tests and if we want to fix one up we should probably do all of them under a separate PR so I'm going to leave this for now.

const spawn = require('child_process').spawn;
const tap = require('tap');

const child = spawn(process.execPath, [__filename, 'child']);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why the test is spawning a child to call triggerReport(), why not just call it directly in the test? It looks like boilerplate copied from a test that must exist in order to get the report that doesn't apply here. If it is needed, probably needs a comment explaining why.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe most of the tests use spawn so the standard validation checks in common.js can check a known set of process arguments. I think @richardlau would be the person to ask if you want the history.

The test is a direct copy of test-api.js with a small change to how the triggerReport() call is made and an extra parameter to the common.validate() function. All the tests work along similar lines so I'll leave it how it is to make sure it fits the current model. If we want to change that we should do it under a separate PR so all the tests are consistent.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, part of the standard validation checks in common.js is to check the command line, so our tests spawn as it's the only way to be certain what to expect.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although the command line check can be skipped by not setting commandline on the options object passed to validate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sam-github Do you want this changed before you approve? I'm happy to raise a separate PR about changing the tests.

child.on('exit', (code) => {
tap.plan(3);
tap.equal(code, 0, 'Process exited cleanly');
const reports = common.findReports(child.pid);
tap.equal(reports.length, 1, 'Found reports ' + reports);
const report = reports[0];
common.validate(tap, report, {pid: child.pid,
commandline: child.spawnargs.join(' '),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was half convinced by the argument for spawning above, then I read test/common.js, and now I'm not. The command line is just checked against what is passed in here, which could just as easily be process.argv.join(" ") as child.spawnargs.join(" "). Same comment for test/test-api.js, which I suspect was simply copied from the other non-API tests. The non-API tests obviously have to spawn, if you are testing the report generated by a fatal exception you need your child to be the one that dies with the fatal exception, but for API testing, I'm not seeing the need. For that matter, I don't think this test needs its own file. test/test-api.js should be changed to test both variants of triggerReport() and to not spawn children, making it a much more typical API test.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the problems we had with process.argv (#58 (comment)) is that Node.js rewrites argv (e.g. it resolves argv[0]). When we spawn we have control over the command line, so we know that if we spawn with a resolved path (e.g. process.execPath) the operating system will match what is reported by Node.js.

But as I pointed out elsewhere the command line check is optional -- We can leave out commandline from the options passed to common.validate and the check will be skipped.

expectedException: "Testing error handling",
});
});
}