mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
report: expose report public native apis
Allows APM vendors to generate a diagnostic report without calling into JavaScript. Like, from their own message channels interrupting the isolate and generating a report on demand. PR-URL: https://github.com/nodejs/node/pull/44255 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
This commit is contained in:
parent
d9b2d2c0dd
commit
cb15fc56d8
1
node.gyp
1
node.gyp
@ -993,6 +993,7 @@
|
||||
'test/cctest/test_node_api.cc',
|
||||
'test/cctest/test_per_process.cc',
|
||||
'test/cctest/test_platform.cc',
|
||||
'test/cctest/test_report.cc',
|
||||
'test/cctest/test_json_utils.cc',
|
||||
'test/cctest/test_sockaddr.cc',
|
||||
'test/cctest/test_traced_value.cc',
|
||||
|
30
src/node.h
30
src/node.h
@ -75,8 +75,9 @@
|
||||
#include "v8-platform.h" // NOLINT(build/include_order)
|
||||
#include "node_version.h" // NODE_MODULE_VERSION
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
|
||||
// We cannot use __POSIX__ in this header because that's only defined when
|
||||
// building Node.js.
|
||||
@ -617,6 +618,33 @@ NODE_EXTERN v8::MaybeLocal<v8::Value> PrepareStackTraceCallback(
|
||||
v8::Local<v8::Value> exception,
|
||||
v8::Local<v8::Array> trace);
|
||||
|
||||
// Writes a diagnostic report to a file. If filename is not provided, the
|
||||
// default filename includes the date, time, PID, and a sequence number.
|
||||
// The report's JavaScript stack trace is taken from err, if present.
|
||||
// If isolate is nullptr, no information about the JavaScript environment
|
||||
// is included in the report.
|
||||
// Returns the filename of the written report.
|
||||
NODE_EXTERN std::string TriggerNodeReport(v8::Isolate* isolate,
|
||||
const char* message,
|
||||
const char* trigger,
|
||||
const std::string& filename,
|
||||
v8::Local<v8::Value> error);
|
||||
NODE_EXTERN std::string TriggerNodeReport(Environment* env,
|
||||
const char* message,
|
||||
const char* trigger,
|
||||
const std::string& filename,
|
||||
v8::Local<v8::Value> error);
|
||||
NODE_EXTERN void GetNodeReport(v8::Isolate* isolate,
|
||||
const char* message,
|
||||
const char* trigger,
|
||||
v8::Local<v8::Value> error,
|
||||
std::ostream& out);
|
||||
NODE_EXTERN void GetNodeReport(Environment* env,
|
||||
const char* message,
|
||||
const char* trigger,
|
||||
v8::Local<v8::Value> error,
|
||||
std::ostream& out);
|
||||
|
||||
// This returns the MultiIsolatePlatform used for an Environment or IsolateData
|
||||
// instance, if one exists.
|
||||
NODE_EXTERN MultiIsolatePlatform* GetMultiIsolatePlatform(Environment* env);
|
||||
|
@ -449,8 +449,7 @@ static void ReportFatalException(Environment* env,
|
||||
}
|
||||
|
||||
if (env->isolate_data()->options()->report_uncaught_exception) {
|
||||
report::TriggerNodeReport(
|
||||
isolate, env, report_message.c_str(), "Exception", "", error);
|
||||
TriggerNodeReport(env, report_message.c_str(), "Exception", "", error);
|
||||
}
|
||||
|
||||
if (env->options()->trace_uncaught) {
|
||||
@ -482,10 +481,6 @@ void OnFatalError(const char* location, const char* message) {
|
||||
}
|
||||
|
||||
Isolate* isolate = Isolate::TryGetCurrent();
|
||||
Environment* env = nullptr;
|
||||
if (isolate != nullptr) {
|
||||
env = Environment::GetCurrent(isolate);
|
||||
}
|
||||
bool report_on_fatalerror;
|
||||
{
|
||||
Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
|
||||
@ -493,8 +488,7 @@ void OnFatalError(const char* location, const char* message) {
|
||||
}
|
||||
|
||||
if (report_on_fatalerror) {
|
||||
report::TriggerNodeReport(
|
||||
isolate, env, message, "FatalError", "", Local<Object>());
|
||||
TriggerNodeReport(isolate, message, "FatalError", "", Local<Object>());
|
||||
}
|
||||
|
||||
fflush(stderr);
|
||||
@ -512,10 +506,6 @@ void OOMErrorHandler(const char* location, bool is_heap_oom) {
|
||||
}
|
||||
|
||||
Isolate* isolate = Isolate::TryGetCurrent();
|
||||
Environment* env = nullptr;
|
||||
if (isolate != nullptr) {
|
||||
env = Environment::GetCurrent(isolate);
|
||||
}
|
||||
bool report_on_fatalerror;
|
||||
{
|
||||
Mutex::ScopedLock lock(node::per_process::cli_options_mutex);
|
||||
@ -523,8 +513,7 @@ void OOMErrorHandler(const char* location, bool is_heap_oom) {
|
||||
}
|
||||
|
||||
if (report_on_fatalerror) {
|
||||
report::TriggerNodeReport(
|
||||
isolate, env, message, "OOMError", "", Local<Object>());
|
||||
TriggerNodeReport(isolate, message, "OOMError", "", Local<Object>());
|
||||
}
|
||||
|
||||
fflush(stderr);
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "env-inl.h"
|
||||
#include "json_utils.h"
|
||||
#include "node_report.h"
|
||||
#include "debug_utils-inl.h"
|
||||
#include "diagnosticfilename-inl.h"
|
||||
#include "env-inl.h"
|
||||
#include "json_utils.h"
|
||||
#include "node_internals.h"
|
||||
#include "node_metadata.h"
|
||||
#include "node_mutex.h"
|
||||
@ -29,8 +29,6 @@ constexpr double SEC_PER_MICROS = 1e-6;
|
||||
constexpr int MAX_FRAME_COUNT = 10;
|
||||
|
||||
namespace node {
|
||||
namespace report {
|
||||
|
||||
using node::worker::Worker;
|
||||
using v8::Array;
|
||||
using v8::Context;
|
||||
@ -53,6 +51,7 @@ using v8::TryCatch;
|
||||
using v8::V8;
|
||||
using v8::Value;
|
||||
|
||||
namespace report {
|
||||
// Internal/static function declarations
|
||||
static void WriteNodeReport(Isolate* isolate,
|
||||
Environment* env,
|
||||
@ -83,102 +82,6 @@ static void PrintRelease(JSONWriter* writer);
|
||||
static void PrintCpuInfo(JSONWriter* writer);
|
||||
static void PrintNetworkInterfaceInfo(JSONWriter* writer);
|
||||
|
||||
// External function to trigger a report, writing to file.
|
||||
std::string TriggerNodeReport(Isolate* isolate,
|
||||
Environment* env,
|
||||
const char* message,
|
||||
const char* trigger,
|
||||
const std::string& name,
|
||||
Local<Value> error) {
|
||||
std::string filename;
|
||||
|
||||
// Determine the required report filename. In order of priority:
|
||||
// 1) supplied on API 2) configured on startup 3) default generated
|
||||
if (!name.empty()) {
|
||||
// Filename was specified as API parameter.
|
||||
filename = name;
|
||||
} else {
|
||||
std::string report_filename;
|
||||
{
|
||||
Mutex::ScopedLock lock(per_process::cli_options_mutex);
|
||||
report_filename = per_process::cli_options->report_filename;
|
||||
}
|
||||
if (report_filename.length() > 0) {
|
||||
// File name was supplied via start-up option.
|
||||
filename = report_filename;
|
||||
} else {
|
||||
filename = *DiagnosticFilename(env != nullptr ? env->thread_id() : 0,
|
||||
"report", "json");
|
||||
}
|
||||
}
|
||||
|
||||
// Open the report file stream for writing. Supports stdout/err,
|
||||
// user-specified or (default) generated name
|
||||
std::ofstream outfile;
|
||||
std::ostream* outstream;
|
||||
if (filename == "stdout") {
|
||||
outstream = &std::cout;
|
||||
} else if (filename == "stderr") {
|
||||
outstream = &std::cerr;
|
||||
} else {
|
||||
std::string report_directory;
|
||||
{
|
||||
Mutex::ScopedLock lock(per_process::cli_options_mutex);
|
||||
report_directory = per_process::cli_options->report_directory;
|
||||
}
|
||||
// Regular file. Append filename to directory path if one was specified
|
||||
if (report_directory.length() > 0) {
|
||||
std::string pathname = report_directory;
|
||||
pathname += kPathSeparator;
|
||||
pathname += filename;
|
||||
outfile.open(pathname, std::ios::out | std::ios::binary);
|
||||
} else {
|
||||
outfile.open(filename, std::ios::out | std::ios::binary);
|
||||
}
|
||||
// Check for errors on the file open
|
||||
if (!outfile.is_open()) {
|
||||
std::cerr << "\nFailed to open Node.js report file: " << filename;
|
||||
|
||||
if (report_directory.length() > 0)
|
||||
std::cerr << " directory: " << report_directory;
|
||||
|
||||
std::cerr << " (errno: " << errno << ")" << std::endl;
|
||||
return "";
|
||||
}
|
||||
outstream = &outfile;
|
||||
std::cerr << "\nWriting Node.js report to file: " << filename;
|
||||
}
|
||||
|
||||
bool compact;
|
||||
{
|
||||
Mutex::ScopedLock lock(per_process::cli_options_mutex);
|
||||
compact = per_process::cli_options->report_compact;
|
||||
}
|
||||
WriteNodeReport(isolate, env, message, trigger, filename, *outstream,
|
||||
error, compact);
|
||||
|
||||
// Do not close stdout/stderr, only close files we opened.
|
||||
if (outfile.is_open()) {
|
||||
outfile.close();
|
||||
}
|
||||
|
||||
// Do not mix JSON and free-form text on stderr.
|
||||
if (filename != "stderr") {
|
||||
std::cerr << "\nNode.js report completed" << std::endl;
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
// External function to trigger a report, writing to a supplied stream.
|
||||
void GetNodeReport(Isolate* isolate,
|
||||
Environment* env,
|
||||
const char* message,
|
||||
const char* trigger,
|
||||
Local<Value> error,
|
||||
std::ostream& out) {
|
||||
WriteNodeReport(isolate, env, message, trigger, "", out, error, false);
|
||||
}
|
||||
|
||||
// Internal function to coordinate and write the various
|
||||
// sections of the report to the supplied stream
|
||||
static void WriteNodeReport(Isolate* isolate,
|
||||
@ -319,12 +222,8 @@ static void WriteNodeReport(Isolate* isolate,
|
||||
expected_results += w->RequestInterrupt([&](Environment* env) {
|
||||
std::ostringstream os;
|
||||
|
||||
GetNodeReport(env->isolate(),
|
||||
env,
|
||||
"Worker thread subreport",
|
||||
trigger,
|
||||
Local<Value>(),
|
||||
os);
|
||||
GetNodeReport(
|
||||
env, "Worker thread subreport", trigger, Local<Value>(), os);
|
||||
|
||||
Mutex::ScopedLock lock(workers_mutex);
|
||||
worker_infos.emplace_back(os.str());
|
||||
@ -884,4 +783,136 @@ static void PrintRelease(JSONWriter* writer) {
|
||||
}
|
||||
|
||||
} // namespace report
|
||||
|
||||
// External function to trigger a report, writing to file.
|
||||
std::string TriggerNodeReport(Isolate* isolate,
|
||||
const char* message,
|
||||
const char* trigger,
|
||||
const std::string& name,
|
||||
Local<Value> error) {
|
||||
Environment* env = nullptr;
|
||||
if (isolate != nullptr) {
|
||||
env = Environment::GetCurrent(isolate);
|
||||
}
|
||||
return TriggerNodeReport(env, message, trigger, name, error);
|
||||
}
|
||||
|
||||
// External function to trigger a report, writing to file.
|
||||
std::string TriggerNodeReport(Environment* env,
|
||||
const char* message,
|
||||
const char* trigger,
|
||||
const std::string& name,
|
||||
Local<Value> error) {
|
||||
std::string filename;
|
||||
|
||||
// Determine the required report filename. In order of priority:
|
||||
// 1) supplied on API 2) configured on startup 3) default generated
|
||||
if (!name.empty()) {
|
||||
// Filename was specified as API parameter.
|
||||
filename = name;
|
||||
} else {
|
||||
std::string report_filename;
|
||||
{
|
||||
Mutex::ScopedLock lock(per_process::cli_options_mutex);
|
||||
report_filename = per_process::cli_options->report_filename;
|
||||
}
|
||||
if (report_filename.length() > 0) {
|
||||
// File name was supplied via start-up option.
|
||||
filename = report_filename;
|
||||
} else {
|
||||
filename = *DiagnosticFilename(
|
||||
env != nullptr ? env->thread_id() : 0, "report", "json");
|
||||
}
|
||||
}
|
||||
|
||||
// Open the report file stream for writing. Supports stdout/err,
|
||||
// user-specified or (default) generated name
|
||||
std::ofstream outfile;
|
||||
std::ostream* outstream;
|
||||
if (filename == "stdout") {
|
||||
outstream = &std::cout;
|
||||
} else if (filename == "stderr") {
|
||||
outstream = &std::cerr;
|
||||
} else {
|
||||
std::string report_directory;
|
||||
{
|
||||
Mutex::ScopedLock lock(per_process::cli_options_mutex);
|
||||
report_directory = per_process::cli_options->report_directory;
|
||||
}
|
||||
// Regular file. Append filename to directory path if one was specified
|
||||
if (report_directory.length() > 0) {
|
||||
std::string pathname = report_directory;
|
||||
pathname += kPathSeparator;
|
||||
pathname += filename;
|
||||
outfile.open(pathname, std::ios::out | std::ios::binary);
|
||||
} else {
|
||||
outfile.open(filename, std::ios::out | std::ios::binary);
|
||||
}
|
||||
// Check for errors on the file open
|
||||
if (!outfile.is_open()) {
|
||||
std::cerr << "\nFailed to open Node.js report file: " << filename;
|
||||
|
||||
if (report_directory.length() > 0)
|
||||
std::cerr << " directory: " << report_directory;
|
||||
|
||||
std::cerr << " (errno: " << errno << ")" << std::endl;
|
||||
return "";
|
||||
}
|
||||
outstream = &outfile;
|
||||
std::cerr << "\nWriting Node.js report to file: " << filename;
|
||||
}
|
||||
|
||||
bool compact;
|
||||
{
|
||||
Mutex::ScopedLock lock(per_process::cli_options_mutex);
|
||||
compact = per_process::cli_options->report_compact;
|
||||
}
|
||||
|
||||
Isolate* isolate = nullptr;
|
||||
if (env != nullptr) {
|
||||
isolate = env->isolate();
|
||||
}
|
||||
report::WriteNodeReport(
|
||||
isolate, env, message, trigger, filename, *outstream, error, compact);
|
||||
|
||||
// Do not close stdout/stderr, only close files we opened.
|
||||
if (outfile.is_open()) {
|
||||
outfile.close();
|
||||
}
|
||||
|
||||
// Do not mix JSON and free-form text on stderr.
|
||||
if (filename != "stderr") {
|
||||
std::cerr << "\nNode.js report completed" << std::endl;
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
// External function to trigger a report, writing to a supplied stream.
|
||||
void GetNodeReport(Isolate* isolate,
|
||||
const char* message,
|
||||
const char* trigger,
|
||||
Local<Value> error,
|
||||
std::ostream& out) {
|
||||
Environment* env = nullptr;
|
||||
if (isolate != nullptr) {
|
||||
env = Environment::GetCurrent(isolate);
|
||||
}
|
||||
report::WriteNodeReport(
|
||||
isolate, env, message, trigger, "", out, error, false);
|
||||
}
|
||||
|
||||
// External function to trigger a report, writing to a supplied stream.
|
||||
void GetNodeReport(Environment* env,
|
||||
const char* message,
|
||||
const char* trigger,
|
||||
Local<Value> error,
|
||||
std::ostream& out) {
|
||||
Isolate* isolate = nullptr;
|
||||
if (env != nullptr) {
|
||||
isolate = env->isolate();
|
||||
}
|
||||
report::WriteNodeReport(
|
||||
isolate, env, message, trigger, "", out, error, false);
|
||||
}
|
||||
|
||||
} // namespace node
|
||||
|
@ -14,24 +14,10 @@
|
||||
#endif
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace node {
|
||||
namespace report {
|
||||
|
||||
// Function declarations - functions in src/node_report.cc
|
||||
std::string TriggerNodeReport(v8::Isolate* isolate,
|
||||
Environment* env,
|
||||
const char* message,
|
||||
const char* trigger,
|
||||
const std::string& name,
|
||||
v8::Local<v8::Value> error);
|
||||
void GetNodeReport(v8::Isolate* isolate,
|
||||
Environment* env,
|
||||
const char* message,
|
||||
const char* trigger,
|
||||
v8::Local<v8::Value> error,
|
||||
std::ostream& out);
|
||||
|
||||
// Function declarations - utility functions in src/node_report_utils.cc
|
||||
void WalkHandle(uv_handle_t* h, void* arg);
|
||||
|
||||
|
@ -44,8 +44,7 @@ void WriteReport(const FunctionCallbackInfo<Value>& info) {
|
||||
else
|
||||
error = Local<Value>();
|
||||
|
||||
filename = TriggerNodeReport(
|
||||
isolate, env, *message, *trigger, filename, error);
|
||||
filename = TriggerNodeReport(env, *message, *trigger, filename, error);
|
||||
// Return value is the report filename
|
||||
info.GetReturnValue().Set(
|
||||
String::NewFromUtf8(isolate, filename.c_str()).ToLocalChecked());
|
||||
@ -65,8 +64,7 @@ void GetReport(const FunctionCallbackInfo<Value>& info) {
|
||||
else
|
||||
error = Local<Object>();
|
||||
|
||||
GetNodeReport(
|
||||
isolate, env, "JavaScript API", __func__, error, out);
|
||||
GetNodeReport(env, "JavaScript API", __func__, error, out);
|
||||
|
||||
// Return value is the contents of a report as a string.
|
||||
info.GetReturnValue().Set(
|
||||
|
53
test/addons/report-api/binding.cc
Normal file
53
test/addons/report-api/binding.cc
Normal file
@ -0,0 +1,53 @@
|
||||
#include <node.h>
|
||||
#include <v8.h>
|
||||
|
||||
using v8::FunctionCallbackInfo;
|
||||
using v8::Isolate;
|
||||
using v8::Local;
|
||||
using v8::Object;
|
||||
using v8::Value;
|
||||
|
||||
void TriggerReport(const FunctionCallbackInfo<Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
|
||||
node::TriggerNodeReport(
|
||||
isolate, "FooMessage", "BarTrigger", std::string(), Local<Value>());
|
||||
}
|
||||
|
||||
void TriggerReportNoIsolate(const FunctionCallbackInfo<Value>& args) {
|
||||
node::TriggerNodeReport(static_cast<Isolate*>(nullptr),
|
||||
"FooMessage",
|
||||
"BarTrigger",
|
||||
std::string(),
|
||||
Local<Value>());
|
||||
}
|
||||
|
||||
void TriggerReportEnv(const FunctionCallbackInfo<Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
|
||||
node::TriggerNodeReport(
|
||||
node::GetCurrentEnvironment(isolate->GetCurrentContext()),
|
||||
"FooMessage",
|
||||
"BarTrigger",
|
||||
std::string(),
|
||||
Local<Value>());
|
||||
}
|
||||
|
||||
void TriggerReportNoEnv(const FunctionCallbackInfo<Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
|
||||
node::TriggerNodeReport(static_cast<node::Environment*>(nullptr),
|
||||
"FooMessage",
|
||||
"BarTrigger",
|
||||
std::string(),
|
||||
Local<Value>());
|
||||
}
|
||||
|
||||
void init(Local<Object> exports) {
|
||||
NODE_SET_METHOD(exports, "triggerReport", TriggerReport);
|
||||
NODE_SET_METHOD(exports, "triggerReportNoIsolate", TriggerReportNoIsolate);
|
||||
NODE_SET_METHOD(exports, "triggerReportEnv", TriggerReportEnv);
|
||||
NODE_SET_METHOD(exports, "triggerReportNoEnv", TriggerReportNoEnv);
|
||||
}
|
||||
|
||||
NODE_MODULE(NODE_GYP_MODULE_NAME, init)
|
9
test/addons/report-api/binding.gyp
Normal file
9
test/addons/report-api/binding.gyp
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'binding',
|
||||
'sources': [ 'binding.cc' ],
|
||||
'includes': ['../common.gypi'],
|
||||
}
|
||||
]
|
||||
}
|
44
test/addons/report-api/test.js
Normal file
44
test/addons/report-api/test.js
Normal file
@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../../common');
|
||||
const assert = require('assert');
|
||||
const path = require('path');
|
||||
const helper = require('../../common/report.js');
|
||||
const tmpdir = require('../../common/tmpdir');
|
||||
|
||||
const binding = path.resolve(__dirname, `./build/${common.buildType}/binding`);
|
||||
const addon = require(binding);
|
||||
|
||||
function myAddonMain(method, hasJavaScriptFrames) {
|
||||
tmpdir.refresh();
|
||||
process.report.directory = tmpdir.path;
|
||||
|
||||
addon[method]();
|
||||
|
||||
const reports = helper.findReports(process.pid, tmpdir.path);
|
||||
assert.strictEqual(reports.length, 1);
|
||||
|
||||
const report = reports[0];
|
||||
helper.validate(report);
|
||||
|
||||
const content = require(report);
|
||||
assert.strictEqual(content.header.event, 'FooMessage');
|
||||
assert.strictEqual(content.header.trigger, 'BarTrigger');
|
||||
|
||||
// Check that the javascript stack is present.
|
||||
if (hasJavaScriptFrames) {
|
||||
assert.strictEqual(content.javascriptStack.stack.findIndex((frame) => frame.match('myAddonMain')), 0);
|
||||
} else {
|
||||
assert.strictEqual(content.javascriptStack, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
const methods = [
|
||||
['triggerReport', true],
|
||||
['triggerReportNoIsolate', false],
|
||||
['triggerReportEnv', true],
|
||||
['triggerReportNoEnv', false],
|
||||
];
|
||||
for (const [method, hasJavaScriptFrames] of methods) {
|
||||
myAddonMain(method, hasJavaScriptFrames);
|
||||
}
|
125
test/cctest/test_report.cc
Normal file
125
test/cctest/test_report.cc
Normal file
@ -0,0 +1,125 @@
|
||||
#include "node.h"
|
||||
|
||||
#include <string>
|
||||
#include "gtest/gtest.h"
|
||||
#include "node_test_fixture.h"
|
||||
|
||||
using node::Environment;
|
||||
using v8::Context;
|
||||
using v8::Function;
|
||||
using v8::FunctionCallbackInfo;
|
||||
using v8::HandleScope;
|
||||
using v8::Isolate;
|
||||
using v8::Local;
|
||||
using v8::SealHandleScope;
|
||||
using v8::String;
|
||||
using v8::Value;
|
||||
|
||||
bool report_callback_called = false;
|
||||
|
||||
class ReportTest : public EnvironmentTestFixture {
|
||||
private:
|
||||
void TearDown() override {
|
||||
NodeTestFixture::TearDown();
|
||||
report_callback_called = false;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ReportTest, ReportWithNoIsolate) {
|
||||
SealHandleScope handle_scope(isolate_);
|
||||
|
||||
std::ostringstream oss;
|
||||
node::GetNodeReport(static_cast<Isolate*>(nullptr),
|
||||
"FooMessage",
|
||||
"BarTrigger",
|
||||
Local<Value>(),
|
||||
oss);
|
||||
|
||||
// Simple checks on the output string contains the message and trigger.
|
||||
std::string actual = oss.str();
|
||||
EXPECT_NE(actual.find("FooMessage"), std::string::npos);
|
||||
EXPECT_NE(actual.find("BarTrigger"), std::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(ReportTest, ReportWithNoEnv) {
|
||||
SealHandleScope handle_scope(isolate_);
|
||||
|
||||
std::ostringstream oss;
|
||||
node::GetNodeReport(static_cast<Environment*>(nullptr),
|
||||
"FooMessage",
|
||||
"BarTrigger",
|
||||
Local<Value>(),
|
||||
oss);
|
||||
|
||||
// Simple checks on the output string contains the message and trigger.
|
||||
std::string actual = oss.str();
|
||||
EXPECT_NE(actual.find("FooMessage"), std::string::npos);
|
||||
EXPECT_NE(actual.find("BarTrigger"), std::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(ReportTest, ReportWithIsolate) {
|
||||
const HandleScope handle_scope(isolate_);
|
||||
const Argv argv;
|
||||
Env env{handle_scope, argv};
|
||||
|
||||
Local<Context> context = isolate_->GetCurrentContext();
|
||||
Local<Function> fn =
|
||||
Function::New(context, [](const FunctionCallbackInfo<Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
HandleScope scope(isolate);
|
||||
|
||||
std::ostringstream oss;
|
||||
node::GetNodeReport(isolate, "FooMessage", "BarTrigger", args[0], oss);
|
||||
|
||||
// Simple checks on the output string contains the message and trigger.
|
||||
std::string actual = oss.str();
|
||||
EXPECT_NE(actual.find("FooMessage"), std::string::npos);
|
||||
EXPECT_NE(actual.find("BarTrigger"), std::string::npos);
|
||||
|
||||
report_callback_called = true;
|
||||
}).ToLocalChecked();
|
||||
|
||||
context->Global()
|
||||
->Set(context, String::NewFromUtf8(isolate_, "foo").ToLocalChecked(), fn)
|
||||
.FromJust();
|
||||
|
||||
node::LoadEnvironment(*env, "foo()").ToLocalChecked();
|
||||
|
||||
EXPECT_TRUE(report_callback_called);
|
||||
}
|
||||
|
||||
TEST_F(ReportTest, ReportWithEnv) {
|
||||
const HandleScope handle_scope(isolate_);
|
||||
const Argv argv;
|
||||
Env env{handle_scope, argv};
|
||||
|
||||
Local<Context> context = isolate_->GetCurrentContext();
|
||||
Local<Function> fn =
|
||||
Function::New(context, [](const FunctionCallbackInfo<Value>& args) {
|
||||
Isolate* isolate = args.GetIsolate();
|
||||
HandleScope scope(isolate);
|
||||
|
||||
std::ostringstream oss;
|
||||
node::GetNodeReport(
|
||||
node::GetCurrentEnvironment(isolate->GetCurrentContext()),
|
||||
"FooMessage",
|
||||
"BarTrigger",
|
||||
args[0],
|
||||
oss);
|
||||
|
||||
// Simple checks on the output string contains the message and trigger.
|
||||
std::string actual = oss.str();
|
||||
EXPECT_NE(actual.find("FooMessage"), std::string::npos);
|
||||
EXPECT_NE(actual.find("BarTrigger"), std::string::npos);
|
||||
|
||||
report_callback_called = true;
|
||||
}).ToLocalChecked();
|
||||
|
||||
context->Global()
|
||||
->Set(context, String::NewFromUtf8(isolate_, "foo").ToLocalChecked(), fn)
|
||||
.FromJust();
|
||||
|
||||
node::LoadEnvironment(*env, "foo()").ToLocalChecked();
|
||||
|
||||
EXPECT_TRUE(report_callback_called);
|
||||
}
|
Loading…
Reference in New Issue
Block a user