export async function goTestWithBazel()

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;
}