From f2c2d345d4a3ada3031b1399374a9adf46f0997f Mon Sep 17 00:00:00 2001 From: Wang Xiaofeng Date: Mon, 24 Aug 2026 00:35:34 +0800 Subject: [PATCH 1/8] Run Bazel tests in parallel in CI --- .github/workflows/ci-linux.yml | 15 ++++++++++++--- test/BUILD.bazel | 11 +++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index 70414a460a..fa13697030 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -203,7 +203,12 @@ jobs: # real server (e.g. brpc_redis_unittest) actually run under bazel instead # of skipping. Same shared action the make-based unittest jobs use. - uses: ./.github/actions/install-essential-dependencies - - run: bazel test --config=rdma --config=ubring //test/... + - run: | + bazel test --test_output=errors \ + --local_test_jobs=3 \ + --config=rdma \ + --config=ubring \ + //test/... gcc-compile-with-bazel-all-options: runs-on: ubuntu-22.04 @@ -256,7 +261,9 @@ jobs: # actually run under bazel (see gcc-unittest-with-bazel). - uses: ./.github/actions/install-essential-dependencies - run: | - bazel test --test_output=streamed \ + # Keep test targets parallel; streamed output forces local serial execution. + bazel test --test_output=errors \ + --local_test_jobs=3 \ --action_env=CC=clang \ --config=rdma \ --config=ubring \ @@ -384,7 +391,9 @@ jobs: grep -qE "bazel_dep\(name = ['\"]protobuf['\"], version = ['\"]${TEST_PROTOBUF_VERSION}['\"]" MODULE.bazel \ || { echo "ERROR: failed to override protobuf version in MODULE.bazel to ${TEST_PROTOBUF_VERSION}"; exit 1; } - run: | - bazel test --action_env=CC=clang --config=rdma --config=ubring \ + bazel test --test_output=errors \ + --local_test_jobs=3 \ + --action_env=CC=clang --config=rdma --config=ubring \ --define with_bthread_tracer=true \ --define with_babylon_counter=true \ //test/... diff --git a/test/BUILD.bazel b/test/BUILD.bazel index 27d63aed81..a8fd300de3 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -207,6 +207,11 @@ generate_unittests( "@com_google_googletest//:gtest_main", ] + TCMALLOC_DEP_UNLESS_ASAN, copts = COPTS, + per_test_tags = { + "bthread_cond_unittest.cpp": ["exclusive"], + "bthread_fd_unittest.cpp": ["exclusive"], + "bthread_unittest.cpp": ["exclusive"], + }, ) # Expose unit-test data files (cert*, jsonout) at the runfiles workspace root @@ -252,8 +257,14 @@ generate_unittests( # PATH, apt-installed by install-essential-dependencies); tag them the same # so bazel never serves a cached pass that actually skipped and runs them # outside the sandbox where mysqld and loopback are visible. + # Run timing-sensitive event-loop and socket tests without competing test + # processes. Their assertions intentionally depend on prompt scheduling. per_test_tags = { + "brpc_event_dispatcher_unittest.cpp": ["exclusive"], + "brpc_http_rpc_protocol_unittest.cpp": ["exclusive"], "brpc_redis_unittest.cpp": ["external", "local"], + "brpc_server_unittest.cpp": ["exclusive"], + "brpc_socket_unittest.cpp": ["exclusive"], "brpc_mysql_auth_handshake_unittest.cpp": ["external", "local"], "brpc_mysql_connection_type_unittest.cpp": ["external", "local"], "brpc_mysql_prepared_integration_unittest.cpp": ["external", "local"], From 002b10ec5a8267982ae3e8902fb23fe617cd9bae Mon Sep 17 00:00:00 2001 From: Wang Xiaofeng Date: Mon, 24 Aug 2026 09:23:19 +0800 Subject: [PATCH 2/8] Use an ephemeral port in interceptor test --- test/brpc_interceptor_unittest.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/test/brpc_interceptor_unittest.cpp b/test/brpc_interceptor_unittest.cpp index ca9ab40f11..98034b5d8c 100644 --- a/test/brpc_interceptor_unittest.cpp +++ b/test/brpc_interceptor_unittest.cpp @@ -38,7 +38,6 @@ int main(int argc, char* argv[]) { const int EREJECT = 4000; int g_index = 0; -const int port = 8613; const std::string EXP_REQUEST = "hello"; const std::string EXP_RESPONSE = "world"; const std::string NSHEAD_EXP_RESPONSE = "error"; @@ -108,7 +107,7 @@ class InterceptorTest : public ::testing::Test { options.interceptor = new MyInterceptor; options.nshead_service = new MyNsheadProtocol; options.server_owns_interceptor = true; - EXPECT_EQ(0, _server.Start(port, &options)); + EXPECT_EQ(0, _server.Start(0, &options)); } ~InterceptorTest() override = default; @@ -143,7 +142,7 @@ TEST_F(InterceptorTest, sanity) { { brpc::Channel channel; brpc::ChannelOptions options; - ASSERT_EQ(0, channel.Init("localhost", port, &options)); + ASSERT_EQ(0, channel.Init(_server.listen_address(), &options)); test::EchoService_Stub stub(&channel); CallMethod(stub, req, res); } @@ -153,7 +152,7 @@ TEST_F(InterceptorTest, sanity) { brpc::Channel channel; brpc::ChannelOptions options; options.protocol = brpc::PROTOCOL_HTTP; - ASSERT_EQ(0, channel.Init("localhost", port, &options)); + ASSERT_EQ(0, channel.Init(_server.listen_address(), &options)); test::EchoService_Stub stub(&channel); // Set the x-bd-error-code header of http response to brpc error code. brpc::policy::FLAGS_use_http_error_code = true; @@ -165,7 +164,7 @@ TEST_F(InterceptorTest, sanity) { brpc::Channel channel; brpc::ChannelOptions options; options.protocol = brpc::PROTOCOL_HULU_PBRPC; - ASSERT_EQ(0, channel.Init("localhost", port, &options)); + ASSERT_EQ(0, channel.Init(_server.listen_address(), &options)); test::EchoService_Stub stub(&channel); CallMethod(stub, req, res); } @@ -175,7 +174,7 @@ TEST_F(InterceptorTest, sanity) { brpc::Channel channel; brpc::ChannelOptions options; options.protocol = brpc::PROTOCOL_SOFA_PBRPC; - ASSERT_EQ(0, channel.Init("localhost", port, &options)); + ASSERT_EQ(0, channel.Init(_server.listen_address(), &options)); test::EchoService_Stub stub(&channel); CallMethod(stub, req, res); } @@ -185,7 +184,7 @@ TEST_F(InterceptorTest, sanity) { brpc::Channel channel; brpc::ChannelOptions options; options.protocol = brpc::PROTOCOL_NSHEAD; - ASSERT_EQ(0, channel.Init("localhost", port, &options)); + ASSERT_EQ(0, channel.Init(_server.listen_address(), &options)); brpc::NsheadMessage request; for (g_index = 0; g_index < 1000; ++g_index) { brpc::Controller cntl; @@ -198,4 +197,4 @@ TEST_F(InterceptorTest, sanity) { } } } -} \ No newline at end of file +} From c4f8ff12a4bd8f1d2ccb1e1fd620505bc065d35e Mon Sep 17 00:00:00 2001 From: Wang Xiaofeng Date: Mon, 24 Aug 2026 09:23:37 +0800 Subject: [PATCH 3/8] Use an ephemeral port in HTTP expect test --- test/brpc_http_rpc_protocol_unittest.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/brpc_http_rpc_protocol_unittest.cpp b/test/brpc_http_rpc_protocol_unittest.cpp index e0c7b741dd..f23bbfb73a 100644 --- a/test/brpc_http_rpc_protocol_unittest.cpp +++ b/test/brpc_http_rpc_protocol_unittest.cpp @@ -2767,14 +2767,12 @@ void ReadOneResponse(brpc::SocketUniquePtr& sock, } TEST_F(HttpTest, http_expect) { - const int port = 8923; brpc::Server server; HttpServiceImpl svc; EXPECT_EQ(0, server.AddService(&svc, brpc::SERVER_DOESNT_OWN_SERVICE)); - EXPECT_EQ(0, server.Start(port, nullptr)); + EXPECT_EQ(0, server.Start(0, nullptr)); - butil::EndPoint ep; - ASSERT_EQ(0, butil::str2endpoint("127.0.0.1:8923", &ep)); + const butil::EndPoint ep = server.listen_address(); brpc::SocketOptions options; options.remote_side = ep; brpc::SocketId id; From 1abe2d4125eef46b5ac5f79658401259d1a70820 Mon Sep 17 00:00:00 2001 From: Wang Xiaofeng Date: Fri, 4 Sep 2026 00:05:20 +0800 Subject: [PATCH 4/8] Set protobuf JSON test timeout explicitly --- test/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/test/BUILD.bazel b/test/BUILD.bazel index a8fd300de3..eed0eda9dc 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -285,6 +285,7 @@ generate_unittests( per_test_size = { "brpc_channel_unittest.cpp": "large", "brpc_load_balancer_unittest.cpp": "large", + "brpc_protobuf_json_unittest.cpp": "large", }, ) From 33b7e7bf3a7fb0546ddfd51f13456e01e9e0f05f Mon Sep 17 00:00:00 2001 From: Wang Xiaofeng Date: Fri, 4 Sep 2026 00:05:27 +0800 Subject: [PATCH 5/8] Use an ephemeral port in endpoint test --- test/endpoint_unittest.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/endpoint_unittest.cpp b/test/endpoint_unittest.cpp index ef8fd4ea73..3d293cd7f4 100644 --- a/test/endpoint_unittest.cpp +++ b/test/endpoint_unittest.cpp @@ -190,6 +190,10 @@ static void test_listen_connect(const std::string& server_addr, const std::strin int listen_fd = butil::tcp_listen(point); ASSERT_GT(listen_fd, 0); + if (point.port == 0) { + ASSERT_EQ(0, butil::get_local_side(listen_fd, &point)); + } + const std::string actual_server_addr = butil::endpoint2str(point).c_str(); pthread_t pid; pthread_create(&pid, nullptr, server_proc, (void*)(int64_t)listen_fd); @@ -206,7 +210,7 @@ static void test_listen_connect(const std::string& server_addr, const std::strin ASSERT_EQ(exp_client_addr, s.substr(0, exp_client_addr.size())); } ASSERT_EQ(0, butil::get_remote_side(fd, &point2)); - ASSERT_EQ(server_addr, butil::endpoint2str(point2).c_str()); + ASSERT_EQ(actual_server_addr, butil::endpoint2str(point2).c_str()); close(fd); void* ret = nullptr; @@ -225,7 +229,7 @@ static void test_parse_and_serialize(const std::string& instr, const std::string } TEST(EndPointTest, ipv4) { - test_listen_connect("127.0.0.1:8787", "127.0.0.1:"); + test_listen_connect("127.0.0.1:0", "127.0.0.1:"); } TEST(EndPointTest, ipv6) { From c89a66d91e35d5bb3738fa911db031f96ccc621d Mon Sep 17 00:00:00 2001 From: Wang Xiaofeng Date: Fri, 4 Sep 2026 00:05:34 +0800 Subject: [PATCH 6/8] Use an ephemeral port in oversized message test --- test/brpc_server_unittest.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/brpc_server_unittest.cpp b/test/brpc_server_unittest.cpp index 19e2f9a7ba..ed1fa91c1c 100644 --- a/test/brpc_server_unittest.cpp +++ b/test/brpc_server_unittest.cpp @@ -1918,11 +1918,13 @@ TEST_F(ServerTest, single_repeated_to_array) { } TEST_F(ServerTest, too_big_message) { + GFLAGS_NAMESPACE::FlagSaver flag_saver; + brpc::FLAGS_max_body_size = 1024; EchoServiceImpl echo_svc; brpc::Server server; ASSERT_EQ(0, server.AddService(&echo_svc, brpc::SERVER_DOESNT_OWN_SERVICE)); - ASSERT_EQ(0, server.Start(8613, nullptr)); + ASSERT_EQ(0, server.Start(0, nullptr)); #if !BRPC_WITH_GLOG logging::StringSink log_str; @@ -1930,7 +1932,7 @@ TEST_F(ServerTest, too_big_message) { #endif brpc::Channel chan; - ASSERT_EQ(0, chan.Init("localhost:8613", nullptr)); + ASSERT_EQ(0, chan.Init(server.listen_address(), nullptr)); brpc::Controller cntl; test::EchoRequest req; test::EchoResponse res; From 718f6ab0abba41dc95ee6bab692b5379cc618469 Mon Sep 17 00:00:00 2001 From: Wang Xiaofeng Date: Sun, 6 Sep 2026 23:44:29 +0800 Subject: [PATCH 7/8] Isolate additional timing-sensitive Bazel tests Run the channel and SSL test binaries exclusively. They rely on strict timing or process-wide networking state and can fail when competing with parallel test processes. --- test/BUILD.bazel | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/BUILD.bazel b/test/BUILD.bazel index eed0eda9dc..8706f63f2a 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -257,14 +257,18 @@ generate_unittests( # PATH, apt-installed by install-essential-dependencies); tag them the same # so bazel never serves a cached pass that actually skipped and runs them # outside the sandbox where mysqld and loopback are visible. - # Run timing-sensitive event-loop and socket tests without competing test - # processes. Their assertions intentionally depend on prompt scheduling. + # Run timing-sensitive tests and tests that manipulate process-wide + # networking state without competing test processes. per_test_tags = { + "brpc_channel_unittest.cpp": ["exclusive"], "brpc_event_dispatcher_unittest.cpp": ["exclusive"], "brpc_http_rpc_protocol_unittest.cpp": ["exclusive"], "brpc_redis_unittest.cpp": ["external", "local"], + "brpc_rdma_unittest.cpp": ["exclusive"], "brpc_server_unittest.cpp": ["exclusive"], "brpc_socket_unittest.cpp": ["exclusive"], + "brpc_ssl_unittest.cpp": ["exclusive"], + "brpc_streaming_rpc_unittest.cpp": ["exclusive"], "brpc_mysql_auth_handshake_unittest.cpp": ["external", "local"], "brpc_mysql_connection_type_unittest.cpp": ["external", "local"], "brpc_mysql_prepared_integration_unittest.cpp": ["external", "local"], From c719de69a94811c012fe8401107e9421ca8e6160 Mon Sep 17 00:00:00 2001 From: Wang Xiaofeng Date: Sun, 6 Sep 2026 23:44:37 +0800 Subject: [PATCH 8/8] Avoid restoring incompatible Bazel caches Limit fallback restoration to caches produced by the same CI job. The broad fallback could restore a cache from a different compiler or protobuf setup, which produced no hits while consuming transfer time and cache capacity. --- .github/actions/setup-build-cache/action.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/actions/setup-build-cache/action.yml b/.github/actions/setup-build-cache/action.yml index 6045ec891d..c95c6217d5 100644 --- a/.github/actions/setup-build-cache/action.yml +++ b/.github/actions/setup-build-cache/action.yml @@ -61,7 +61,6 @@ runs: key: ${{ runner.os }}-bazel-disk-${{ github.job }}-${{ github.sha }} restore-keys: | ${{ runner.os }}-bazel-disk-${{ github.job }}- - ${{ runner.os }}-bazel-disk- - name: Configure Bazel caches if: inputs.kind == 'bazel'