use std::{fs, path::Path};
mod support;
const MSRV: &str = "1.87";
const VERSION: &str = "0.2.3";
const FEATURES: &[&str] = &[
"default",
"core",
"rest",
"rpc",
"resil",
"cache",
"cache-redis",
"discovery",
"discovery-etcd",
"discovery-kube",
"observability",
"observability-prometheus-client",
"otlp",
"profiling",
"db",
"db-sqlite",
"db-mysql",
"db-postgres",
];
#[test]
fn workspace_manifest_declares_version_msrv_and_feature_boundaries() {
let manifest = read("Cargo.toml");
support::assert_contains_all(
&manifest,
&[
&format!("version = \"{VERSION}\""),
"edition = \"2024\"",
&format!("rust-version = \"{MSRV}\""),
"rust-version.workspace = true",
"default = [\"core\", \"rest\", \"rpc\", \"resil\", \"cache\", \"discovery\", \"observability\", \"db-sqlite\"]",
"cache-redis = [\"cache\", \"resil\", \"dep:redis\", \"dep:sha1_smol\", \"dep:uuid\"]",
"discovery-etcd = [\"discovery\", \"dep:etcd-client\"]",
"discovery-kube = [\"discovery\", \"dep:kube\", \"dep:k8s-openapi\", \"dep:tokio-stream\", \"k8s-openapi/v1_30\"]",
"observability-prometheus-client = [\"observability\", \"dep:prometheus-client\"]",
"otlp = [\"observability\"",
"profiling = [\"core\", \"dep:pyroscope\"]",
"db-mysql = [\"db\", \"sqlx/mysql\"]",
"db-postgres = [\"db\", \"sqlx/postgres\"]",
],
);
for manifest_path in [
"crates/rs-zero-cli/Cargo.toml",
"examples/rest-hello/Cargo.toml",
"examples/rpc-hello/Cargo.toml",
] {
let content = read(manifest_path);
assert!(
content.contains("rust-version.workspace = true"),
"{manifest_path} must inherit workspace rust-version"
);
}
}
#[test]
fn stability_docs_link_policy_feature_matrix_and_migrations() {
let readme = read("README.md");
support::assert_contains_all(
&readme,
&[
"API 稳定性",
"docs/api-stability.md",
"docs/feature-matrix.md",
"docs/migrations/README.md",
&format!("Rust `{MSRV}`"),
],
);
let docs_index = read("docs/README.md");
support::assert_contains_all(
&docs_index,
&[
"API 稳定性",
"api-stability.md",
"feature-matrix.md",
"migrations/README.md",
],
);
let stability = read("docs/api-stability.md");
support::assert_contains_all(
&stability,
&[
"不承诺 `1.0` 稳定性",
&format!("当前 MSRV 是 Rust `{MSRV}`"),
"feature matrix",
"migrations/README.md",
"稳定面",
"非承诺项",
"cargo +1.87 check",
],
);
}
#[test]
fn feature_matrix_covers_manifest_features_and_validation_commands() {
let matrix = read("docs/feature-matrix.md");
for feature in FEATURES {
assert!(
matrix.contains(&format!("`{feature}`")),
"feature matrix must document `{feature}`"
);
}
support::assert_contains_all(
&matrix,
&[
"cargo check -p rs-zero --no-default-features",
"cargo check -p rs-zero --no-default-features --features rest,rpc",
"cargo check -p rs-zero --no-default-features --features db-mysql,db-postgres,cache-redis,discovery-etcd,discovery-kube,otlp",
"cargo test -p rs-zero --test service_group",
"cargo package -p rs-zero --allow-dirty",
"cargo package -p rs-zero-cli --allow-dirty",
"scripts/external-integration.sh all",
],
);
}
#[test]
fn migration_docs_define_current_baseline_and_entry_template() {
let index_path = Path::new("docs/migrations/README.md");
let baseline_path = Path::new("docs/migrations/0.1.md");
assert!(index_path.exists(), "migration index must exist");
assert!(baseline_path.exists(), "0.1 migration baseline must exist");
let index = read(index_path);
support::assert_contains_all(
&index,
&["0.1.x", "条目模板", "影响范围", "迁移步骤", "MSRV"],
);
let baseline = read(baseline_path);
support::assert_contains_all(
&baseline,
&[
&format!("workspace 版本:`{VERSION}`"),
&format!("MSRV:Rust `{MSRV}`"),
"默认 runtime features",
"外部 adapter features",
"升级检查清单",
],
);
}
#[test]
fn verify_yaml_runs_api_stability_guard() {
let verify = read(".helloagents/verify.yaml");
support::assert_contains_all(
&verify,
&[
"cargo test --test api_stability",
"cargo test -p rs-zero --test service_group",
"cargo test -p rs-zero --test service_group_adapters",
],
);
}
fn read(path: impl AsRef<Path>) -> String {
fs::read_to_string(path.as_ref()).unwrap_or_else(|err| {
panic!("read {}: {err}", path.as_ref().display());
})
}