in src/bazel/bazelTestUtils.ts [85:188]
export async function goTestWithBazel(
testconfig: TestConfig,
debugConfig?: vscode.DebugConfiguration,
coverageHandler?: GoCoverageHandler
): Promise<RunResult> {
const outputChannel = testconfig.outputChannel ? testconfig.outputChannel : testOutputChannel;
// IDE setup tasks prior to the run.
if (runningTestProcesses.length < 1) outputChannel.clear();
if (testconfig.goConfig['disableConcurrentTests'] || debugConfig) await cancelRunningTests();
if (!testconfig.background) outputChannel.show(true);
const testType: string = testconfig.isBenchmark ? 'Benchmarks' : 'Tests';
// compute test target package and generate full args.
const { targets, currentGoWorkspace } = await getTestTargetPackages(testconfig, outputChannel);
const currentWorkingDirectory = currentGoWorkspace ? currentGoWorkspace : testconfig.dir; // Run from test location if worskpace not found
const bazelTargets = await getBazelTargetsFromPackages(testconfig, targets, currentWorkingDirectory, debugConfig);
const buildEventsFile = path.join(os.tmpdir(), `build_events_${hash(outputChannel.name)}`); // Output channel name provides unique timestamp for temp file.
const bazelArgs = getBazelArgs(testconfig, bazelTargets, buildEventsFile, debugConfig);
outputChannel.appendLine(['Running command:', 'bazel', ...bazelArgs].join(' '));
let testResult = {};
try {
testResult = await new Promise<RunResult>((resolve) => {
// TODO: Add support of test environment variables. IDE-73
const testProcess = cp.exec(['bazel', ...bazelArgs].join(' '), { cwd: currentWorkingDirectory });
const outBuf = new LineBuffer();
const errBuf = new LineBuffer();
testconfig.cancel?.onCancellationRequested(() => killProcessTree(testProcess));
// bazel test emits test results on stdout
// TODO: filter and append only relevant lines to improve readability of output. IDE-65.
outBuf.onLine((line) => {
outputChannel.appendLine(expandFilePathInOutput(line, testconfig.dir));
// In debug mode, resolve the promise once the API server is listening, so that the debugger can attach.
if (debugConfig && line.startsWith('API server listening at:')) resolve({ debugReady: true });
});
outBuf.onDone((last) => {
last && outputChannel.appendLine(expandFilePathInOutput(last, testconfig.dir));
});
// bazel test emits build errors on stderr, which contain paths relative to the cwd
errBuf.onLine((line) => outputChannel.appendLine(expandFilePathInOutput(line, testconfig.dir)));
errBuf.onDone((last) => last && outputChannel.appendLine(expandFilePathInOutput(last, testconfig.dir)));
testProcess.stdout?.on('data', (chunk) => outBuf.append(chunk.toString()));
testProcess.stderr?.on('data', (chunk) => errBuf.append(chunk.toString()));
statusBarItem.show();
testProcess.on('close', async () => {
outBuf.done();
errBuf.done();
const index = runningTestProcesses.indexOf(testProcess, 0);
if (index > -1) runningTestProcesses.splice(index, 1);
const buildEventOutputs = await processBuildEvents(buildEventsFile, outputChannel);
if (testconfig.goTestOutputConsumer)
await processTestResultXML(
buildEventOutputs.testXMLPaths,
outputChannel,
testconfig.goTestOutputConsumer
);
if (
testconfig.applyCodeCoverage &&
buildEventOutputs.localExecRoot &&
buildEventOutputs.exitCode === 0 // Combined coverage file is provided only when tests pass.
) {
await coverageHandler?.processCoverProfile({
coverProfilePath: path.join(
buildEventOutputs.localExecRoot,
'/bazel-out/_coverage/_coverage_report.dat'
),
bazelWorkspaceRoot: buildEventOutputs.workspaceDirectory,
currentGoWorkspace: currentWorkingDirectory,
targetPackages: targets,
generatedFilePrefix: buildEventOutputs.genDir || ''
});
}
resolve({
exitCode: buildEventOutputs.exitCode,
message: buildEventOutputs.errorMessages.join('\n')
});
if (!runningTestProcesses.length) statusBarItem.hide();
});
runningTestProcesses.push(testProcess);
});
} catch (err) {
outputChannel.appendLine(`Error: ${testType} failed.`);
if (err instanceof Error) outputChannel.appendLine((err as Error).message);
}
return testResult;
}