mod common;
use common::{assert_has_key, load_json};
use serde_json::Value;
use std::path::{Path, PathBuf};
fn openapi_dir() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests")
.join("api_contracts")
.join("openapi")
}
fn load_schema(name: &str) -> Value {
let path = openapi_dir().join(name);
let content = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("failed to read schema {}: {}", path.display(), e));
serde_json::from_str(&content)
.unwrap_or_else(|e| panic!("failed to parse schema {}: {}", name, e))
}
fn validate_schema(schema_name: &str) {
let schema = load_schema(schema_name);
let fixture_name = schema["fixture"]
.as_str()
.unwrap_or_else(|| panic!("schema {} missing 'fixture' field", schema_name));
let fixture = load_json(fixture_name);
let root_is_array = schema
.get("root")
.and_then(|v| v.as_str())
.is_some_and(|v| v == "array");
let target = if root_is_array {
fixture
.get(0)
.unwrap_or_else(|| panic!("fixture {} is empty array", fixture_name))
} else {
&fixture
};
let required_paths = schema["required_paths"]
.as_array()
.unwrap_or_else(|| panic!("schema {} missing 'required_paths' array", schema_name));
for path_val in required_paths {
let path = path_val
.as_str()
.unwrap_or_else(|| panic!("non-string path in schema {}", schema_name));
assert_has_key(target, path);
}
}
#[test]
fn schema_azure_token() {
validate_schema("azure_token.json");
}
#[test]
fn schema_azure_vms() {
validate_schema("azure_vms.json");
}
#[test]
fn schema_azure_nics() {
validate_schema("azure_nics.json");
}
#[test]
fn schema_azure_public_ips() {
validate_schema("azure_public_ips.json");
}
#[test]
fn schema_digitalocean_droplets() {
validate_schema("digitalocean_droplets.json");
}
#[test]
fn schema_gcp_token() {
validate_schema("gcp_token.json");
}
#[test]
fn schema_gcp_aggregated_instances() {
validate_schema("gcp_aggregated_instances.json");
}
#[test]
fn schema_hetzner_servers() {
validate_schema("hetzner_servers.json");
}
#[test]
fn schema_leaseweb_baremetal() {
validate_schema("leaseweb_baremetal.json");
}
#[test]
fn schema_leaseweb_cloud() {
validate_schema("leaseweb_cloud.json");
}
#[test]
fn schema_linode_instances() {
validate_schema("linode_instances.json");
}
#[test]
fn schema_oracle_compartments() {
validate_schema("oracle_compartments.json");
}
#[test]
fn schema_oracle_instances() {
validate_schema("oracle_instances.json");
}
#[test]
fn schema_oracle_vnic_attachments() {
validate_schema("oracle_vnic_attachments.json");
}
#[test]
fn schema_oracle_vnic() {
validate_schema("oracle_vnic.json");
}
#[test]
fn schema_oracle_image() {
validate_schema("oracle_image.json");
}
#[test]
fn schema_ovh_instances() {
validate_schema("ovh_instances.json");
}
#[test]
fn schema_scaleway_servers() {
validate_schema("scaleway_servers.json");
}
#[test]
fn schema_tailscale_api_devices() {
validate_schema("tailscale_api_devices.json");
}
#[test]
fn schema_upcloud_servers() {
validate_schema("upcloud_servers.json");
}
#[test]
fn schema_upcloud_server_detail() {
validate_schema("upcloud_server_detail.json");
}
#[test]
fn schema_vultr_instances() {
validate_schema("vultr_instances.json");
}
#[test]
fn schema_all_fragments_present() {
let dir = openapi_dir();
let expected = [
"azure_token.json",
"azure_vms.json",
"azure_nics.json",
"azure_public_ips.json",
"digitalocean_droplets.json",
"gcp_token.json",
"gcp_aggregated_instances.json",
"hetzner_servers.json",
"leaseweb_baremetal.json",
"leaseweb_cloud.json",
"linode_instances.json",
"oracle_compartments.json",
"oracle_instances.json",
"oracle_vnic_attachments.json",
"oracle_vnic.json",
"oracle_image.json",
"ovh_instances.json",
"scaleway_servers.json",
"tailscale_api_devices.json",
"upcloud_servers.json",
"upcloud_server_detail.json",
"vultr_instances.json",
];
let mut missing = Vec::new();
for name in &expected {
if !dir.join(name).exists() {
missing.push(*name);
}
}
assert!(
missing.is_empty(),
"missing OpenAPI schema fragments: {:?}",
missing
);
}