use super::*;
const FIXTURE: &str = r#"{
"models": {
"zhipuai/glm-5.2": {
"id": "zhipuai/glm-5.2",
"family": "glm",
"reasoning": true,
"modalities": { "input": ["text"], "output": ["text"] },
"limit": { "context": 1000000, "output": 131072 }
}
},
"providers": {
"zhipuai": {
"id": "zhipuai",
"models": {
"glm-5.2": {
"id": "glm-5.2",
"family": "glm",
"default": true,
"reasoning": true,
"reasoning_options": [{ "type": "effort", "values": ["high", "max"] }],
"modalities": { "input": ["text"], "output": ["text"] },
"limit": { "context": 1000000, "output": 131072 },
"cost": { "input": 1.4, "output": 4.4, "cache_read": 0.26 }
},
"glm-voice": {
"id": "glm-voice",
"modalities": { "input": ["text"], "output": ["audio"] }
}
}
},
"together": {
"id": "together",
"models": {
"deepseek-ai/DeepSeek-V4-Pro": {
"id": "deepseek-ai/DeepSeek-V4-Pro",
"base_model": "deepseek-v4-pro",
"family": "deepseek",
"reasoning": false,
"modalities": { "input": ["text"], "output": ["text"] },
"cost": { "input": 0.9, "output": 0.9 }
}
}
}
}
}"#;
fn fixture() -> ModelsDevCatalog {
ModelsDevCatalog::parse_json(FIXTURE).expect("fixture parses")
}
fn find<'a>(rows: &'a [CatalogOffering], provider: &str, wire: &str) -> &'a CatalogOffering {
rows.iter()
.find(|r| r.provider == provider && r.wire_model_id == wire)
.unwrap_or_else(|| panic!("offering {provider}/{wire} not found"))
}
#[test]
fn hydrates_models_dev_offerings_preserving_offering_facts() {
let rows = bundled_offerings_from_models_dev(&fixture());
assert_eq!(rows.len(), 2, "audio-only rows are not chat offerings");
let glm = find(&rows, "zhipuai", "glm-5.2");
assert!(glm.default_for_provider);
assert_eq!(glm.family.as_deref(), Some("glm"));
assert_eq!(glm.reasoning, Some(true));
assert_eq!(glm.reasoning_options.len(), 1);
assert_eq!(glm.limit.as_ref().and_then(|l| l.context), Some(1_000_000));
assert_eq!(glm.cost.as_ref().and_then(|c| c.cache_read), Some(0.26));
assert_eq!(glm.canonical_model, None);
assert_eq!(glm.source, CatalogSource::Bundled);
}
#[test]
fn hosted_offering_keeps_prefixed_wire_id_and_explicit_canonical_join() {
let rows = bundled_offerings_from_models_dev(&fixture());
let hosted = find(&rows, "together", "deepseek-ai/DeepSeek-V4-Pro");
assert_eq!(hosted.wire_model_id, "deepseek-ai/DeepSeek-V4-Pro");
assert_eq!(hosted.provider, "together");
assert_eq!(hosted.canonical_model.as_deref(), Some("deepseek-v4-pro"));
assert_eq!(hosted.reasoning, Some(false));
}
#[test]
fn to_offering_projects_routing_identity_and_limits() {
let rows = bundled_offerings_from_models_dev(&fixture());
let glm = find(&rows, "zhipuai", "glm-5.2").to_offering();
assert_eq!(glm.provider.as_str(), "zhipuai");
assert_eq!(glm.wire_model_id.as_str(), "glm-5.2");
assert_eq!(glm.canonical_model, None);
assert_eq!(glm.endpoint_key, "chat");
assert_eq!(glm.limits.context_tokens, Some(1_000_000));
assert_eq!(glm.limits.output_tokens, Some(131_072));
}
#[test]
fn compiler_merges_layers_with_override_precedence() {
let bundled = vec![CatalogOffering {
provider: "acme".into(),
wire_model_id: "synth-chat-1".into(),
endpoint_key: "chat".into(),
default_for_provider: true,
family: Some("synth".into()),
source: CatalogSource::Bundled,
..Default::default()
}];
let live = vec![
CatalogOffering {
provider: "acme".into(),
wire_model_id: "synth-chat-1".into(),
endpoint_key: "chat".into(),
cost: Some(ModelsDevCost {
input: Some(2.0),
..Default::default()
}),
source: CatalogSource::Live {
base_url_fingerprint: "fp".into(),
fetched_at: 100,
},
..Default::default()
},
CatalogOffering {
provider: "acme".into(),
wire_model_id: "synth-chat-2".into(),
endpoint_key: "chat".into(),
source: CatalogSource::Live {
base_url_fingerprint: "fp".into(),
fetched_at: 100,
},
..Default::default()
},
];
let overrides = vec![CatalogOffering {
provider: "acme".into(),
wire_model_id: "synth-chat-1".into(),
canonical_model: Some("acme-canonical".into()),
endpoint_key: "chat".into(),
source: CatalogSource::UserOverride,
..Default::default()
}];
let snapshot = CatalogCompiler::new()
.with_bundled(bundled)
.with_live(live)
.with_overrides(overrides)
.compile();
assert_eq!(snapshot.offerings.len(), 2);
let one = find(&snapshot.offerings, "acme", "synth-chat-1");
assert_eq!(one.source, CatalogSource::UserOverride);
assert_eq!(one.canonical_model.as_deref(), Some("acme-canonical"));
let two = find(&snapshot.offerings, "acme", "synth-chat-2");
assert!(matches!(two.source, CatalogSource::Live { .. }));
}
#[test]
fn cache_scopes_by_provider_and_base_url_fingerprint() {
let fp_a = base_url_fingerprint("https://api.example.com/v1");
let fp_b = base_url_fingerprint("https://other.example.com/v1");
assert_ne!(fp_a, fp_b, "different hosts must not share a fingerprint");
let mut cache = ProviderCatalogCache::new();
let row = |id: &str| CatalogOffering {
provider: "acme".into(),
wire_model_id: id.into(),
endpoint_key: "chat".into(),
..Default::default()
};
cache.record_success(
ProviderCatalogDelta {
provider: "acme".into(),
base_url_fingerprint: fp_a.clone(),
fetched_at: 1_000,
offerings: vec![row("from-a")],
},
3_600,
);
cache.record_success(
ProviderCatalogDelta {
provider: "acme".into(),
base_url_fingerprint: fp_b.clone(),
fetched_at: 1_000,
offerings: vec![row("from-b")],
},
3_600,
);
cache.record_success(
ProviderCatalogDelta {
provider: "beta".into(),
base_url_fingerprint: fp_a.clone(),
fetched_at: 1_000,
offerings: vec![row("from-beta")],
},
3_600,
);
let a = cache.fresh_offerings("acme", &fp_a, 1_100);
assert_eq!(a.len(), 1);
assert_eq!(a[0].wire_model_id, "from-a");
let b = cache.fresh_offerings("acme", &fp_b, 1_100);
assert_eq!(b[0].wire_model_id, "from-b");
let beta = cache.fresh_offerings("beta", &fp_a, 1_100);
assert_eq!(beta[0].wire_model_id, "from-beta");
assert_eq!(cache.entries.len(), 3);
}
#[test]
fn fingerprint_folds_cosmetic_base_url_differences() {
let canonical = base_url_fingerprint("https://API.Example.com/v1");
assert_eq!(
canonical,
base_url_fingerprint("https://api.example.com/v1/"),
"trailing slash + host case must not change the cache scope"
);
assert_eq!(
canonical,
base_url_fingerprint(" https://api.example.com:443/v1 "),
"default https port + surrounding whitespace must fold away"
);
assert_ne!(
canonical,
base_url_fingerprint("https://api.example.com/V1")
);
assert_eq!(
base_url_fingerprint("http://h.example.com:80/v1"),
base_url_fingerprint("http://h.example.com/v1"),
"http default port :80 must fold away"
);
assert_ne!(
base_url_fingerprint("http://h.example.com:443/v1"),
base_url_fingerprint("http://h.example.com/v1"),
":443 is not http's default port and must not fold"
);
}
#[test]
fn ttl_marks_entries_stale_and_excludes_them_from_fresh() {
let fp = base_url_fingerprint("https://api.example.com");
let mut cache = ProviderCatalogCache::new();
cache.record_success(
ProviderCatalogDelta {
provider: "acme".into(),
base_url_fingerprint: fp.clone(),
fetched_at: 1_000,
offerings: vec![CatalogOffering {
provider: "acme".into(),
wire_model_id: "synth-chat-1".into(),
endpoint_key: "chat".into(),
..Default::default()
}],
},
100, );
assert_eq!(cache.status("acme", &fp, 1_050), CatalogStatus::Fresh);
assert_eq!(cache.fresh_offerings("acme", &fp, 1_050).len(), 1);
match cache.status("acme", &fp, 1_200) {
CatalogStatus::Stale { age_secs } => assert_eq!(age_secs, 200),
other => panic!("expected stale, got {other:?}"),
}
assert!(cache.fresh_offerings("acme", &fp, 1_200).is_empty());
assert_eq!(cache.get("acme", &fp).unwrap().offerings.len(), 1);
}
#[test]
fn ttl_zero_is_always_stale() {
let fp = base_url_fingerprint("https://api.example.com");
let mut cache = ProviderCatalogCache::new();
cache.record_success(
ProviderCatalogDelta {
provider: "acme".into(),
base_url_fingerprint: fp.clone(),
fetched_at: 1_000,
offerings: vec![],
},
0,
);
assert!(cache.get("acme", &fp).unwrap().is_stale(1_000));
}
#[test]
fn unknown_scope_reports_unknown_status() {
let cache = ProviderCatalogCache::new();
let fp = base_url_fingerprint("https://api.example.com");
assert_eq!(cache.status("acme", &fp, 1_000), CatalogStatus::Unknown);
assert!(cache.fresh_offerings("acme", &fp, 1_000).is_empty());
}
#[test]
fn refresh_failure_preserves_prior_rows_and_marks_failed() {
let fp = base_url_fingerprint("https://api.example.com");
let mut cache = ProviderCatalogCache::new();
cache.record_success(
ProviderCatalogDelta {
provider: "acme".into(),
base_url_fingerprint: fp.clone(),
fetched_at: 1_000,
offerings: vec![CatalogOffering {
provider: "acme".into(),
wire_model_id: "synth-chat-1".into(),
endpoint_key: "chat".into(),
..Default::default()
}],
},
3_600,
);
for reason in [
CatalogRefreshError::Unauthorized,
CatalogRefreshError::Forbidden,
CatalogRefreshError::NotFound,
CatalogRefreshError::RateLimited,
CatalogRefreshError::InvalidResponse,
CatalogRefreshError::EmptyList,
CatalogRefreshError::Network,
] {
cache.record_failure("acme", &fp, reason);
let entry = cache.get("acme", &fp).expect("entry survives failure");
assert_eq!(entry.offerings.len(), 1, "{reason:?} dropped prior rows");
assert_eq!(entry.status, CatalogStatus::Failed { reason });
assert_eq!(entry.fetched_at, 1_000);
assert!(
cache.fresh_offerings("acme", &fp, 1_100).is_empty(),
"{reason:?}: failed entry served fresh offerings within TTL"
);
assert!(cache.all_fresh_offerings(1_100).is_empty());
assert_eq!(
cache.status("acme", &fp, 1_100),
CatalogStatus::Failed { reason }
);
}
}
#[test]
fn failure_without_prior_creates_observable_empty_entry() {
let fp = base_url_fingerprint("https://api.example.com");
let mut cache = ProviderCatalogCache::new();
cache.record_failure("acme", &fp, CatalogRefreshError::Unauthorized);
let entry = cache.get("acme", &fp).expect("failure is observable");
assert!(entry.offerings.is_empty());
assert_eq!(
entry.status,
CatalogStatus::Failed {
reason: CatalogRefreshError::Unauthorized
}
);
}
#[test]
fn record_success_stamps_live_provenance_on_rows() {
let fp = base_url_fingerprint("https://api.example.com");
let mut cache = ProviderCatalogCache::new();
cache.record_success(
ProviderCatalogDelta {
provider: "acme".into(),
base_url_fingerprint: fp.clone(),
fetched_at: 4_242,
offerings: vec![CatalogOffering {
provider: "acme".into(),
wire_model_id: "synth-chat-1".into(),
endpoint_key: "chat".into(),
source: CatalogSource::Bundled,
..Default::default()
}],
},
3_600,
);
let entry = cache.get("acme", &fp).unwrap();
assert_eq!(
entry.offerings[0].source,
CatalogSource::Live {
base_url_fingerprint: fp,
fetched_at: 4_242,
}
);
}
#[test]
fn cache_serialization_round_trips_and_contains_no_secrets() {
let fp = base_url_fingerprint("https://api.example.com/v1");
let mut cache = ProviderCatalogCache::new();
cache.record_success(
ProviderCatalogDelta {
provider: "zhipuai".into(),
base_url_fingerprint: fp.clone(),
fetched_at: 1_700,
offerings: bundled_offerings_from_models_dev(&fixture()),
},
3_600,
);
let json = serde_json::to_string_pretty(&cache).expect("cache serializes");
let round: ProviderCatalogCache = serde_json::from_str(&json).expect("cache round-trips");
assert_eq!(round, cache);
let lower = json.to_lowercase();
for needle in [
"api_key",
"apikey",
"api-key",
"authorization",
"secret",
"password",
"bearer",
"access_token",
] {
assert!(
!lower.contains(needle),
"cache JSON unexpectedly contains `{needle}`"
);
}
assert!(json.contains("glm-5.2"));
assert!(json.contains("base_url_fingerprint"));
}
#[test]
fn all_fresh_offerings_spans_providers_and_skips_stale() {
let fp = base_url_fingerprint("https://api.example.com");
let mut cache = ProviderCatalogCache::new();
cache.record_success(
ProviderCatalogDelta {
provider: "acme".into(),
base_url_fingerprint: fp.clone(),
fetched_at: 1_000,
offerings: vec![CatalogOffering {
provider: "acme".into(),
wire_model_id: "fresh-row".into(),
endpoint_key: "chat".into(),
..Default::default()
}],
},
3_600,
);
cache.record_success(
ProviderCatalogDelta {
provider: "beta".into(),
base_url_fingerprint: fp.clone(),
fetched_at: 0,
offerings: vec![CatalogOffering {
provider: "beta".into(),
wire_model_id: "stale-row".into(),
endpoint_key: "chat".into(),
..Default::default()
}],
},
10, );
let fresh = cache.all_fresh_offerings(1_100);
assert_eq!(fresh.len(), 1);
assert_eq!(fresh[0].wire_model_id, "fresh-row");
}
#[test]
fn snapshot_feeds_route_resolver_offerings() {
let snapshot = CatalogCompiler::new().with_models_dev(&fixture()).compile();
let offerings = snapshot.to_offerings();
let glm = offerings
.iter()
.find(|o| o.provider.as_str() == "zhipuai" && o.wire_model_id.as_str() == "glm-5.2")
.expect("GLM offering reaches the route resolver seam");
assert_eq!(glm.limits.context_tokens, Some(1_000_000));
assert_eq!(glm.limits.output_tokens, Some(131_072));
assert!(
!offerings
.iter()
.any(|o| o.wire_model_id.as_str() == "glm-voice")
);
}
#[test]
fn bundled_asset_parses() {
let catalog = ModelsDevCatalog::parse_json(BUNDLED_MODELS_DEV_JSON)
.expect("committed bundled asset must be valid Models.dev JSON");
assert!(
!catalog.providers.is_empty(),
"bundled asset must carry provider rows"
);
assert_eq!(bundled_models_dev_catalog(), catalog);
}
#[test]
fn bundled_asset_yields_real_chat_offerings_for_key_models() {
let rows = bundled_catalog_offerings();
assert!(
rows.len() >= 20,
"expected dozens of bundled chat offerings, got {}",
rows.len()
);
let glm = find(&rows, "zai", "GLM-5.2");
assert_eq!(glm.limit.as_ref().and_then(|l| l.context), Some(1_000_000));
assert!(glm.default_for_provider);
let kimi = find(&rows, "moonshot", "kimi-k2.7-code");
assert_eq!(kimi.limit.as_ref().and_then(|l| l.context), Some(262_144));
assert!(
rows.iter().all(|r| !r.wire_model_id.contains("tts")),
"no TTS rows should reach the offering layer"
);
}
#[test]
fn bundled_asset_pricing_is_honest() {
let rows = bundled_catalog_offerings();
let deepseek = find(&rows, "deepseek", "deepseek-v4-pro");
assert!(
deepseek.cost.is_none(),
"DeepSeek-native rows must stay unpriced in the bundled asset"
);
for row in &rows {
if let Some(cost) = row.cost.as_ref() {
assert!(
cost.input.is_some() || cost.output.is_some(),
"{}/{}: priced row must have an input or output rate",
row.provider,
row.wire_model_id
);
}
}
let glm51 = find(&rows, "zai", "glm-5.1");
let cost = glm51.cost.as_ref().expect("glm-5.1 is priced");
assert_eq!(cost.input, Some(0.98));
assert_eq!(cost.output, Some(3.08));
}