提交前在仓库根目录运行以下三条命令,与 CI(Windows 与 Ubuntu)一致,不依赖 Docker:
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
工具链由 rust-toolchain.toml 固定为 1.98.0,CI 使用同一版本。
本机 cargo test --workspace 不需要 Docker、Trino 或 PostgreSQL:连接真实引擎的测试全部标为 #[ignore],在本机只编译、不运行。
crates/ontoforge-engine/tests/trino_it.rs:真实 Trino 上的查询、describe_tables类型 golden、值解码 golden、printer 固定语料往返、超时后服务端查询被取消、catalog 可见性与 drift。crates/ontoforge/tests/cli_trino_it.rs:ontoforge validate --online --check-pk --server-config ci/ontoforge-server.ci.toml examples/ontologies/aviation退出码 0;另用临时 ontology 绑定 seed 中唯一没有 PRIMARY KEY 约束的demo.aviation.flights_dup,断言--check-pk报出重复键与 NULL 键两条ONT-V18、退出码 1。- 两者都读环境变量
ONTOFORGE_TRINO_URL;以--ignored运行而该变量缺失时测试会 panic,不会静默通过。 - PR 的
integration作业(.github/workflows/ci.yml)起 PostgreSQL 17 与 Trino 483,用ci/pg/seed.sql从 aviation fixture 导入数据,再运行这两个目标;另有一步检查两个目标列出的 ignored 测试数都大于 0。 - golden 预期值写在测试源码的内联快照里。标有
PROVISIONAL注释的预期值尚未经真实 Trino 确认,首次 CI 运行不一致时按日志修正并删除该注释。
在装有 Docker 的 Linux 上手动复现(与 CI 步骤相同):
docker run -d --name ontoforge-pg -p 5432:5432 -e POSTGRES_PASSWORD=ontoforge-ci-only postgres:17.11@sha256:2d2b8998d31037bf721cfdf764d76ba74171b4fab3431b7f72c27c56ddbdf9e3
export PGHOST=localhost PGUSER=postgres PGPASSWORD=ontoforge-ci-only
psql -v ON_ERROR_STOP=1 -d postgres -c 'CREATE DATABASE demo' -c 'CREATE DATABASE editstore'
psql -v ON_ERROR_STOP=1 -v fixtures="$PWD/examples/ontologies/aviation/bindings/dev/fixtures" -d demo -f ci/pg/seed.sql
docker run -d --name trino --network host -v "$PWD/ci/trino/catalog:/etc/trino/catalog:ro" trinodb/trino:483@sha256:db58cc93e593a2706553745f276bb119c9810e69918be56ecde088ba7ccb0534
# 等到 curl -fsS http://localhost:8080/v1/info 的 "starting" 为 false
ONTOFORGE_TRINO_URL=http://localhost:8080 cargo test -p ontoforge-engine --test trino_it -- --ignored
ONTOFORGE_TRINO_URL=http://localhost:8080 cargo test -p ontoforge --test cli_trino_it -- --ignored
edit store 的 conformance 在 Windows 与 Ubuntu 的 test 作业里用 SQLite 运行,同一套用例在 Linux CI 的真实 PostgreSQL 17 上再运行一次(#[ignore],以 --ignored 运行)。
| 测试目标 | crate | 所需环境 |
|---|---|---|
conformance_pg、reload_pg、scope_store、migrate_pg、history_masking、import |
ontoforge-storage |
ONTOFORGE_PG_URL,或 --features embedded-pg |
reload_trino_it |
ontoforge-storage |
ONTOFORGE_TRINO_URL 与 ONTOFORGE_PG_URL(后者必须是 Trino catalog editstore 映射的数据库) |
rowpred_trino_it |
ontoforge-auth |
ONTOFORGE_TRINO_URL,且 demo 库里已用 ci/pg/rowpred_corpus.sql 建好语料表 |
本机跑 PostgreSQL 用例有两种方式:
# 已有 PostgreSQL(每个测试在其中建自己的一对 schema)
ONTOFORGE_PG_URL=postgres://user:password@localhost:5432/editstore cargo test -p ontoforge-storage --test conformance_pg -- --ignored
# 没有 PostgreSQL:postgresql_embedded 首次运行时从 GitHub 下载 PG 二进制,之后复用
cargo test -p ontoforge-storage --features embedded-pg --test conformance_pg -- --ignored
没有设置变量也没有 embedded-pg 时,--ignored 的 PostgreSQL 测试会 panic,不会静默通过。
CI 对应的步骤在 integration 作业:Edit store conformance (PostgreSQL)、Row predicate corpus (Trino)、Reload visibility probe (Trino + PostgreSQL),以及 Ignored tests are actually there(上表每个目标列出的 ignored 测试数都必须大于 0)。test 作业另有一步 cargo clippy -p ontoforge-storage --features embedded-pg --all-targets,只编译检查,保证本机 PG 路径不失修。Trino 的 edit store catalog(ci/trino/catalog/editstore.properties)需要 postgresql.array-mapping=AS_ARRAY,部署说明见 docs/edit-store.md。
.github/workflows/nightly.yml 每天运行一次,也可手动触发 workflow_dispatch。Trino 483/484 使用 PostgreSQL JDBC catalog 与真实 MinIO S3 warehouse。ci/minio/Dockerfile 固定官方 MinIO source commit 和 Go builder digest,复用原依赖图生成 scratch 测试镜像;自建产物保留 DEVELOPMENT 标识,不宣称官方预编译或 bit-reproducibility。版本、SHA256、source/runner 身份及运行证据写入 target/phase072-minio/<run-id>/provenance.json。
# Linux or Windows Git Bash; one owner per host, CARGO_BUILD_JOBS=2.
bash ci/iceberg-services.sh contract --trino 483
bash ci/iceberg-services.sh contract --trino 484
bash ci/iceberg-services.sh nightly --trino 483
# Verify the SDK helper extracted from the built image.
ONTOFORGE_ICEBERG_STATE=/path/to/private/helper-state.json bash ci/iceberg-services.sh helper-test
# Recovery cleanup; set ONTOFORGE_ICEBERG_STATE before starting the run.
bash ci/iceberg-services.sh cleanup --state /path/to/private/state.jsoncontract 验证 source/copy 均为29行、精确 Rust 测试、PG 的 s3://warehouse/ metadata 与非空对象,并只重启 MinIO/Trino后复验,不重新 CTAS。nightly 再执行原有 Action atomicity/race/idempotency/outbox、Trino Action、完整 Engine/CLI corpus;各目标必须发现且实际执行非零测试。容器、network、volumes 按本次 owner label 和身份清理,已有服务不受影响;PG/Trino只发布 loopback 随机端口。
临时凭据只进入私有 env/catalog,Trino使用环境凭据 provider;原始日志按本次真实凭据扫描通过后才可公开。CI为主fixture和helper分别保存私有state,并用两个独立 always() 步骤补偿清理,第一项失败也会尝试第二项。helper在创建容器前持久化owner和lock token;清理失败保留state供重试。state不存在时无操作,资源或锁身份无法核验时拒绝删除。只有 schedule 触发且失败 才运行拥有 issues: write 的 report-failure;手动触发不创建 issue/comment,测试job始终只有 contents: read。
公司环境与不能公开的数据只通过 crates/ontoforge/tests/private_fixtures.rs 在本地验证,CI 不运行这个测试目标。
- 环境变量
ONTOFORGE_PRIVATE_FIXTURES指向仓库之外的目录。 - 目录约定:每个子目录
<name>/是一组 fixture,包含<name>/ontology/(ontology 目录)与<name>/ontoforge-server.toml(服务配置,密钥只用*_env/*_file引用)。缺任一项的子目录被跳过。 - 运行:
ONTOFORGE_PRIVATE_FIXTURES=/path/outside/repo cargo test -p ontoforge --test private_fixtures -- --ignored。每组执行ontoforge validate --online --server-config <name>/ontoforge-server.toml <name>/ontology,退出码必须为 0。 - 不得把公司的绑定、catalog / 表名、配置或数据提交进仓库,也不得出现在 issue、PR 或 CI 日志中。
诊断输出、CLI 输出等用 insta 快照固定。
- 更新快照:
INSTA_UPDATE=always cargo test -p <crate>。本机未装cargo-insta也可使用。 - 更新后用
git diff逐个审阅.snap的变化,确认是预期改动再提交。 - CI 环境(
CI=true)下 insta 不写快照,缺失或不一致的快照会让测试失败,这是期望行为。 - 快照里不要出现绝对路径、耗时或机器相关内容。
- 行尾由
.gitattributes统一为 LF,不要提交 CRLF 的 fixture 或快照。 - 测试里不得调用
std::env::set_var:edition 2024 下它是unsafe,会被unsafe_code = "forbid"拦截。需要给子进程设环境变量时使用Command::env。
- 位置:
examples/ontologies/invalid/<code>-<slug>/。 - 目录名前缀决定期望的诊断码,例如
v04-unknown-field期望ONT-V04。 - 新增样例只需加目录并生成快照,不需要改测试代码。
诊断码(ONT-V*、ONT-E*、ONT-W*)一经发布不得复用或改义。废弃的诊断码保留编号,不再分配给新诊断。
- 命名遵循 ADR-0002(crate 前缀
ontoforge-)。 - 禁止沿用参考仓库的标识符,禁止复制参考仓库的代码。
- ontology 定义文档的格式以 ADR-0012 为准。
- 定义文档与 manifest 的 JSON Schema 位于
schemas/,由ontoforge schema export生成;IR 改动后需重新导出。 - yaml-language-server 的 modeline(
# yaml-language-server: $schema=...)只作用于它所在的那个 YAML document,不会延续到---之后的 document,见 redhat-developer/vscode-yaml#1066 。因此examples/ontologies/aviation的定义文件在每个---的下一行都写一次定义 modeline。新增 document 时同样写在---的下一行,测试aviation_definition_documents_start_with_modeline会检查。 - 多文档文件以项目级
yaml.schemas为准。仓库提供.zed/settings.json(Zed,位于lsp.yaml-language-server.settings.yaml.schemas)与.vscode/settings.json(VS Code + Red Hat YAML 扩展,yaml.schemas),把./schemas/ontoforge-definition.schema.json关联到examples/ontologies/**/*.yaml,并用!examples/ontologies/**/ontology.yaml排除 manifest。 - manifest 通过自己第 1 行的 manifest modeline 关联 manifest schema(modeline 优先于 settings)。没有 modeline 的 manifest 不关联任何 schema,不会被误按定义 schema 校验。
- 两份配置必须保持一致,且只写严格 JSON(不写注释),由测试
editor_configs_associate_definition_schema_with_examples检查。 - JetBrains IDE 不读取上述两个文件:在 Settings → Languages & Frameworks → Schemas and DTDs → JSON Schema Mappings 中手动添加映射,
schemas/ontoforge-definition.schema.json对应定义文件,schemas/ontoforge-manifest.schema.json对应ontology.yaml。 - 补全触发:yaml-language-server 不声明补全触发字符,输入
kind:后不会自动弹出补全,需要按 Ctrl+Space(或键入值的首字母)。