Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .config/nextest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# CI 用 cargo-nextest 跑测试(`cargo test --workspace` 本地照常能用,这里的分组它不认)。
#
# nextest 把每个测试放进独立进程、跨二进制并行。cargo test 是 140 个二进制**串行**、
# 各自内部并行——多数二进制只有一两个测试,机器大部分时间在等一个测试跑完再起下一个进程;
# 换 nextest 后运行阶段本地 136s → 60s。代价是 cargo test 里隐含的两条隔离假设不再成立,
# 下面两条规则就是把它们显式写出来:
#
# 1. store 的集成测试之间**不能并行**。它们共用一个库,好几处断言的是全库状态——
# 「只排了一个向量索引构建任务」、timeline 重算时的行锁——别的文件同时写就会多数或死锁。
# cargo test 时它们各在自己的二进制里顺序跑,天然满足;这里用一个 max-threads = 1 的组复现。
# 2. a_queued_job_wakes_an_idle_worker 的三个测试共用 utopia_jobs 通知频道,靠进程内的
# 静态 Mutex 串行,而且要求库里没有别的进程在排任务。每个测试一个进程后 Mutex 失效,
# 别的测试入队的通知也会把它叫醒。threads-required = num-cpus 让它独占全部并发槽:
# 跑它时别的测试一个都不跑,比 Mutex 更强。
[test-groups]
store-serial = { max-threads = 1 }

[[profile.default.overrides]]
filter = 'binary(a_queued_job_wakes_an_idle_worker)'
threads-required = "num-cpus"

[[profile.default.overrides]]
filter = 'package(utopia-store)'
test-group = 'store-serial'
15 changes: 13 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,22 @@ jobs:
run: cargo run -p utopia-store --example migrate
env:
UTOPIA_DATABASE_URL: postgres://utopia:utopia@localhost:5432/utopia
# 用 nextest 跑:cargo test 把 140 个测试二进制串行执行,运行阶段 86s;nextest 跨二进制
# 并行,本地 136s → 60s。隔离规则在 .config/nextest.toml 里,那里解释了为什么
# store 的测试要串行、哪一个要独占。装的是官方预编译二进制(几秒),用 cargo install
# 要编三四分钟;版本钉死,升级要有人看一眼;装过的话在 ~/.cargo/bin 缓存里,跳过
- name: 装 nextest
run: |
command -v cargo-nextest && exit 0
curl -LsSf https://get.nexte.st/0.9.146/linux | tar zxf - -C "${CARGO_HOME:-$HOME/.cargo}/bin"
- name: Test
run: cargo test --workspace
# 装了 Poppler 就必须真的用它测:没有它时 PDF 回退的那个测试会跳过,
# 而一个静静跳过的测试等于没写(#248)。库同理:有库就**必须**连
# (UTOPIA_TEST_REQUIRE_DB),连库测试没跑成要红,不能跳过显示绿色
# (UTOPIA_TEST_REQUIRE_DB),连库测试没跑成要红,不能跳过显示绿色。
# nextest 不跑 doctest,第二条补上——现在一个都没有,但有了不该悄悄不跑
run: |
cargo nextest run --workspace
cargo test --workspace --doc
env:
UTOPIA_TEST_REQUIRE_PDFTOTEXT: "1"
UTOPIA_DATABASE_URL: postgres://utopia:utopia@localhost:5432/utopia
Expand Down
4 changes: 3 additions & 1 deletion CONTRIBUTING.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@ let Ok(url) = std::env::var("UTOPIA_DATABASE_URL") else {

```bash
export UTOPIA_DATABASE_URL=postgres://utopia:utopia@localhost:5432/utopia
cargo run -p utopia-store --example migrate # 空库先迁移;CI 的 backend job 也是这么做的
cargo run -p utopia-store --example migrate # 空库先迁移;CI 的 test job 也是这么做的
cargo test --workspace
```

CI 实际用的是 `cargo nextest run --workspace`(快一倍,跨二进制并行),隔离规则在 `.config/nextest.toml`。本地装了 nextest 的话用它更接近 CI;没装 `cargo test` 也一样能过。

## 几条会被 review 拦下来的

**迁移编号别撞。** `migrations/` 按序号前滚。开 PR 前看一眼 `main` 上最新的号 —— 两个分支各写一个 `0011_` 已经发生过一次,合并之后谁都跑不起来。
Expand Down
17 changes: 15 additions & 2 deletions crates/utopia-server/src/api/mcp_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,21 @@ impl Fixture {
.await?;
let dir = self.dir.clone();
drop(self);
std::fs::remove_dir_all(dir)?;
Ok(())
// drop 掉的 tantivy IndexWriter 不等合并线程:它们还会往 search/ 里写几个段文件,
// 立刻删目录会撞 "Directory not empty"——nextest 下每个测试独占进程、时序更紧,
// 五次里能碰上一次。等它们写完再删,几十毫秒的事;其余 fixture 都是 `let _ =`
// 直接忽略,这里保留报错是为了目录真删不掉时看得见
let mut attempt = 0;
loop {
match std::fs::remove_dir_all(&dir) {
Ok(()) => return Ok(()),
Err(_) if attempt < 50 => {
attempt += 1;
tokio::time::sleep(std::time::Duration::from_millis(20)).await;
}
Err(e) => return Err(e.into()),
}
}
}
}

Expand Down