ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

VictoriaMetrics 集成测试框架深度解析:apptest 包架构、运行机制与实战编写指南

VictoriaMetrics 集成测试框架深度解析:apptest 包架构、运行机制与实战编写指南 VictoriaMetrics 集成测试框架深度解析apptest 包架构、运行机制与实战编写指南【免费下载链接】VictoriaMetricsVictoriaMetrics: fast, cost-effective monitoring solution and time series database项目地址: https://gitcode.com/GitHub_Trending/vi/VictoriaMetricsapptest是 VictoriaMetrics 仓库中面向整个应用而非单个代码单元的集成测试包它把 vmstorage、vminsert、vmselect、vmsingle 等真实二进制以独立进程方式拉起再通过 HTTP 请求、指标校验、文件检查等方式验证应用整体行为。本文以 apptest/README.md 为主体结合 app.go、client.go、testcase.go 等源码系统讲解该框架的分层设计、进程管理原理、客户端工具集、集群测试编排方式以及如何构建二进制并运行、编写自己的集成测试用例。集成测试与单元测试的分工为什么需要 apptest单元测试验证的是应用积木的行为——例如 lib/storage 中某个 block 的读写逻辑、lib/mergeset 中某个索引操作的内部正确性而集成测试要回答的是另一个层面的问题把整个应用组装好之后它对外表现是否符合预期。按照 apptest/README.md 的定位集成测试的目标是把应用当作一个黑盒整体来验证测试进程启动一个真实的应用二进制然后向它发起 HTTP 请求并检查响应或者读取该应用暴露的/metrics指标或者检查它创建的文件。因此测试的对象可以不是单个应用而是多个应用协同工作的系统——典型例子就是 VictoriaMetrics 集群测试可以还原任意集群拓扑验证 vminsert、vmstorage、vmselect 作为一套系统时数据如何写入、分片、查询与聚合。这一设计直接决定了 apptest 包的三层架构层次文件职责通用进程管理app.go启动任意应用进程、注入默认 flag、从日志提取运行时信息、优雅停止集成测试不应直接使用应用专属封装vmstorage.go、vminsert.go、vmselect.go、vmsingle.go 等基于app.go提供启动某个具体应用的入口并填充该应用的默认 flag 与日志提取规则网络客户端client.go提供向应用发送 HTTP 请求、读写原始 TCP、拉取并解析指标等辅助函数集成测试用例本体则统一放在 apptest/tests 下的*_test.go文件中文件名没有强制规则但要能反映该文件测试的主导目的例如 sharding_test.go 专注于测试数据分片。通用进程启动器app.go 的实现原理startApp()是 app.go 的核心函数它完成四件事合并默认 flag、创建子进程并接管 stdout/stderr、启动行处理器解析日志、等待所有预期信息被提取出来。默认 flag 注入每个应用在启动前会通过appOptions.defaultFlags指定一组默认 flagsetDefaultFlags()app.go会把测试显式传入的 flag 与默认 flag 做去重合并凡是测试传入的 flag 已经覆盖的项默认值会被丢弃避免冲突。以 vmstorage.go 为例启动 vmstorage 时会自动补全defaultFlags: map[string]string{ -storageDataPath: fmt.Sprintf(%s/%s-%d, os.TempDir(), instance, time.Now().UnixNano()), -httpListenAddr: 127.0.0.1:0, -vminsertAddr: 127.0.0.1:0, -vmselectAddr: 127.0.0.1:0, },其中127.0.0.1:0让操作系统为各监听端口分配随机可用端口——这正是集成测试能并行运行多个实例而不互相冲突的关键-storageDataPath则被指向带实例名和时间戳的唯一临时目录保证数据隔离。从日志提取运行时信息子进程启动后框架无法预知随机端口号因此 app.go 定义了一组正则表达式从应用的日志输出stderr中钓取关键运行时信息storageDataPathRE regexp.MustCompile(successfully opened storage (.*)) httpListenAddrRE regexp.MustCompile(started server at http://(.*:\d{1,5})/) graphiteListenAddrRE regexp.MustCompile(started TCP Graphite server at (.*:\d{1,5})) openTSDBListenAddrRE regexp.MustCompile(started TCP OpenTSDB collector at (.*:\d{1,5})) vminsertAddrRE regexp.MustCompile(accepting vminsert conns at (.*:\d{1,5})$) vmselectAddrRE regexp.MustCompile(accepting vmselect conns at (.*:\d{1,5})$)reExtractorapp.go是一个逐行处理器对每一行执行FindSubmatch命中后把第一个子匹配写入 channel 并声明完成extractREs()app.go则借助reflect.Select同时监听所有提取器的 channel 和一个5 秒超时定时器任何一个正则迟迟匹配不到日志就判定启动失败并终止进程——这相当于一套内置的就绪探测readiness只有当应用打印出全部预期日志如各监听地址后测试才会继续从而把应用真的可用这个前置条件显式化。输出透传与优雅停止processOutput()app.go用bufio.Scanner逐行消费 stdout/stderr每一行会依次经过所有活跃的行处理器始终在列表末尾的writeToOutput处理器会把行以实例名 内容的格式透传到测试输出默认 stderr失败时可定位是哪台实例报错。Stop()app.go向进程发送os.InterruptSIGINT并等待其退出模拟生产环境中优雅停机路径而不是直接 kill——这也顺带验证了应用处理 SIGINT 后正确 flush 数据的能力。应用专属封装StartVmstorage / StartVminsert / StartVmselect / StartVmsingle各app/*.go文件基于startApp提供语义化的启动函数并返回持有丰富状态的对象StartVmstorage启动 vmstorage默认提取数据目录、HTTP 地址、vminsert 与 vmselect 内部 RPC 地址返回的Vmstorage对象同时内嵌metricsClient与vmstorageClient可直接查询/metrics或调用ForceFlush、ForceMerge、快照系列接口。StartVminsert额外解析-storageNodeflag并为每个存储节点追加一个successfully dialed -storageNode...日志提取器阻塞直到 vminsert 与所有 vmstorage 建立连接确保写入前拓扑已就绪。StartVmselect默认启动-httpListenAddr与-clusternativeListenAddr提取 HTTP 地址与集群原生通信地址。StartVmsingle单机版封装同时提取 Graphite、OpenTSDB 监听地址且其客户端同时内嵌 vmstorage、vmselect、vminsert 三类客户端一台 vmsingle 即可承担完整的读写查询。二进制路径的查找遵循统一约定优先读取环境变量如VMSTORAGE_PATH、VMINSERT_PATH、VMSELECT_PATH、VMSINGLE_PATH未设置时回退到../../bin/binary-race见 vmstorage.go。也就是说测试默认使用带 race detector 的构建产物把数据竞争检测直接并入集成测试运行。网络客户端工具集client.go 的能力矩阵client.go 是测试与应用的手按用途可分为四组通用 HTTP 客户端Clientclient.go封装http.Client提供Get、Post、PostForm、Deleteclient.go统一返回响应体字符串与状态码便于断言Writeclient.go则直接以 TCP 方式向 Graphite 等明文协议端口写入多行数据。指标读取客户端metricsClientclient.go以http://addr/metrics为数据源提供三类读取方式GetMetric/GetIntMetric按完整指标名取单个值GetMetricsByPrefix取同一前缀的全部指标值如用于求和vm_rpc_rows_sent_totalGetMetricsByRegexp按正则匹配一批指标。rpcRowsSentTotal()client.go把各 vmstorage 的vm_rpc_rows_sent_total求和作为vminsert 已成功转发 N 行到存储的判据。协议级读写客户端vminsertClient覆盖了 VictoriaMetrics 的全部主流写入协议每个方法对应一个真实 HTTP 端点Prometheus remote-writePrometheusAPIV1Write→/prometheus/api/v1/writesnappy 压缩的 protobufPrometheus 文本格式PrometheusAPIV1ImportPrometheus→/prometheus/api/v1/import/prometheusCSV / Native 导入PrometheusAPIV1ImportCSV/PrometheusAPIV1ImportNativeInflux 行协议InfluxWrite→/influx/writeOpenTelemetryOpentelemetryV1Metrics→/opentelemetry/v1/metricsOpenTSDBOpenTSDBAPIPut→/opentsdb/api/putZabbixZabbixConnectorHistory→/zabbixconnector/api/v1/historyGraphiteGraphiteWrite走原始 TCP 端口。vmselectClient则对应查询侧 API包括PrometheusAPIV1Query/PrometheusAPIV1QueryRange/PrometheusAPIV1Series/PrometheusAPIV1Labels/PrometheusAPIV1Export等以及 Graphite 的GraphiteRender、GraphiteMetricsFind、GraphiteMetricsExpand等查询接口。存储管理客户端vmstorageClient提供运维类能力ForceFlush/internal/force_flush让刚写入的数据立即可查询、ForceMerge/internal/force_merge、以及快照系列接口SnapshotCreate/SnapshotList/SnapshotDelete/SnapshotDeleteAll覆盖 vmstorage 暴露的运维端点。多租户 URL 处理getClusterPath()client.go按QueryOpts决定租户标识放哪优先走 URL 路径/insert/tenant/...若通过 HTTP 头传AccountID/ProjectID则省略路径中的租户段需开启-enableMultitenancyViaHeaders兜底使用默认租户0:0。这与集群版的实际 URL 格式约定一致测试因此能覆盖 multitenant_test.go 与 multitenancy_via_headers_test.go 两类租户路由场景。测试用例编排testcase.go 与轮询断言testcase.go 是测试的骨架核心是TestCase类型NewTestCase(t)testcase.go自动调用t.Parallel()允许用例并行执行其Cleanup会在测试失败或-v模式下把收集到的子进程输出 flush 到 stderr。一组MustStart*方法MustStartVmsingle、MustStartVmstorage、MustStartVminsert、MustStartVmselect、MustStartVmagent、MustStartVmauth、MustStartVmbackup、MustStartVmrestore把启动失败转化为测试失败并把实例登记到startedApps统一管理。Stop()testcase.go负责清理关闭所有客户端连接 → 逐个优雅停止应用 → 仅在用例未失败时删除数据目录失败时保留以便人工排查。带重试的 Assert处理数据可见性延迟VictoriaMetrics尤其集群版写入的数据不会立刻可见因此TestCase.Assert()testcase.go实现了轮询断言默认重试 20 次、每次间隔 100ms用go-cmp的cmp.Diff对比Want与Got()的取值直到一致或超时若已知数据已就绪可设置DoNotRetry关闭重试。AssertOptionstestcase.go还支持透传CmpOpts给cmp.Diff以及用FailNow控制失败是Error还是Fatal。阻塞写sendBlockingvminsert 写入有缓冲与批量转发机制后台协程约每 200ms 批量发送一次见 vminsert.go 的注释因此sendBlocking在发送后轮询vm_rpc_rows_sent_total指标直到其增量达到预期行数保证数据确实已进入 vmstorage才返回——从源码可见其重试 20 次、间隔 100ms 的默认节奏。集群测试编排Vmcluster 与 ClusterOptions对集群场景testcase.go 提供了两级封装Vmcluster组合一个Vminsert、一个Vmselect与多个Vmstorage并代理ForceFlush/ForceMerge到所有存储节点MustStartDefaultCluster()直接拉起两台 vmstorage各配-storageDataPath与-retentionPeriod100y、一台 vminsert、一台 vmselect 的典型拓扑MustStartCluster(ClusterOptions{...})允许自定义每台实例的 flag框架会自动把 vmstorage 的VminsertAddr()/VmselectAddr()拼进-storageNode传给 vminsert / vmselect完成组件互联。注释中明确说明这类标准集群适合验证业务逻辑如 API 面、MetricsQL而分片、复制、多级 vmselect 等基础设施级行为则需要在 replication_test.go、sharding_test.go、multilevel_test.go 等专门的用例中构造自定义拓扑。构建与运行make apptest 与分支约束二进制前置条件由于集成测试以独立进程方式启动应用必须先构建二进制并放入bin目录推荐入口是make apptestMakefile 中的apptest目标会先构建所需二进制再以GORACEhalt_on_error1 go test ./apptest/... -skip^Test(Cluster|Mixed|Legacy).*运行测试详见 Makefilehalt_on_error1保证 race 检测器一旦发现问题立即让测试失败如果不用 make 而直接执行go test ./apptest/tests则需提前手动构建二进制例如先执行make all也可以通过VMSTORAGE_PATH、VMINSERT_PATH、VMSELECT_PATH、VMSINGLE_PATH等环境变量指定自定义二进制路径。分支与命名规则并非所有二进制都能在任意分支构建集群版二进制只能从cluster分支构建make apptest-cluster相关master 分支只能构建单机版相关二进制。因此测试用例的命名被赋予了语义使用cluster分支二进制集群组件的测试必须以TestCluster前缀命名使用master分支二进制单机组件的测试必须以TestSingle前缀命名。这一约定让make apptest、make apptest-cluster、make apptest-legacy、make apptest-mixed见 Makefile可以通过-run正则精确挑选在当当前分支下可运行的用例组例如apptest-legacy依赖victoria-metrics-race vmbackup-race vmrestore-race并只跑^TestLegacySingle.*用例。现有测试全景从 API 面到数据语义apptest/tests 目录下现有约 35 个测试文件覆盖的维度包括协议与写入ingestprotocols_test.go、opentsdb_server_test.go、vmagent_remotewrite_test.go查询语义metricsql_test.go、special_query_regression_test.go、rollup_result_cache_test.go、graphite_test.go存储行为dedup_test.go、per_day_index_test.go、legacy_indexdb_test.go、snapshot_test.go集群特性sharding_test.go、replication_test.go、multilevel_test.go、multitenant_test.go资源与限额maxingestionrate_test.go、query_resource_limit_test.go、future_timestamps_test.go、max_backfill_age_test.go周边工具链vmctl 迁移系列vmctl_native_migration_test.go、vmctl_thanos_migration_test.go 等、backup_restore_test.go、vmauth_routing_test.go。配合 apptest/testdata 中的测试数据这些用例构成了对 VictoriaMetrics 全功能面的黑盒回归保障。结语apptest 的价值与扩展方式从架构上看apptest 把进程编排、日志解析、就绪等待、优雅停机、指标断言、集群互联这些集成测试的脏活全部封装为可复用组件让测试作者只需聚焦于业务语义写什么数据、查什么结果、期望什么指标。三层职责通用启动器 → 应用封装 → 协议客户端与两条约定二进制先行、分支命名规则共同保证了这套框架既能并行拉起大量真实进程又能稳定地验证单机与集群两个形态下的端到端行为。如果你要为 VictoriaMetrics 新增端到端能力验证最直接的做法就是在apptest/tests下新建*_test.go用NewTestCaseMustStart*Client完成编排再用带重试的Assert收敛断言然后通过make apptest一键验证。【免费下载链接】VictoriaMetricsVictoriaMetrics: fast, cost-effective monitoring solution and time series database项目地址: https://gitcode.com/GitHub_Trending/vi/VictoriaMetrics创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表