138 lines
6.3 KiB
Rust
138 lines
6.3 KiB
Rust
// file: crates/ksp-core-lib/tests/workspace_dependencies.rs
|
|
// version: 6
|
|
|
|
//! Workspace-level dependency policy canaries owned by the foundational KSP test surface.
|
|
|
|
fn workspace_root() -> std::path::PathBuf {
|
|
let manifest_directory = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
|
|
let parent = manifest_directory.parent();
|
|
assert!(parent.is_some(), "core crate must have a crates directory parent");
|
|
let parent = match parent {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return manifest_directory.to_path_buf(),
|
|
};
|
|
let root = parent.parent();
|
|
assert!(root.is_some(), "core crate must have a workspace root");
|
|
return match root {
|
|
std::option::Option::Some(value) => value.to_path_buf(),
|
|
std::option::Option::None => parent.to_path_buf(),
|
|
};
|
|
}
|
|
|
|
#[test]
|
|
fn workspace_dependency_table_does_not_activate_consumer_features() {
|
|
let manifest_path = workspace_root().join("Cargo.toml");
|
|
let manifest = std::fs::read_to_string(manifest_path.as_path());
|
|
assert!(manifest.is_ok(), "workspace manifest must be readable during integration tests");
|
|
let manifest = match manifest {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let workspace_dependencies = match manifest.split("[workspace.dependencies]").nth(1) {
|
|
std::option::Option::Some(tail) => tail.split("[workspace.lints.rust]").next(),
|
|
std::option::Option::None => std::option::Option::None,
|
|
};
|
|
assert!(workspace_dependencies.is_some(), "workspace dependencies section must exist");
|
|
let workspace_dependencies = match workspace_dependencies {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
for line in workspace_dependencies.lines() {
|
|
let content = match line.split('#').next() {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => continue,
|
|
};
|
|
for inline_field in content.split(',') {
|
|
let key = match inline_field.split('=').next() {
|
|
std::option::Option::Some(value) => value.trim().trim_start_matches('{').trim(),
|
|
std::option::Option::None => continue,
|
|
};
|
|
assert_ne!(key, "features", "consumer feature activation must stay in member manifests");
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn transport_manifest_preserves_ksp_dependency_firewall() {
|
|
let manifest_path = workspace_root().join("crates/ksp-onchain-transport-lib/Cargo.toml");
|
|
let manifest = std::fs::read_to_string(manifest_path).expect("transport manifest must be readable during workspace integration tests");
|
|
for forbidden in ["ksp-config-lib", "ksp-store-api", "ksp-store-lib", "ksp-program-api", "ksp-program-lib", "tracing =", "tracing."] {
|
|
assert!(!manifest.contains(forbidden), "forbidden direct transport dependency detected: {forbidden}");
|
|
}
|
|
assert!(manifest.contains("ksp-core-lib"));
|
|
assert!(manifest.contains("ksp-logging-lib"));
|
|
assert!(manifest.contains("futures-util = { workspace = true, features = [\"sink\", \"std\"] }"));
|
|
assert!(manifest.contains("reqwest = { workspace = true, features = [\"rustls\"] }"));
|
|
assert!(manifest.contains("tokio = { workspace = true, features = [\"macros\", \"net\", \"rt\", \"sync\", \"time\"] }"));
|
|
assert!(manifest.contains("tokio-tungstenite = { workspace = true, features = [\"connect\", \"rustls-tls-webpki-roots\"] }"));
|
|
assert!(manifest.contains("tonic = { workspace = true, features = [\"channel\"] }"));
|
|
assert!(manifest.contains("yellowstone-grpc-proto.workspace = true"));
|
|
assert!(manifest.contains("[dev-dependencies]"));
|
|
assert!(manifest.contains("tokio = { workspace = true, features = [\"io-util\", \"net\", \"rt\", \"test-util\"] }"));
|
|
}
|
|
|
|
#[test]
|
|
fn transport_manifest_runtime_and_dev_dependency_names_are_exact() {
|
|
let manifest_path = workspace_root().join("crates/ksp-onchain-transport-lib/Cargo.toml");
|
|
let manifest = std::fs::read_to_string(manifest_path).expect("transport manifest must be readable during workspace integration tests");
|
|
let dependencies_tail = manifest.split("[dependencies]").nth(1);
|
|
assert!(dependencies_tail.is_some(), "transport dependencies section must exist");
|
|
let dependencies_tail = match dependencies_tail {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let dependencies = match dependencies_tail.split("[dev-dependencies]").next() {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let dependency_names = manifest_dependency_names(dependencies);
|
|
assert_eq!(
|
|
dependency_names,
|
|
std::vec![
|
|
"futures-util",
|
|
"ksp-core-lib",
|
|
"ksp-logging-lib",
|
|
"reqwest",
|
|
"serde",
|
|
"serde_json",
|
|
"tokio",
|
|
"tokio-tungstenite",
|
|
"tonic",
|
|
"yellowstone-grpc-proto"
|
|
]
|
|
);
|
|
let dev_dependencies_tail = manifest.split("[dev-dependencies]").nth(1);
|
|
assert!(dev_dependencies_tail.is_some(), "transport dev-dependencies section must exist");
|
|
let dev_dependencies_tail = match dev_dependencies_tail {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let dev_dependencies = match dev_dependencies_tail.split("[lints]").next() {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
assert_eq!(manifest_dependency_names(dev_dependencies), std::vec!["tokio"]);
|
|
}
|
|
|
|
fn manifest_dependency_names(section: &str) -> std::vec::Vec<&str> {
|
|
let mut names = std::vec::Vec::new();
|
|
for line in section.lines() {
|
|
let content = match line.split('#').next() {
|
|
std::option::Option::Some(value) => value.trim(),
|
|
std::option::Option::None => continue,
|
|
};
|
|
if content.is_empty() {
|
|
continue;
|
|
}
|
|
let name = match content.split('=').next() {
|
|
std::option::Option::Some(value) => value.trim().trim_end_matches(".workspace"),
|
|
std::option::Option::None => continue,
|
|
};
|
|
if !name.is_empty() {
|
|
names.push(name);
|
|
}
|
|
}
|
|
names.sort_unstable();
|
|
return names;
|
|
}
|