ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Buzz 项目测试指南:从单元测试到本地中继端到端验证的完整实践

Buzz 项目测试指南:从单元测试到本地中继端到端验证的完整实践 Buzz 项目测试指南从单元测试到本地中继端到端验证的完整实践【免费下载链接】buzzA hive mind communication platform项目地址: https://gitcode.com/GitHub_Trending/buzz14/buzz本文是 Buzz基于 Nostr 协议的 hive mind 通信平台仓库中 TESTING.md 的深度实践指南。它系统梳理了该项目的自动化测试分层单元测试与集成测试、Review-Proven 回归测试标准以及最核心的实战部分——如何在本机构建buzz-relay并用buzzCLI 完成从发消息、验证千人大名单roster到 ACP Agent 端到端联调的全流程。读完本文你将能复现一条完整的本地中继验证链路并理解每一个测试步骤背后的源码依据与环境变量语义。一、自动化测试两层命令与一个明确边界Buzz 将测试收敛为两条just命令由仓库根目录的 Justfile 定义just test-unit # 单元测试 —— 无需任何基础设施 just test # 单元 集成测试必要时自动启动 Dockerjust test-unit纯内存、无外部依赖的单元测试。在 Justfile 中它调用 scripts/run-tests.sh覆盖buzz-core、buzz-auth、buzz-voice、buzz-cli、buzz-acprelay 与 agent 之间的信任边界、buzz-db的迁移器与 lint、buzz-conformance的多租户回放校验、buzz-backend-kubernetes的决策层、buzz-agent的模型能力语料以及buzz-relay的handlers::channel_authz/handlers::moderation_authz/handlers::side_effects纯函数授权网格。若本机装有cargo-nextest同一批目标会以 nextest 表达式运行否则回退到 run-tests.sh 的cargo test清单。just test先跑单元测试再跑集成测试。集成部分依赖 Postgres 与 RedisJustfile 中的_ensure-services会检查buzz-postgres、buzz-redis两个容器的健康状态未就绪时自动执行docker compose up -d并轮询等待随后_ensure-migrations运行迁移并播种本地社区。关键边界两条任务都不跑buzz-test-client的 E2E 套件。该 crate 的 E2E 测试全部标记为#[ignore]需要一台真实运行的中继。手动触发方式# 先启动中继见下文然后 cargo test -p buzz-test-client -- --ignored另外本地测试通过但 CI 失败时通常是因为遗漏了整门gatejust ci会执行 fmt、clippy、单元测试以及 desktop/web 的构建检查见 Justfile 中ci任务与本文末尾故障排查表。Review-Proven 测试标准回归测试必须绑定生产接缝且可证伪TESTING.md 从最近 25 个 PR 的评审讨论中提炼出一条被评审者反复计较的测试质量标准回归测试必须绑定生产代码路径production seam并且是可证伪的。其依据全部来自真实评审事故一个守卫被移除后没有任何测试变红说明它没有保护任何东西——这类幸存突变曾在移动端测试套件中连续两次漏网PR #6996、#7013回归测试绑定在测试专用 helper 而非生产代码路径上同样无效PR #7013。对应的可操作规则包括纯谓词应使用表驱动测试table test覆盖完整输入组合空间PR #6807Playwright 定位器必须限定作用域——必需 smoke 测试中不加作用域的getByText是严格模式下的典型 flake 源PR #6980。这条标准的推论是每条回归测试都应当能通过删除被保护代码后测试失败的方式自证价值而不是作为通过即可的形式化存在。二、本地实时中继Live Local Relay最快的中继端到端演练文档推荐的最快路径是一次性构建 release 二进制运行buzz-relay再用buzzCLI 驱动它。CLI 会对每个请求做 NIP-98 签名因此无需nak或手写curl。第 1 步环境准备. ./bin/activate-hermit # 激活钉住的工具链Hermit just bootstrap # 创建 .env 并一次性生成稳定的 relay key just setup # 启动 Docker 服务执行迁移其中just bootstrap见 Justfile会从.env.example复制生成.env并调用scripts/ensure-local-relay-key.sh注入稳定的中继身份密钥just setup调用scripts/dev-setup.sh启动服务并迁移。两个必须提前知道的坑与 Buzz Desktop 共享容器与端口Desktop 使用相同的容器名buzz-postgres、buzz-redis和默认端口:5432、:6379。just setup会复用这些服务意味着测试中继会写入 Desktop 的数据库。做读写 smoke 测试没问题但just reset会连同 Desktop 的数据一起清空。需要隔离时先停止 Desktop或用独立 Compose 项目名COMPOSE_PROJECT_NAMEbuzz-dev docker compose …just reset会清空所有本地数据并重来——包括共享同一开发栈的 Buzz Desktop 数据。先清理陈旧的 env如果 shell 从先前会话或 staging 配置继承了BUZZ_AUTH_TAG、BUZZ_RELAY_URL、BUZZ_PRIVATE_KEY中的任何一个先unset掉。陈旧的BUZZ_AUTH_TAG会让本地开发中继在第一次 CLI 写入时直接失败unset BUZZ_AUTH_TAG BUZZ_RELAY_URL BUZZ_PRIVATE_KEY错误形态是auth_error: signature verification failed——本地开发中继对此零容忍。第 2 步构建二进制cargo build --release -p buzz-relay -p buzz-cli -p buzz-admin export PATH$PWD/target/release:$PATH后续所有步骤都使用 release 二进制因此任何代码改动后都必须重新构建并重新导出 PATH。第 3 步启动中继在独立终端前台运行set -o allexport source .env # 包含 just bootstrap 生成的密钥 set o allexport buzz-relay # 第 2 步的 release 二进制监听 ws://localhost:3000 # 备选 # cargo run --release -p buzz-relay # 重新构建并以 release 运行 # just relay # DEBUG 构建 —— 热缓存下启动快 # # 但与第 2 步的 release 版本不一致 # # 需要 release 时用 just relay-release回到工作终端验证curl -s http://localhost:3000/health # → ok curl -s http://localhost:3000/_readiness # → {status:ready}健康/就绪/存活探针在独立端口上默认8080可用BUZZ_HEALTH_PORT覆盖这样 K8s 探针可以绕过认证中间件主应用端口也暴露/health以方便使用。这一点在源码中同样成立crates/buzz-relay/src/readiness.rs与crates/buzz-relay/src/router.rs分别承载_readiness路由与健康端点crates/buzz-relay/src/config.rs中BUZZ_HEALTH_PORT与BUZZ_METRICS_PORT的默认值即8080与9102。中继以开发模式启动BUZZ_REQUIRE_AUTH_TOKENfalse携带.env中生成的稳定中继身份。端口冲突处理Buzz 同时绑定三个端口——主端口、健康端口、指标端口任何一个都可能冲突。分别在不同终端导出对应变量中继终端启动buzz-relay前export BUZZ_BIND_ADDR0.0.0.0:3030 export BUZZ_HEALTH_PORT8088 export BUZZ_METRICS_PORT9202 export RELAY_URLws://localhost:3030 # 在 NIP-42 challenge 中公布 buzz-relay工作/CLI 终端用于第 4 步及 ACP harnessexport BUZZ_RELAY_URLhttp://localhost:3030 # CLI 目标 curl -s http://localhost:3030/health # → ok curl -s http://localhost:8088/_readiness # → {status:ready}本文后续代码块均展示默认端口见到localhost:3000/:8080时请在心里替换为你的覆盖值——否则 CLI 会连到 Buzz Desktop 的中继上。另外忽略just setup的 Next steps 横幅它仍打印just relaydebug 构建请使用第 2 步构建的buzz-relayrelease 二进制。用完记得停止中继在其终端 Ctrl-C。若被后台化或丢失终端用pkill -f buzz-relay——留着它会与下一位在同一台机器上照此文档操作的开发者冲突。第 4 步CLI 对中继的 Smoke 测试端到端最小序列生成身份 → 建频道 → 发消息 → 读回。这也是 Agent 验证本地中继所需的最小流程。# 生成密钥对 GEN$(buzz-admin generate-key) export BUZZ_PRIVATE_KEY$(echo $GEN | awk /Secret key:/ {print $3}) PUBKEY$(echo $GEN | awk /Public key:/ {print $3}) echo pubkey: $PUBKEY # 创建频道 —— UUID 在响应中返回 CHANNEL$(buzz channels create --name smoke-$$ --type stream --visibility open | jq -r .channel_id) echo channel: $CHANNEL # 发消息并读回 SEND$(buzz messages send --channel $CHANNEL --content hello from smoke test) EVENT_ID$(echo $SEND | jq -r .event_id) buzz messages get --channel $CHANNEL --limit 5 | jq . # 取某条消息的回复链叶子消息返回空数组 —— 正常 buzz messages thread --channel $CHANNEL --event $EVENT_ID | jq .成功时send 输出{event_id:…,accepted:true,message:}get输出消息体thread对叶子消息返回[]只有出现回复后才会有内容见第 6 步。第 5 步验证超过 1000 人的频道名单修改频道成员、发现discovery或对账reconciliation逻辑时应使用聚焦的实时中继脚本 scripts/e2e-large-channel-roster.sh。它能证明纯 DB 测试证明不了的三条边界中继提供的 kind 39002 中名单位置 1501 的成员被包含该身份可以发布频道消息定向对账targeted reconciliation之后该成员仍可被发现。只对隔离的本地数据库运行。脚本直接插入 fixture 成员然后通过 release CLI 与中继驱动发现与消息流程。保持第 3 步的 release 中继运行并使用其配置的中继密钥进行权威替换export PATH$PWD/target/release:$PATH export DATABASE_URLpostgres://buzz:buzz_devlocalhost:5432/buzz_roster_e2e export BUZZ_RELAY_URLhttp://localhost:3030 # 与第 3 步中继保持一致 export RELAY_URLws://localhost:3030 export BUZZ_RELAY_PRIVATE_KEY与 buzz-relay 使用的相同密钥 scripts/e2e-large-channel-roster.sh成功可直接观察为四行PASS。第一、四行包含大于 1000 的成员数与同一个晚加入成员公钥第二行包含被接受的 kind 9 事件 ID第三行证明定向修复后 kind 39000/39001 的 ID 与 tags 保持不变PASS discovery-before-republish channeluuid members1502 late_pubkeyhex PASS late-member-action event_idhex PASS targeted-repair-preserves-metadata-and-admin-events channeluuid PASS discovery-after-republish channeluuid members1502 late_pubkeyhex从脚本源码看它有以下硬性约束拒绝 debug 二进制拒绝解析到本仓库target/release之外的buzz/buzz-admin要求权威替换操作必须使用BUZZ_RELAY_PRIVATE_KEY绝不能用临时签名者替代。其实现方式是通过psql直接向channel_members插入 1499 个 fixture 1 个真实晚加入身份位于第 1501 位再用一次 API 添加成员强制中继经正常成员变更路径发出新的发现快照随后依次断言发现、写入、对账保真与再发现。第 6 步继续深入覆盖全部 CLI 命令12 组、54 子命令的完整清单见 crates/buzz-cli/TESTING.md从channels、canvas、messages、diff 消息、reactions、DMs、users、频道成员、workflows、feed、论坛投票到 NIP-23 notes含每个命令的预期输出与错误路径退出码。中继的 HTTP 桥接提供三个端点便于测试buzz-cli之外的其他客户端Endpoint用途POST /events提交一个已签名的 Nostr 事件POST /queryNIP-01 过滤器查询返回事件POST /countNIP-45 计数查询三者都接受 NIP-98 认证推荐开发模式下也接受X-Pubkey头回退。消息线程没有 REST API——用带#e过滤器的POST /query或buzz messages thread。三、ACP Harness与真实 Agent 的端到端联调可选buzz-acp将支持 ACP 协议的 Agentgoose、codex、claude code、buzz-agent接入中继。harness 监听事件、通过 stdio 驱动 AgentAgent 再经由 MCP 工具回复。最小配方——假设第 3 步中继在运行、第 4 步的$CHANNEL仍存在。Agent 身份必须与发送者身份不同BUZZ_ACP_RESPOND_TOanyone时仍会跳过 Agent 自己签名的事件cargo build --release -p buzz-acp export PATH$PWD/target/release:$PATH # 1. 保存第 4 步的发送者身份 —— 之后 提及 Agent 要用 SENDER_SK$BUZZ_PRIVATE_KEY # 2. 铸造全新 Agent 身份并记录其公钥 AGENT_GEN$(buzz-admin generate-key) AGENT_SK$(echo $AGENT_GEN | awk /Secret key:/ {print $3}) AGENT_PUBKEY$(echo $AGENT_GEN | awk /Public key:/ {print $3}) # 3. 将 Agent 加为 $CHANNEL 成员 —— 仍用发送者身份。 # 跳过这一步Agent 启动时只会 discovered 0 channel(s) → agent will # sit idle并静默忽略所有提及。 buzz channels add-member --channel $CHANNEL --pubkey $AGENT_PUBKEY --role member # 4. 切换到 Agent 身份并启动它。 # buzz-acp 需要 ws://不是 http://。若第 3 步把 BUZZ_RELAY_URL 设成了 # http:// 地址这里请设对应的 ws:// 等价地址同主机同端口。 export BUZZ_PRIVATE_KEY$AGENT_SK export BUZZ_RELAY_URLws://localhost:3000 # 与第 3 步一致覆盖过则如 ws://localhost:3030 export BUZZ_ACP_RESPOND_TOanyone # 默认是 owner-only测试时放开闸门 # NIP-AE 核心记忆提示注入默认开启设 BUZZ_ACP_NO_MEMORYtrue 可退出 export GOOSE_MODEauto # 必须是 auto否则 goose 会在提示处挂起 buzz-acp # 前台日志输出到 stdout放独立终端 # 可选默认日志太安静时开启逐轮追踪。 # RUST_LOGbuzz_acpdebug buzz-acp使用其他 ACP Agent默认配方假定goose在$PATH上且已配置goose --version应能打印。对 codex / claude code / buzz-agent请相应设置BUZZ_ACP_AGENT_COMMAND与BUZZ_ACP_AGENT_ARGS——参见crates/buzz-acp/README.md。缺少这些时 buzz-acp 会在启动时无法生成 Agent 子进程而失败。如果你在把 Agent 加进频道之前就启动了它之后补跑add-member即可——它会实时收到成员变更通知并订阅无需重启日志中出现membership notification: subscribing to new channel …。Justfile 还提供just goose key$AGENT_NSEC前台与just goose-bg key$AGENT_NSEC后台 screen 会话两者设置相同的环境。并行 Agent、心跳、respond-to 闸门与论坛订阅见crates/buzz-acp/README.md。测试延迟启动deferred startup启动buzz-acp前加上BUZZ_ACP_LAZY_POOLtrue。harness 应能完成连接、认证、订阅并发布在线状态而不启动配置的 ACP 子进程第一条被接受、可排队的提及应恰好启动一个子进程并分发队列中的消息。自动化覆盖在pool_lifecycle_statecrates/buzz-acp/tests/pool_lifecycle_state.rs中钉住了单次唤醒、重试/退避与过期结果行为它不能替代这种真实中继/进程的 smoke 测试。给 Agent 派活——把 shell 切回第 4 步的发送者身份并 提及 Agentexport BUZZ_PRIVATE_KEY$SENDER_SK # 第 4 步的密钥 buzz messages send --channel $CHANNEL \ --content Hey agent, reply PONG only. # 等待 10–90s然后读频道 —— Agent 的回复是来自 AGENT_PUBKEY 的 kind:9。 # 当前 ACP 构建在一轮对话中 stdout 很安静 # buzz messages get 是确认其确实运行的方式。 buzz messages get --channel $CHANNEL --limit 5 | jq .[] | {pubkey, content}回复是同一频道内的 kind:9buzz messages thread --channel id --event event_id可拉取某条提及的回复链。四、配置参考中继与 CLI 的环境变量中继的所有配置都来自环境变量。配合just setup或just relay的默认值即可开箱即用。常见覆盖项变量默认值说明BUZZ_BIND_ADDR0.0.0.0:3000主应用端口BUZZ_HEALTH_PORT8080/_liveness、/_readinessBUZZ_METRICS_PORT9102Prometheus/metricsRELAY_URLws://localhost:3000在 NIP-11 / NIP-42 challenge 中公布。注意没有BUZZ_前缀。DATABASE_URLpostgres://buzz:buzz_devlocalhost:5432/buzzREDIS_URLredis://localhost:6379BUZZ_REQUIRE_AUTH_TOKENfalse为 true 时 REST 强制 NIP-98无X-Pubkey回退BUZZ_REQUIRE_RELAY_MEMBERSHIPfalse为 true 时仅relay_members中的公钥可连接BUZZ_DRAIN_JITTER_MS0关闭优雅停机时每个活跃 WebSocket 收到1012 Service Restart关闭前的随机延迟上限毫秒。0表示所有 socket 同时关闭旧行为正值将关闭在[1, value]ms 内均匀铺开避免滚动部署时的重连惊群。大于20000的值被截断为20000MAX_DRAIN_JITTER_MS为中继 30s 硬排空超时下的关闭帧投递留出余量。空或纯空白视为未设置关闭非整数会在启动时大声失败。BUZZ_AUDIT_ENABLEDtrue防篡改的事件/媒体审计日志。设为false/0/off可跳过其 DB 连接池与写入。不会关闭独立的审核moderation审计线索。BUZZ_AUTO_MIGRATEfalse以true/1/yes/on显式开启启动时运行内置 SQLx 迁移RELAY_OWNER_PUBKEY未设置首次启动时在relay_members中引导为ownerBUZZ_ALLOW_NIP_OA_AUTHfalse启用 NIP-OA 所有者认证owner attestation用于成员资格BUZZ_WEB_DIR未设置源码态//srv/buzz/web容器态存放邀请落地页 bundle 的目录生产容器启用它使/invite/{code}始终可用BUZZ_SERVE_GIT_WEB_GUIfalse设为true或1暴露随附的 Git 仓库浏览器/与/repos/...邀请路由不依赖此开关以上大多数变量在 crates/buzz-relay/src/config.rs 中有对应解析实现例如BUZZ_DRAIN_JITTER_MS的解析、截断到MAX_DRAIN_JITTER_MS 20_000以及非整数启动失败的路径均有单元测试覆盖如60000被截断、空字符串视为未设置等断言。CLI 侧测试只关心两个变量变量默认值说明BUZZ_RELAY_URLhttp://localhost:3000CLI 中继地址接受ws(s)://并规范化BUZZ_PRIVATE_KEY—必需nsec1…或 64 位 hexBUZZ_AUTH_TAG未设置可选的 NIP-OA 所有者认证 JSON五、故障排查速查表症状原因修复代码改动后出现relay error 500或400: restricted: not a channel member二进制陈旧重新构建并重新导出PATH或直接cargo run中继启动时Address already in usemacOS 为 os error 48Linux 为 98另一个中继或陈旧进程占用了:3000/:8080/:9102或你的覆盖端口指标监听失败会以metrics_bind生命周期终态reasonbind报出。用lsof -iTCP:3000,8080,9102 -sTCP:LISTEN或覆盖后的端口检查。杀掉占用者pkill -f buzz-relay或用第 3 步的端口覆盖块。若已覆盖仍冲突说明之前的开发者留了一个运行在相同替代端口上的中继——杀掉它或换新端口auth_error: BUZZ_PRIVATE_KEY is required环境变量未导出到 CLI 的 shellexport BUZZ_PRIVATE_KEY...或传--private-keyauth_error: BUZZ_AUTH_TAG verification failed … signature verification failed从父 shell 继承了陈旧的BUZZ_AUTH_TAG本地开发中继拒绝它unset BUZZ_AUTH_TAG见第 1 步的清理块关闭的中继上auth-required: verification failed需要 NIP-OA 认证把BUZZ_AUTH_TAG设为主人签发的 JSON或放宽BUZZ_REQUIRE_RELAY_MEMBERSHIPchannels create后channels list为空CLI 不回显频道 UUID用第 4 步的过滤器或POST /query携带{kinds:[39002]}ACP Agent 忽略所有事件默认BUZZ_ACP_RESPOND_TOowner-only且未配置 owner测试时设BUZZ_ACP_RESPOND_TOanyoneACP 日志discovered 0 channel(s)/no channel subscriptions resolvedAgent 身份不是任何频道的成员用另一个身份执行buzz channels add-member --channel $CHANNEL --pubkey $AGENT_PUBKEY --role memberGOOSE_MODE警告、Agent 挂起未设置export GOOSE_MODEauto本地测试通过但 CI 失败忘了跑just cijust ci执行整门检查fmt、clippy、单元测试、desktop/web 构建六、结语一条可复现的验证流水线把整份 TESTING.md 串联起来就得到一条从代码到真实 Agent 行为的完整验证流水线静态与单元层just test-unit零基础设施覆盖核心、认证、CLI、ACP 信任边界、数据库迁移器、多租户回放与授权决策网格集成层just test自动拉起 Postgres/Redis 后跑 DB 与集成套件实时中继层just bootstrapjust setup准备环境release 构建buzz-relay后用 NIP-98 签名的buzzCLI 完成建频道、发消息、读回的最小 smoke边界压力层scripts/e2e-large-channel-roster.sh 以四行 PASS 证明千人以上名单的发现、写入与定向对账保真真实 Agent 层buzz-acpBUZZ_ACP_RESPOND_TOanyone驱动 goose/codex/claude code/buzz-agent 完成带成员资格的 提及回复闭环pool_lifecycle_state测试再钉住延迟启动的生命周期行为。每一步都有对应的源码与脚本可作为证据环境变量语义见 crates/buzz-relay/src/config.rs任务编排见 JustfileCLI 全量命令清单见 crates/buzz-cli/TESTING.md。照此流程无论是开发者、测试人员还是 Agent 本身都能在数分钟内获得一台可信的本地中继并完成任意一次端到端验证。【免费下载链接】buzzA hive mind communication platform项目地址: https://gitcode.com/GitHub_Trending/buzz14/buzz创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进