news 2026/9/12 18:22:19

ente-test-support 集成测试基础设施:在 Rust 测试中一键拉起 Museum、临时 Postgres 与本地对象存储

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ente-test-support 集成测试基础设施:在 Rust 测试中一键拉起 Museum、临时 Postgres 与本地对象存储

ente-test-support 集成测试基础设施:在 Rust 测试中一键拉起 Museum、临时 Postgres 与本地对象存储

【免费下载链接】ente💚 End-to-end encrypted cloud for everything.项目地址: https://gitcode.com/GitHub_Trending/en/ente

导读

ente 仓库的 Rust 侧提供了一批针对后端 Museum 的集成测试,而ente-test-support(源码位于 rust/crates/test-support)正是承载这些测试的轻量级测试基础设施:它能在测试进程内自动启动一个由临时 Postgres 与本地内存对象存储支撑的 Museum 实例,并通过 Cargo feature 门控,让普通cargo test默认跳过、按需开启。读完本文,你将掌握这套测试装置的工作原理、环境依赖、运行命令,以及如何在其上编写自己的端到端测试。

它解决什么问题

Museum 是 ente 的后端服务(见 server),其正常运行需要依赖数据库与对象存储。要让 Rust 集成测试真正覆盖"账号注册、同步、导出、分享"等全链路行为,测试环境就必须具备:

  • 一个真实可用的 Museum HTTP 服务;
  • 一个可读写的关系型数据库(Postgres);
  • 一个兼容 S3/B2 语义的对象存储。

ente-test-support的价值在于把这些外部依赖全部"内嵌"进测试进程:Postgres 由 postgresql_embedded 按需下载并管理,对象存储则是一个运行在线程内的极简 HTTP 服务器,Museum 二进制由go build现场编译。整个环境是临时的、进程内的、随测试销毁的,无需开发者预先安装 Postgres、配置 S3 或准备任何密钥。

环境准备与依赖

按照 rust/crates/test-support/README.md 的说明,运行这类测试只需满足两点:

  1. PATH 中必须有go命令——用于编译并启动 Museum。server.rs中的require_go()会先执行go version校验,失败时直接返回 "Museum live tests requiregoon PATH"(rust/crates/test-support/src/server.rs);
  2. Postgres 二进制无需手动安装,postgresql_embedded会在首次使用时自动下载并缓存。

关于缓存位置,值得展开说明:postgresql_embedded默认把二进制放在$HOME/.theseus,而 postgres.rs 中的install_dir()将其重定向到系统约定的缓存目录下的.theseus/postgresql(例如 Linux 上为$XDG_CACHE_HOME~/.cache/.theseus/postgresql),避免污染家目录根级。依赖配置见 Cargo.toml:postgresql_embedded = "0.20.4"启用了blockingrustlstheseus三个 feature,同时使用tokiort-multi-thread)、uuidv4)与dirs。该 crate 标记为publish = false,属于仓库内部的专用测试库,不对外发布。

架构组成:四个协同模块

src/lib.rs 对外只暴露Museum类型与少量常量,内部按职责拆分为四个模块:

模块职责
postgres.rs管理临时 Postgres 实例,创建测试数据库ente_test
object_store.rs线程内运行的极简 HTTP 对象存储(内存版 S3)
server.rs编译并启动 Museum,注入全部环境变量,等待就绪
process.rs子进程封装:日志落盘、状态检查、Drop 时回收

临时 Postgres

postgres.rs 的start()构造Settings时使用temporary: true、随机空闲端口(free_port()),启动后调用create_database("ente_test")创建专用数据库,并通过host()/port()/username()/password()/database()向外部暴露连接参数。

内存对象存储

object_store.rs 用TcpListener绑定随机端口,在后台线程里循环 accept 连接,实现了一个最小可用的对象存储协议:

  • PUT记录对象路径与长度,返回200 OK
  • HEAD按路径返回200(带 Content-Length)或404 Not Found
  • 其他方法一律返回405 Method Not Allowed

对象数据存放在线程内的HashMap<String, usize>中(只记大小、不落盘),足以支撑 Museum 上传/探测对象的逻辑。

Museum 的编译与启动

server.rs 的start()做了三件事:

  1. 定位 server 目录:由CARGO_MANIFEST_DIR(即本 crate 目录)向上回溯三层得到仓库根目录,再拼接server,对应仓库根下的 server 目录;
  2. 编译 Museum:执行go build -o <临时目录>/museum ./cmd/museum
  3. 注入环境变量并启动:通过Command为 Museum 进程设置全套ENTE_*环境变量。

就绪探测与日志

启动后wait_for_museum()会在90 秒内以500ms间隔轮询GET /ping,直到返回 HTTP 200 才认为就绪;超时或进程提前退出时,会把保存在临时目录logs/museum.log中的日志摘要一并抛出,便于排查(见 server.rs)。子进程在 Drop 时会被 kill 并回收(process.rs)。

环境变量注入清单

Museum 通过环境变量读取配置。server.rsstart()注入的变量是理解整套测试装配的关键,归纳如下:

数据库连接(指向临时 Postgres)

变量
ENTE_DB_HOST/ENTE_DB_PORT临时 Postgres 地址
ENTE_DB_NAMEente_test
ENTE_DB_USER/ENTE_DB_PASSWORD临时实例的账号密码
ENTE_DB_SSLMODEdisable

对象存储(指向内存 S3)

变量
ENTE_S3_ARE_LOCAL_BUCKETStrue,声明桶为本地的,不校验真实云凭证
ENTE_S3_B2_EU_CEN_KEY/ENTE_S3_B2_EU_CEN_SECRETchangeme/changeme1234测试占位凭证
ENTE_S3_B2_EU_CEN_ENDPOINT内存对象存储地址
ENTE_S3_B2_EU_CEN_REGIONeu-central-2
ENTE_S3_B2_EU_CEN_BUCKET/ENTE_SPACE_ASSETS_PRIMARYBUCKETb2-eu-cen

HTTP 与测试辅助

变量
ENTE_HTTP_PORT随机空闲端口,测试据此得到 endpoint
ENTE_CREDENTIALS_FILE指向一个空文件(见下文"空配置文件的用意")
ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_SUFFIX@example.org
ENTE_INTERNAL_HARDCODED_OTT_LOCAL_DOMAIN_VALUE123456
ENTE_JOBS_CRON_SKIPtrue,跳过定时任务,保证测试确定性

其中HARDCODED_OTT = "123456"HARDCODED_OTT_EMAIL_SUFFIX = "@example.org"定义在 src/lib.rs:任何以@example.org结尾的测试邮箱都可以直接用固定 OTP123456完成登录,从而绕开真实邮件发送链路。

空配置文件的用意

write_config()特意写一个空文件作为ENTE_CREDENTIALS_FILE,源码注释说明了原因:不能在这里写任何配置,否则会覆盖开发者本地的museum.yaml;而空文件本身又能"屏蔽"掉任何真实的本地凭据文件,防止测试意外连到生产/开发环境。

如何使用:Cargo feature 门控与运行命令

按 README 约定,使用该装置的测试统一通过名为museum的 Cargo feature 门控。例如 CLI crate 的 Cargo.toml 中声明了museum = [],对应集成测试文件(如 rust/apps/cli/tests/sync.rs)首行就是#![cfg(feature = "museum")]——意味着不启用该 feature 时,普通cargo test会直接跳过这些测试,不影响日常开发。

启用 feature 后运行:

cargo test -p ente-rs --features museum

(以上命令即 rust/crates/test-support/README.md 中给出的标准调用方式。)从源码结构看,当前仓库中使用ente-test-support的集成测试还包括:

  • rust/apps/cli/tests/paste.rs、rust/apps/cli/tests/sync.rs(CLI 的粘贴与同步全链路);
  • rust/crates/accounts/tests/accounts.rs、rust/crates/contacts/tests/contacts.rs、rust/crates/space/tests/space.rs(账号、联系人、Space 等模块的集成测试)。

Museum::run 与 run_async

src/museum.rs 提供两个入口:

  • Museum::run(|museum| ...):同步版本,闭包接收&Museum,内部用catch_unwind包裹测试体,任何错误或 panic 都会触发temp_dir.retain()——保留临时目录并打印路径,方便事后检查日志与数据;
  • Museum::run_async(|endpoint| ...):异步版本,内部新建 tokio runtime 并block_on,闭包直接拿到endpoint字符串。

Museum对外暴露两个方法:endpoint()返回http://127.0.0.1:<port>形式的服务地址,temp_dir()返回临时工作目录。临时目录以ente-test-<uuid>命名,正常结束时随 Drop 自动删除(src/museum.rs 中的TempDir)。

一个真实的测试示例

以 rust/apps/cli/tests/sync.rs 为例,可以看到完整的用法模式:

#[test] fn sync() -> TestResult { Museum::run(|museum| { let cli = support::cli_session(museum, "sync")?; let export_dir = museum.temp_dir().join("export"); std::fs::create_dir_all(&export_dir)?; cli.run_ok(&[ "account", "create", "--email", "sync-test@example.org", "--password", "sync-test-password", "--endpoint", museum.endpoint(), "--export-dir", export_dir.to_str().unwrap(), "--otp", HARDCODED_OTT, // 123456 ])?; let output = cli.run_ok(&["export"])?; assert!(output.contains("Sync completed"), "export did not sync: {output}"); Ok(()) }) }

这个测试在 5 行内完成了"启动全套后端 → 注册账号(用固定 OTP 验证)→ 执行导出同步 → 断言输出"的完整闭环,充分体现了这套基础设施对集成测试的简化能力。

测试账号夹具与常量

src/lib.rs 还内置了一个account_fixture模块,供需要"预置账号密钥"的测试复用:

  • PASSWORD = "museum-account-fixture-password"
  • KEK(密钥加密密钥)与其KEK_SALT为预计算的固定值,注释说明其派生参数为 Argon2id(密码, 16 × 0x4d 盐, 256 MiB 内存, 16 次迭代);
  • MEM_LIMIT = 268_435_456(256 MiB)、OPS_LIMIT = 16,与 Argon2id 参数一一对应。

使用预计算 KEK 可以让涉及加密导出的测试跳过昂贵的密钥派生过程,同时保证加解密结果可预期。

运行前提与注意事项

  • 必须启用museumfeature,否则相关测试被#![cfg(feature = "museum")]直接裁剪,表现为"测试不存在"而非"测试失败";
  • 首次运行会下载 Postgres 二进制(缓存在缓存目录的.theseus/postgresql下),需要网络与磁盘空间,之后运行不再重复下载;
  • 需要go工具链编译 Museum(对应 server 目录下的cmd/museum),编译产物写入测试临时目录,不做全局安装;
  • 端口全部动态分配:Postgres 端口、对象存储端口、Museum HTTP 端口均通过bind(0)获取随机空闲端口(net.rs),多测试并行时不会冲突;
  • 环境隔离:测试通过环境变量注入配置且使用空ENTE_CREDENTIALS_FILE,不会读取开发者本地的museum.yaml或真实云凭证;
  • 失败可诊断:一旦 Museum 未就绪、进程提前退出或测试失败,临时目录会被保留(终端会打印retaining integration test temp dir: <路径>),其中logs/museum.log是首选的排障入口。

小结

ente-test-support是一个"小而美"的测试基础设施:它以极少的对外 API(Museum::run/run_asyncendpoint()temp_dir()HARDCODED_OTTaccount_fixture)封装了"编译 Go 后端 + 下载托管 Postgres + 内存对象存储 + 子进程生命周期管理"的全部复杂度。理解它的环境变量注入清单与临时目录保留策略,是你在 rust/apps/cli/tests 与 rust/crates 各模块测试目录下阅读、扩展或新写集成测试时最重要的前置知识。

【免费下载链接】ente💚 End-to-end encrypted cloud for everything.项目地址: https://gitcode.com/GitHub_Trending/en/ente

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 18:22:11

液冷板材料选型:不锈钢 vs 铝合金 vs 铜合金全面对比

液冷板最常用的材料是6061铝合金&#xff08;成本适中、工艺成熟、重量轻&#xff09;&#xff0c;不锈钢&#xff08;304/316&#xff09;适用于强腐蚀环境但导热差、加工难&#xff0c;铜合金适用于超高功率散热但成本高。储能液冷板选6061铝合金是当前最优解。液冷板的材料选…

作者头像 李华