ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

gRPC EventEngine 可复用一致性测试套件:为自定义 EventEngine 实现编写 Bazel 一致性测试与回显客户端

2026/9/10 12:17:32 拓冰建站 浏览量
gRPC EventEngine 可复用一致性测试套件:为自定义 EventEngine 实现编写 Bazel 一致性测试与回显客户端 gRPC EventEngine 可复用一致性测试套件为自定义 EventEngine 实现编写 Bazel 一致性测试与回显客户端【免费下载链接】grpcC based gRPC (C, Python, Ruby, Objective-C, PHP, C#)项目地址: https://gitcode.com/GitHub_Trending/gr/grpc本文以 gRPC 仓库中的 test/core/event_engine/test_suite/README.md 为主体系统讲解该仓库为 EventEngine 实现提供的可复用一致性测试套件reusable test suite如何通过 Bazel 目标与自定义工厂函数将自己的 EventEngine 实现接入 timer / dns / client / server 等一致性测试以及如何利用echo_client工具以独立二进制的方式实测EventEngine::Connect与Endpoint行为。读完本文你将掌握在 gRPC 源码树内为自定义 EventEngine 搭建 Bazel 一致性测试、编写测试main函数、接入 oracle 参照引擎以及用 netcat 等第三方 TCP 工具联调回显客户端的完整方法。一、这套测试套件解决什么问题gRPC 的 EventEngine 是位于 include/grpc/event_engine/event_engine.h 的抽象接口层把定时器Timer、DNS 解析DNSResolver、连接Connect、监听Listener、端点Endpoint等底层事件能力从 gRPC 核心中解耦出来。任何平台或团队都可以基于该接口提供自己的实现例如仓库中已有的 Posix、Windows、CFStream、thready 等引擎但实现是否正确、行为是否与 gRPC 期望一致需要一套统一的验收标准。test/core/event_engine/test_suite正是这样一套与具体实现无关、可整体复用的一致性测试套件它把针对 EventEngine 各能力面的测试编写成独立的 Bazel 库目标任何自定义 EventEngine 只要在测试目标中链接这些库、并注入一个返回自身引擎实例的工厂函数就能直接跑通整套一致性测试无需修改套件本身。套件在仓库中的结构如下test/core/event_engine/test_suite/ ├── BUILD # 框架库 各平台引擎测试目标 ├── README.md # 使用说明本文主体 ├── event_engine_test_framework.h/.cc # 测试框架工厂注册与测试基类 ├── tests/ # 一致性测试库timer/dns/client/server/endpoint │ ├── BUILD │ ├── timer_test.cc / timer_test.h │ ├── dns_test.cc / dns_test.h / dns_test_record_groups.yaml │ ├── client_test.cc / client_test.h │ ├── server_test.cc / server_test.h │ └── endpoint_test.cc ├── tools/ # 独立测试工具echo_client 等 │ ├── BUILD │ ├── echo_client.cc │ ├── posix_event_engine_factory.cc │ └── windows_event_engine_factory.cc └── posix/ # 作为预言机参照的 Posix 引擎 ├── oracle_event_engine_posix.h / .cc └── oracle_event_engine_posix_test.cc二、为你的 EventEngine 定制一致性测试README 给出了接入套件的两步式流程先声明一个链接测试库的 Bazel 测试目标再编写一个设置自定义 EventEngine 工厂的测试main函数。2.1 第一步声明 Bazel 测试目标在自定义引擎的 BUILD 文件中新增一个grpc_cc_test目标把srcs指向你的测试源文件并在deps中链接//test/core/event_engine/test_suite/tests/...下的测试库grpc_cc_test( name my_custom_event_engine_test, srcs [my_custom_event_engine_test.cc], uses_polling False, deps [//test/core/event_engine/test_suite/tests:timer], )要点说明uses_polling Falsegrpc_cc_test是仓库通过 bazel/grpc_build_system.bzl 提供的宏uses_polling用于声明该测试是否依赖 gRPC 的轮询polling机制事件引擎测试通常按需设置为False。对照仓库现有测试可看到更多配置模式例如 test/core/event_engine/test_suite/BUILD 中posix_event_engine_test使用uses_polling True而windows_event_engine_test使用uses_polling False应根据引擎特性选择。deps只链入你关心的测试面只链接timer时仅执行定时器一致性测试链接多个目标则执行多套测试详见下文一致性测试子集一节。2.2 第二步编写测试 main 函数测试源文件的核心是初始化 GoogleTest、通过框架提供的工厂注册接口注入你的引擎构造逻辑然后运行全部测试#include path/to/my_custom_event_engine.h #include test/core/event_engine/test_suite/event_engine_test_framework.h int main(int argc, char** argv) { testing::InitGoogleTest(argc, argv); SetEventEngineFactory( []() { return absl::make_uniqueMyCustomEventEngine(); }); auto result RUN_ALL_TESTS(); return result; }需要说明的是README 中的SetEventEngineFactory是简化的示意写法当前仓库的框架头文件 event_engine_test_framework.h 中实际暴露的注册接口是带两个参数的SetEventEngineFactories(ee_factory, oracle_ee_factory)——第一个参数是被测引擎工厂第二个是可选的oracle预言机参照引擎工厂详见第三节。仓库内真实测试的写法可参考 posix_event_engine_test.ccint main(int argc, char** argv) { testing::InitGoogleTest(argc, argv); grpc::testing::TestEnvironment env(argc, argv); SetEventEngineFactories( []() { return grpc_event_engine::experimental::PosixEventEngine:: MakePosixEventEngine(); }, []() { return std::make_unique grpc_event_engine::experimental::PosixOracleEventEngine(); }); grpc_event_engine::experimental::InitTimerTests(); grpc_event_engine::experimental::InitClientTests(); grpc_event_engine::experimental::InitServerTests(); // EventEngine 暂时需要在测试前完成 grpc 初始化 grpc_init(); int r RUN_ALL_TESTS(); grpc_shutdown(); return r; }从该示例可见真实接入的几个关键细节测试库通过InitXxxTests()函数完成注册tests/下每个测试库都暴露一个InitXxxTests()入口如 timer_test.h 中的InitTimerTests()你的main需要显式调用想执行的测试面的初始化函数grpc_init()/grpc_shutdown()生命周期管理源码注释说明在 iomgr 关停逻辑清理完成前EventEngine 测试仍需要先初始化 gRPC同时注册 oracle 引擎第二个工厂返回PosixOracleEventEngine用于与待测引擎做对照。三、框架机制工厂注册、oracle 引擎与测试基类框架实现集中在 event_engine_test_framework.h 与 event_engine_test_framework.cc 中核心机制包括全局工厂指针g_ee_factory被测引擎工厂与g_oracle_ee_factoryoracle 参照引擎工厂类型均为absl::AnyInvocablestd::shared_ptrgrpc_event_engine::experimental::EventEngine()*即返回共享指针类型 EventEngine 的可调用对象EventEngineTestEnvironment一个继承自testing::Environment的全局环境对象在SetUp()时把传入的两个工厂写入全局指针TearDown()时置空从而管理工厂的全局生命周期。SetEventEngineFactories内部通过testing::AddGlobalTestEnvironment(...)注册该环境这正是它必须在RUN_ALL_TESTS()之前调用的原因EventEngineTest测试基类提供NewEventEngine()返回被测引擎实例与NewOracleEventEngine()返回 oracle 实例两个受保护方法。各测试库通过调用它们创建引擎从而做到与具体实现解耦。其中oracle 引擎是一种值得注意的测试设计仓库在 posix/oracle_event_engine_posix.h 中实现了一个基于裸 POSIX socket 的PosixOracleEventEngine从源码结构看它直接以文件描述符和线程模拟Endpoint的读写PosixOracleEndpoint内部维护读写线程与ReadOperation/WriteOperation队列作为一套已知正确的参照实现。测试可以在同一套用例中同时驱动被测引擎与 oracle 引擎进行行为对照这可以推断是用于差分校验differential testing——即用参照实现验证被测实现的行为是否一致。框架库本身在 BUILD 中定义为event_engine_test_frameworktestonly True依赖gtest、absl/functional:any_invocable、//:event_engine_base_hdrs等任何自定义测试目标只需链接它即可获得上述全部机制。四、一致性测试子集timer / dns / client / server / endpoint如果只想跑全部一致性测试中的一部分可以在deps中按需组合 tests/BUILD 提供的五个grpc_cc_library目标均为testonly True、alwayslink 1以保证InitXxxTests()符号被链接进测试二进制Bazel 目标对应源码覆盖能力面//test/core/event_engine/test_suite/tests:timertimer_test.cc定时器调度RunAfter/Cancel等计时语义//test/core/event_engine/test_suite/tests:dnsdns_test.ccDNS 解析附带 dns_test_record_groups.yaml 记录组配置与//test/cpp/naming/utils:dns_server等测试数据依赖//test/core/event_engine/test_suite/tests:clientclient_test.cc客户端连接Connect/Endpoint建立与通信//test/core/event_engine/test_suite/tests:serverserver_test.cc服务端监听Listener绑定、接受连接与关闭语义//test/core/event_engine/test_suite/tests:endpointendpoint_test.cc端点读写行为README 虽未列出但它是各引擎测试均会链接的公共测试面例如只想验证自定义引擎的定时器与 DNS 能力可以这样声明grpc_cc_test( name my_custom_event_engine_test, srcs [my_custom_event_engine_test.cc], uses_polling False, deps [ //test/core/event_engine/test_suite/tests:timer, //test/core/event_engine/test_suite/tests:dns, ], )dns测试还依赖本仓库 test/cpp/naming/utils 下的dns_server、dns_resolver、health_check、tcp_connect工具作为数据依赖用于搭建真实的本地 DNS 解析环境因此该测试面的运行条件比其他测试面更重。作为对照仓库自带的引擎实现如何组合这些测试面可直接参考 test_suite/BUILDposix_event_engine_testposix_event_engine_test.cc链接client、dns、endpoint、server、timer全部五个测试面并带no_mac、no_windows、requires-net:ipv4、requires-net:loopback等平台/网络标签thready_posix_event_engine_testthready_posix_event_engine_test.cc对多线程版 Posix 引擎跑同样的 client/endpoint/server/timer 测试windows_event_engine_test、cf_event_engine_test、fuzzing_event_engine_test分别验证 Windows 引擎、CFStream 引擎与模糊测试引擎标签上通过no_linux/no_windows/bazel_only等限制各自运行平台。这些真实目标本身就是如何为自己的引擎组合测试面的最佳范例。五、实用测试工具echo_client 与第三方 TCP 对端联调除了在测试进程内运行一致性用例套件还在 tools/ 下提供了可独立运行的测试工具。其中最典型的是echo_client库它基于你的EventEngine::Connect与Endpoint实现搭建一个TCP 回显客户端可以与任意第三方 TCP 监听端通信用于实测引擎的网络栈行为。5.1 注册你的引擎工厂echo_client要求你提供一个实现CustomEventEngineFactory()的源文件返回一个能创建待测引擎的可调用对象。仓库自带的示例见 posix_event_engine_factory.ccWindows 版本见 windows_event_engine_factory.cc// tools/BUILD: grpc_cc_binary( name my_event_engine_echo_client, srcs [my_event_engine_factory.cc], deps [echo_client], ) // tools/my_event_engine_factory.cc: 实现 CustomEventEngineFactory absl::AnyInvocable std::unique_ptrgrpc_event_engine::experimental::EventEngine(void) CustomEventEngineFactory() { return []() { return std::make_unique grpc_event_engine::experimental::WindowsEventEngine(); }; }仓库中的真实二进制目标可参考 tools/BUILD 的posix_event_engine_echo_client与windows_event_engine_echo_client两者都通过srcs指向各自的 factory 源文件并在deps中链接echo_client库。5.2 运行回显客户端并与 netcat 对端通信README 给出了完整的联调流程先在一个终端启动 TCP 监听端如 netcat / ncat再在另一个终端用bazel run启动回显客户端两者建立连接后即可观察数据收发# 终端 1启动一个 TCP 监听端以 Windows 的 ncat 为例 ncat -klp 32000 # 终端 2运行基于自定义引擎的回显客户端 bazel run //test/core/event_engine/test_suite/tools:my_event_engine_echo_client从 echo_client.cc 的源码可以看到它的工作细节目标地址可通过 flag 指定ABSL_FLAG(std::string, target, ipv4:127.0.0.1:50051, Target string)即默认连接ipv4:127.0.0.1:50051可用--target覆盖支持通过resolver_registry的AddDefaultPrefixIfNeeded自动补全目标前缀如localhost:32000会被规范化连接流程GetDefaultEventEngine()获取默认引擎后构造ChannelArgsEndpointConfig与MemoryAllocator调用engine-Connect(callback, addr, config, allocator, 2h)发起带 2 小时超时的异步连接并通过grpc_core::Notification等待连接完成回显循环连接建立后客户端进入while(true)循环先SendMessage写入一条Waiting for message %d ... \n消息再ReceiveAndEchoMessage读取对端返回的数据并打印到日志全程使用Endpoint::Write/Endpoint::Read的回调 Notification同步模式Slice/SliceBuffer负责数据承载入口main中先absl::ParseCommandLine解析 flag再SetEventEngineFactory(CustomEventEngineFactory())把自定义引擎注册为默认引擎之后grpc_init()→RunUntilInterrupted()→grpc_shutdown()。因此实际操作中你只需把终端 1 的 ncat 监听端口与终端 2 的--target指向同一地址即可在 ncat 侧输入数据、在 echo_client 侧日志中看到引擎真实收发的字节流从而脱离测试框架单独验证Connect/Endpoint的实现质量。README 同时说明每个工具在其源文件中都有更完整的文档说明扩展或新写工具时以源码内注释为准。六、接入套件的注意事项综合 README 与仓库源码接入这套一致性测试套件时有几点值得留意框架注册接口以源码为准README 示例中的SetEventEngineFactory为简化写法当前头文件event_engine_test_framework.h实际提供SetEventEngineFactories(ee_factory, oracle_ee_factory)务必在写main前核对头文件签名测试库需要InitXxxTests()显式注册仅链接 Bazel 目标还不够必须在main中调用对应测试面的InitTimerTests()/InitClientTests()/InitServerTests()等初始化函数各测试库头文件声明在 tests/ 下注意平台与运行条件标签套件内许多测试目标带有no_windows、no_mac、requires-net:ipv4、requires-net:loopback、bazel_only等标签见 test_suite/BUILD为自定义引擎组合测试时应参照这些标签判断哪些测试面能在你的目标平台上运行oracle 引擎可显著提升测试有效性为被测引擎同时注册 oracle 工厂即可在 posix/oracle_event_engine_posix.h 这类参照实现的对照下发现被测实现的行为偏差。七、总结test/core/event_engine/test_suite为 gRPC EventEngine 生态提供了一套零侵入的一致性验收方案通过grpc_cc_test 工厂注入任何 EventEngine 实现都能复用仓库内 timer、dns、client、server、endpoint 五套一致性测试库并以 oracle 引擎做行为对照通过tools/echo_client又能在测试框架之外以独立二进制 netcat 的方式实测Connect与Endpoint。整套机制以 event_engine_test_framework.h 的工厂与测试基类为支点把自定义引擎必须满足 gRPC 期望行为这一要求变成了可复制、可组合、可独立运行的具体工程实践。【免费下载链接】grpcC based gRPC (C, Python, Ruby, Objective-C, PHP, C#)项目地址: https://gitcode.com/GitHub_Trending/gr/grpc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考