tftsr-devops_investigation/node_modules/mocha/lib/nodejs/worker.js

152 lines
4.3 KiB
JavaScript
Raw Normal View History

feat: initial implementation of TFTSR IT Triage & RCA application Implements Phases 1-8 of the TFTSR implementation plan. Rust backend (Tauri 2.x, src-tauri/): - Multi-provider AI: OpenAI-compatible, Anthropic, Gemini, Mistral, Ollama - PII detection engine: 11 regex patterns with overlap resolution - SQLCipher AES-256 encrypted database with 10 versioned migrations - 28 Tauri IPC commands for triage, analysis, document, and system ops - Ollama: hardware probe, model recommendations, pull/delete with events - RCA and blameless post-mortem Markdown document generators - PDF export via printpdf - Audit log: SHA-256 hash of every external data send - Integration stubs for Confluence, ServiceNow, Azure DevOps (v0.2) Frontend (React 18 + TypeScript + Vite, src/): - 9 pages: full triage workflow NewIssue→LogUpload→Triage→Resolution→RCA→Postmortem→History+Settings - 7 components: ChatWindow, TriageProgress, PiiDiffViewer, DocEditor, HardwareReport, ModelSelector, UI primitives - 3 Zustand stores: session, settings (persisted), history - Type-safe tauriCommands.ts matching Rust backend types exactly - 8 IT domain system prompts (Linux, Windows, Network, K8s, DB, Virt, HW, Obs) DevOps: - .woodpecker/test.yml: rustfmt, clippy, cargo test, tsc, vitest on every push - .woodpecker/release.yml: linux/amd64 + linux/arm64 builds, Gogs release upload Verified: - cargo check: zero errors - tsc --noEmit: zero errors - vitest run: 13/13 unit tests passing Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 03:36:25 +00:00
/**
* A worker process. Consumes {@link module:reporters/parallel-buffered} reporter.
* @module worker
* @private
*/
'use strict';
const {
createInvalidArgumentTypeError,
createInvalidArgumentValueError
} = require('../errors');
const workerpool = require('workerpool');
const Mocha = require('../mocha');
const {handleRequires, validateLegacyPlugin} = require('../cli/run-helpers');
const d = require('debug');
const debug = d.debug(`mocha:parallel:worker:${process.pid}`);
const isDebugEnabled = d.enabled(`mocha:parallel:worker:${process.pid}`);
const {serialize} = require('./serializer');
const {setInterval, clearInterval} = global;
let rootHooks;
if (workerpool.isMainThread) {
throw new Error(
'This script is intended to be run as a worker (by the `workerpool` package).'
);
}
/**
* Initializes some stuff on the first call to {@link run}.
*
* Handles `--require` and `--ui`. Does _not_ handle `--reporter`,
* as only the `Buffered` reporter is used.
*
* **This function only runs once per worker**; it overwrites itself with a no-op
* before returning.
*
* @param {Options} argv - Command-line options
*/
let bootstrap = async argv => {
// globalSetup and globalTeardown do not run in workers
const plugins = await handleRequires(argv.require, {
ignoredPlugins: ['mochaGlobalSetup', 'mochaGlobalTeardown']
});
validateLegacyPlugin(argv, 'ui', Mocha.interfaces);
rootHooks = plugins.rootHooks;
bootstrap = () => {};
debug('bootstrap(): finished with args: %O', argv);
};
/**
* Runs a single test file in a worker thread.
* @param {string} filepath - Filepath of test file
* @param {string} [serializedOptions] - **Serialized** options. This string will be eval'd!
* @see https://npm.im/serialize-javascript
* @returns {Promise<{failures: number, events: BufferedEvent[]}>} - Test
* failure count and list of events.
*/
async function run(filepath, serializedOptions = '{}') {
if (!filepath) {
throw createInvalidArgumentTypeError(
'Expected a non-empty "filepath" argument',
'file',
'string'
);
}
debug('run(): running test file %s', filepath);
if (typeof serializedOptions !== 'string') {
throw createInvalidArgumentTypeError(
'run() expects second parameter to be a string which was serialized by the `serialize-javascript` module',
'serializedOptions',
'string'
);
}
let argv;
try {
// eslint-disable-next-line no-eval
argv = eval('(' + serializedOptions + ')');
} catch (err) {
throw createInvalidArgumentValueError(
'run() was unable to deserialize the options',
'serializedOptions',
serializedOptions
);
}
const opts = Object.assign({ui: 'bdd'}, argv, {
// if this was true, it would cause infinite recursion.
parallel: false,
// this doesn't work in parallel mode
forbidOnly: true,
// it's useful for a Mocha instance to know if it's running in a worker process.
isWorker: true
});
await bootstrap(opts);
opts.rootHooks = rootHooks;
const mocha = new Mocha(opts).addFile(filepath);
try {
await mocha.loadFilesAsync();
} catch (err) {
debug('run(): could not load file %s: %s', filepath, err);
throw err;
}
return new Promise((resolve, reject) => {
let debugInterval;
/* istanbul ignore next */
if (isDebugEnabled) {
debugInterval = setInterval(() => {
debug('run(): still running %s...', filepath);
}, 5000).unref();
}
mocha.run(result => {
// Runner adds these; if we don't remove them, we'll get a leak.
process.removeAllListeners('uncaughtException');
process.removeAllListeners('unhandledRejection');
try {
const serialized = serialize(result);
debug(
'run(): completed run with %d test failures; returning to main process',
typeof result.failures === 'number' ? result.failures : 0
);
resolve(serialized);
} catch (err) {
// TODO: figure out exactly what the sad path looks like here.
// rejection should only happen if an error is "unrecoverable"
debug('run(): serialization failed; rejecting: %O', err);
reject(err);
} finally {
clearInterval(debugInterval);
}
});
});
}
// this registers the `run` function.
workerpool.worker({run});
debug('started worker process');
// for testing
exports.run = run;