use paygress::nostr::{
CapacityInfo, HeartbeatContent, IsolationLevel, PodSpec, ProviderOfferContent, SCHEMA_VERSION,
};
fn sample_offer() -> ProviderOfferContent {
ProviderOfferContent {
provider_npub: "npub1example".to_string(),
hostname: "host.example".to_string(),
location: Some("BER".to_string()),
capabilities: vec!["lxc".to_string()],
specs: vec![PodSpec {
id: "basic".to_string(),
name: "Basic".to_string(),
description: "1 vCPU".to_string(),
cpu_millicores: 1000,
memory_mb: 1024,
rate_msats_per_sec: 50,
}],
whitelisted_mints: vec!["https://mint.example".to_string()],
uptime_percent: 99.5,
total_jobs_completed: 7,
api_endpoint: None,
version: SCHEMA_VERSION,
isolation_level: IsolationLevel::SharedKernel,
stake_proof: None,
}
}
fn sample_heartbeat() -> HeartbeatContent {
HeartbeatContent {
provider_npub: "npub1example".to_string(),
timestamp: 1_700_000_000,
active_workloads: 3,
available_capacity: CapacityInfo {
cpu_available: 4000,
memory_mb_available: 8192,
storage_gb_available: 100,
},
version: SCHEMA_VERSION,
}
}
#[test]
fn offer_v1_roundtrip() {
let offer = sample_offer();
let json = serde_json::to_string(&offer).expect("serialize");
let back: ProviderOfferContent = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back.provider_npub, offer.provider_npub);
assert_eq!(back.version, SCHEMA_VERSION);
assert_eq!(back.isolation_level, IsolationLevel::SharedKernel);
}
#[test]
fn heartbeat_v1_roundtrip() {
let hb = sample_heartbeat();
let json = serde_json::to_string(&hb).expect("serialize");
let back: HeartbeatContent = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back.timestamp, hb.timestamp);
assert_eq!(back.version, SCHEMA_VERSION);
}
#[test]
fn offer_v0_payload_defaults_to_v1_schema() {
let v0_json = serde_json::json!({
"provider_npub": "npub1old",
"hostname": "old.example",
"location": null,
"capabilities": ["lxc"],
"specs": [],
"whitelisted_mints": [],
"uptime_percent": 90.0,
"total_jobs_completed": 0,
"api_endpoint": null,
});
let parsed: ProviderOfferContent = serde_json::from_value(v0_json).expect("v0 must parse");
assert_eq!(parsed.version, SCHEMA_VERSION);
assert_eq!(parsed.isolation_level, IsolationLevel::SharedKernel);
}
#[test]
fn heartbeat_v0_payload_defaults_to_v1_schema() {
let v0_json = serde_json::json!({
"provider_npub": "npub1old",
"timestamp": 1_600_000_000u64,
"active_workloads": 0,
"available_capacity": {
"cpu_available": 0,
"memory_mb_available": 0,
"storage_gb_available": 0,
},
});
let parsed: HeartbeatContent = serde_json::from_value(v0_json).expect("v0 must parse");
assert_eq!(parsed.version, SCHEMA_VERSION);
}
#[test]
fn offer_with_unknown_future_field_is_tolerated() {
let json = serde_json::json!({
"provider_npub": "npub1future",
"hostname": "fut.example",
"location": null,
"capabilities": ["lxc"],
"specs": [],
"whitelisted_mints": [],
"uptime_percent": 100.0,
"total_jobs_completed": 0,
"api_endpoint": null,
"version": 1,
"isolation_level": "shared-kernel",
"future_field_we_have_no_clue_about": {"k": "v"},
});
serde_json::from_value::<ProviderOfferContent>(json)
.expect("unknown fields must not break parsing");
}
#[test]
fn isolation_level_serializes_as_kebab_case() {
let s = serde_json::to_string(&IsolationLevel::AttestedResearchTier).unwrap();
assert_eq!(s, "\"attested-research-tier\"");
let s = serde_json::to_string(&IsolationLevel::DedicatedHost).unwrap();
assert_eq!(s, "\"dedicated-host\"");
}
#[test]
fn isolation_level_deserializes_kebab_case() {
let level: IsolationLevel = serde_json::from_str("\"shared-kernel\"").unwrap();
assert_eq!(level, IsolationLevel::SharedKernel);
let level: IsolationLevel = serde_json::from_str("\"attested-research-tier\"").unwrap();
assert_eq!(level, IsolationLevel::AttestedResearchTier);
}