diff --git a/base/test/launcher/teamcity_service_messages.cc b/base/test/launcher/teamcity_service_messages.cc index 618b54634ac..b8eafe09ab8 100644 --- a/base/test/launcher/teamcity_service_messages.cc +++ b/base/test/launcher/teamcity_service_messages.cc @@ -53,18 +53,22 @@ class EscapedValue { TeamcityServiceMessages::Message::Message(std::ostream& ostream, std::string_view name) : ostream_(ostream) { - (*ostream_) << "##teamcity[" << name; + // Use stringstream to format the message before writing it to stdout. + sstream_ << "##teamcity[" << name; } TeamcityServiceMessages::Message::~Message() { - (*ostream_) << "]" << std::endl; + sstream_ << "]" << std::endl; + // Important: output into stdout in a single call to not mix with outputs from + // other threads. + (*ostream_) << sstream_.str() << std::flush; } TeamcityServiceMessages::Message& TeamcityServiceMessages::Message::WriteProperty(std::string_view name, std::string_view value) { if (!value.empty()) { - (*ostream_) << " " << name << "='" << EscapedValue(value) << "'"; + sstream_ << " " << name << "='" << EscapedValue(value) << "'"; } return *this; } diff --git a/base/test/launcher/teamcity_service_messages.h b/base/test/launcher/teamcity_service_messages.h index 8107f1a4106..7713cb4a809 100644 --- a/base/test/launcher/teamcity_service_messages.h +++ b/base/test/launcher/teamcity_service_messages.h @@ -7,6 +7,7 @@ #define BRAVE_BASE_TEST_LAUNCHER_TEAMCITY_SERVICE_MESSAGES_H_ #include +#include #include #include "base/memory/raw_ref.h" @@ -48,6 +49,7 @@ class TeamcityServiceMessages { private: raw_ref ostream_; + std::ostringstream sstream_; }; raw_ref ostream_; diff --git a/build/commands/lib/test.js b/build/commands/lib/test.js index 1afb0f856d8..17bab943cc7 100644 --- a/build/commands/lib/test.js +++ b/build/commands/lib/test.js @@ -164,6 +164,10 @@ const runTests = (passthroughArgs, suite, buildConfig, options) => { `--avd-config tools/android/avd/proto/generic_android${options.android_test_emulator_version}.textpb`) } let runOptions = config.defaultOptions + if (config.isTeamcity) { + // Stdout and stderr must be separate for a test launcher. + runOptions.stdio = 'inherit' + } if (options.output) // When test results are saved to a file, callers (such as CI) generate // and analyze test reports as a next step. These callers are typically