如何为 SmartDNS 搭建自动化测试与 CI/CD:从改一行代码到每次提交的完整指南
2026/9/15 14:17:50 网站建设 项目流程

如何为 SmartDNS 搭建自动化测试与 CI/CD:从改一行代码到每次提交的完整指南

【免费下载链接】smartdnsA local DNS server to obtain the fastest website IP for the best Internet experience, support DoT, DoH, DoQ. 一个本地DNS服务器,获取最快的网站IP,获得最佳上网体验,支持DoH,DoT,DoQ。项目地址: https://gitcode.com/GitHub_Trending/smar/smartdns

你刚给 SmartDNS 改了一行解析逻辑,按下提交前敢拍胸脯吗?SmartDNS 是一款本地 DNS 服务器,核心卖点是在多个可用 IP 里自动挑出访问最快的那个返回给客户端,同时支持 DoT、DoH、DoQ 等加密解析协议。改动这类基础设施代码,最怕的就是"修好一处、弄坏三处"。这篇文章带你亲手搭一条 SmartDNS 自动化测试 + CI/CD 的流水线:一条命令跑完全部用例,测试不通过就拦下你的提交,不用等线上用户替你发现问题。

先交代一下心态:我们不去背框架文档,而是像进实验室一样,先跑、再看、再改。跟着做一遍,整个过程大概十几分钟。

跑通第一批测试的步骤:make test 之后会发生什么

先别急着理解原理,我们直接动手。

git clone https://gitcode.com/GitHub_Trending/smar/smartdns cd smartdns/test make test

就这三条命令。你需要注意两个前提:一是系统里有dig工具(测试入口 test/test.cc 启动时会先which dig检查,缺了会直接报错退出);二是装了 libgtest 开发包和 OpenSSL,否则链接会失败。

make会先做两件事:通过 test/Makefile 里的通配符把test/下所有.cc文件编译成目标文件,再调用src/目录的 Makefile 打出核心库libsmartdns-test.a,最后链接出test.bin。注意 Makefile 里加了-DTEST宏,这正是"测试模式"的开关——它会激活核心代码中只有测试时才需要的钩子。

make test的目标定义很简单:依赖test.bin,然后执行它。你会在终端看到 GoogleTest 风格的一行行滚动:

[ RUN ] SpeedCheck.fastest_ip [ OK ] SpeedCheck.fastest_ip (231 ms) ... [ PASSED ] 100+ tests.

如果某个用例挂了,它会告诉你挂在哪、断言在哪一行。第一次跑全绿,说明你的环境和这个测试体系都就位了 ✅

三块积木拆解:MockServer、Client 和用例入口

现在回头看刚才那堆输出。SmartDNS 的测试系统其实就三块积木,对应 test/ 目录下的三个文件:

积木位置大白话技术要点
假上游test/server.h 的MockServer一个"配合演出的"DNS 上游,你告诉它"这个域名就返回这几个 IP",它就照办起一个真实 UDP/TCP 监听,每个请求回调一个std::function,返回码可控制应答、SOA、不响应等
真客户端test/client.h 的Client替你发查询、拆答案的 DNS 客户端底层调dig命令,再把结果解析成GetAnswer()GetStatus()这些可直接断言的方法
剧本test/test.cc + test/cases/每个.cc文件是一组"剧情",TEST_F(名字, 场景)就是一场戏基于 GoogleTest,test.bin会把所有注册的场景挨个演出

还有一个常被忽略的角色:同文件里的Server类(也在 server.h),它才是被测对象——它把一段配置字符串写成临时文件、fork 出真正的 smartdns 进程跑起来,并支持MockPing()伪造 Ping 时延。所以一次用例其实是四个角色过家家:MockServer装上游,Server装 SmartDNS,Client装终端用户,MockPing装"网络质量"。

整个数据流走一遍就是:

理解了这条回路,你看任何用例都能秒懂它在验证什么。

SmartDNS 测试用例怎么写:逐行读速度检查用例

速度检查最能代表 SmartDNS 的招牌能力——"选最快 IP"。我们拆开 test/cases/test-speed-check.cc 里的fastest_ip这个用例看骨架:

// ① 假上游:域名 b.com 一律返回两个 IP server_upstream.Start("udp://0.0.0.0:61053", & { MockServer::AddIP(request, "1.2.3.4"); MockServer::AddIP(request, "5.6.7.8"); ... }); // ② 伪造网络时延:两个 IP 只差 10ms server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 100); server.MockPing(PING_TYPE_ICMP, "5.6.7.8", 60, 110); // ③ 用真实配置启动 SmartDNS,开启 ping 测速 server.Start(R"""(bind [::]:60053 server 127.0.0.1:61053 speed-check-mode ping )"""); // ④ 查询并断言:答案里必须只出现快的那个 ASSERT_TRUE(client.Query("b.com", 60053)); ASSERT_EQ(client.GetAnswerNum(), 1); EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");

逻辑链非常清晰:模拟上游给两个 IP → 给它们捏造不同的 Ping 时延 → 断言 SmartDNS 只把1.2.3.4(100ms 那个)交还给用户。妙处在于MockPing——它不改内核、不真发包,而是让测试进程"演"出 100ms 和 110ms 的时延,所以这个用例在你家网断网、或者没有 ICMP 权限的容器里照样能稳定复现,不会偶发失败。

同一个文件里还有十几个场景:Ping 不可用自动降级 TCP 探测(no_ping_fallback_tcp)、TCP 比 Ping 更快时改信 TCP(tcp_faster_than_ping)、IPv4 最优 IP 不可达时切 IPv6(unreach_best_ipv4/unreach_best_ipv6)……写新用例时照这个"搭场景 → 捏数据 → 断言行为"的三段式来就行 🧪

把测试接进每次提交:脚本、钩子与覆盖率

跑一次是好事,跑"每一次"才是 CI/CD。落地分三步:

第一步,写个入口脚本ci-run.sh,把清理、构建、跑测、覆盖率串起来:

#!/bin/bash set -e make -C test clean # 干净环境 make -C test test # 构建并运行,失败即退出 gcovr -r . --html --html-details -o coverage.html --exclude=test/

第二步,给它加个"哨兵",二选一:

# 方式一:Git pre-commit 钩子(.git/hooks/pre-commit) # 测试不过,提交直接被拦下 ./ci-run.sh || { echo "提交被拦截:测试未通过"; exit 1; } # 方式二:定时任务兜底 # crontab -e 10 * * * * cd /path/to/smartdns && ./ci-run.sh >> ci.log 2>&1

第三步,学会读coverage.html。浏览器打开后先看三个数:整体行覆盖率、src/dns_server/下的回答生成模块是否被充分覆盖、以及标红的未覆盖分支。对 DNS 这种基础设施,优先关注"规则命中路径"(比如 domain-rule、client-rule 的分支)有没有测试踩到,而不是盲目追 100%。

这套组合拳的效果:make test是本地开发时的快速反馈,钩子是提交前的最后闸门,定时任务则防止你忘了装钩子 🚀

让测试更聪明:TDD、性能基准与可视化

几个进阶方向,各点两句就够:

  • TDD 循环:新功能先写用例、看着它红、再写实现让它绿。比如加一条"按客户端 IP 屏蔽域名"的规则,可以先写TEST_FEXPECT_EQ(client.GetStatus(), "NXDOMAIN")的失败用例,再去 src/dns_conf/client_rule.c 补逻辑。用例就是你最不会过期的需求文档。
  • 性能基准:test/cases/test-perf.cc 已经给了现成模板,思路是起 MockServer + Server 后多线程并发查询,统计 QPS 和平均查询耗时。建议把它当作"性能回归线":每次发版跑一遍,QPS 掉超过阈值就当功能回归一样处理。
  • 可视化监控:plugin/smartdns-ui/ 里的 Web 管理界面能实时看总查询数、缓存命中率、平均查询时间这些指标,测试压测时开着它,比盯日志直观得多。

动手清单:四步走完这条线

  1. 克隆并跑通:git clone https://gitcode.com/GitHub_Trending/smar/smartdns,然后cd smartdns/test && make test,看到全绿再往下走;
  2. 精读一个用例:打开 test/cases/test-speed-check.cc,对照本文"三块积木"标出 MockServer、Server、Client 各自在哪几行出场;
  3. 写你自己的第一个用例:照"搭场景 → 捏数据 → 断言行为"三段式,加一个验证addressdomain-rules的行为用例,跑红改绿;
  4. 接上 CI:落地ci-run.sh+ pre-commit 钩子,顺手用 gcovr 出一份coverage.html,从此每次提交都有闸门。

跑完这四步,你就给 SmartDNS 装上了一套"改一行、验一遍、拦得住"的质量流水线。测试体系还会继续长出新玩法——模糊测试、大规模并发场景、跨平台部署验证都值得折腾,而起点就是此刻你终端里那行make test

【免费下载链接】smartdnsA local DNS server to obtain the fastest website IP for the best Internet experience, support DoT, DoH, DoQ. 一个本地DNS服务器,获取最快的网站IP,获得最佳上网体验,支持DoH,DoT,DoQ。项目地址: https://gitcode.com/GitHub_Trending/smar/smartdns

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询