aboutsummaryrefslogtreecommitdiff
path: root/lib/internal/coverage-gen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/internal/coverage-gen')
-rw-r--r--lib/internal/coverage-gen/with_instrumentation.js36
-rw-r--r--lib/internal/coverage-gen/with_profiler.js84
2 files changed, 120 insertions, 0 deletions
diff --git a/lib/internal/coverage-gen/with_instrumentation.js b/lib/internal/coverage-gen/with_instrumentation.js
new file mode 100644
index 0000000000..711a3c3f12
--- /dev/null
+++ b/lib/internal/coverage-gen/with_instrumentation.js
@@ -0,0 +1,36 @@
+'use strict';
+
+// This file contains hooks for nyc instrumented lib/ files to collect
+// JS coverage for core.
+// See `make coverage-build`.
+function writeCoverage() {
+ if (!global.__coverage__) {
+ return;
+ }
+
+ const path = require('path');
+ const { mkdirSync, writeFileSync } = require('fs');
+
+ const dirname = path.join(path.dirname(process.execPath), '.coverage');
+ const filename = `coverage-${process.pid}-${Date.now()}.json`;
+ try {
+ mkdirSync(dirname);
+ } catch (err) {
+ if (err.code !== 'EEXIST') {
+ console.error(err);
+ return;
+ }
+ }
+
+ const target = path.join(dirname, filename);
+ const coverageInfo = JSON.stringify(global.__coverage__);
+ try {
+ writeFileSync(target, coverageInfo);
+ } catch (err) {
+ console.error(err);
+ }
+}
+
+module.exports = {
+ writeCoverage
+};
diff --git a/lib/internal/coverage-gen/with_profiler.js b/lib/internal/coverage-gen/with_profiler.js
new file mode 100644
index 0000000000..6b17073939
--- /dev/null
+++ b/lib/internal/coverage-gen/with_profiler.js
@@ -0,0 +1,84 @@
+'use strict';
+
+// Implements coverage collection exposed by the `NODE_V8_COVERAGE`
+// environment variable which can also be used in the user land.
+
+let coverageConnection = null;
+let coverageDirectory;
+
+function writeCoverage() {
+ if (!coverageConnection && coverageDirectory) {
+ return;
+ }
+
+ const { join } = require('path');
+ const { mkdirSync, writeFileSync } = require('fs');
+ const { threadId } = require('internal/worker');
+
+ const filename = `coverage-${process.pid}-${Date.now()}-${threadId}.json`;
+ try {
+ mkdirSync(coverageDirectory, { recursive: true });
+ } catch (err) {
+ if (err.code !== 'EEXIST') {
+ console.error(err);
+ return;
+ }
+ }
+
+ const target = join(coverageDirectory, filename);
+ try {
+ disableAllAsyncHooks();
+ let msg;
+ coverageConnection._coverageCallback = function(_msg) {
+ msg = _msg;
+ };
+ coverageConnection.dispatch(JSON.stringify({
+ id: 3,
+ method: 'Profiler.takePreciseCoverage'
+ }));
+ const coverageInfo = JSON.parse(msg).result;
+ writeFileSync(target, JSON.stringify(coverageInfo));
+ } catch (err) {
+ console.error(err);
+ } finally {
+ coverageConnection.disconnect();
+ coverageConnection = null;
+ }
+}
+
+function disableAllAsyncHooks() {
+ const { getHookArrays } = require('internal/async_hooks');
+ const [hooks_array] = getHookArrays();
+ hooks_array.forEach((hook) => { hook.disable(); });
+}
+
+function startCoverageCollection() {
+ const { Connection } = internalBinding('inspector');
+ coverageConnection = new Connection((res) => {
+ if (coverageConnection._coverageCallback) {
+ coverageConnection._coverageCallback(res);
+ }
+ });
+ coverageConnection.dispatch(JSON.stringify({
+ id: 1,
+ method: 'Profiler.enable'
+ }));
+ coverageConnection.dispatch(JSON.stringify({
+ id: 2,
+ method: 'Profiler.startPreciseCoverage',
+ params: {
+ callCount: true,
+ detailed: true
+ }
+ }));
+}
+
+function setCoverageDirectory(dir) {
+ coverageDirectory = dir;
+}
+
+module.exports = {
+ startCoverageCollection,
+ writeCoverage,
+ setCoverageDirectory
+};