use schemars::generate::SchemaSettings;
use serde_json::{Value, json};
use crate::msg::{ERROR_KINDS, Envelope, Request, Response};
use crate::{CAPABILITIES, CORE_MIN_VERSION, MAX_VERSION, MIN_VERSION};
pub const PUBLISHED: &str = include_str!("../conformance/schema.json");
#[must_use]
pub fn document() -> Value {
let mut generator = SchemaSettings::draft2020_12().into_generator();
generator.subschema_for::<Envelope<Request>>();
generator.subschema_for::<Envelope<Response>>();
let defs: serde_json::Map<String, Value> = generator.take_definitions(true).into_iter().collect();
json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "DRE plugin protocol messages",
"description": "Every JSON frame of the DRE plugin protocol (docs/protocol.md). A frame core sends matches `$defs/Request`; a frame a plugin sends matches `$defs/Response`. Generated from dre-protocol's msg.rs; don't edit by hand.",
"anyOf": [{"$ref": "#/$defs/Request"}, {"$ref": "#/$defs/Response"}],
"x-dre": {
"protocol": {
"min_version": MIN_VERSION,
"max_version": MAX_VERSION,
"core_min_version": CORE_MIN_VERSION,
},
"capabilities": CAPABILITIES,
"error_kinds": ERROR_KINDS,
},
"$defs": defs,
})
}
#[must_use]
pub fn render() -> String {
let mut s = serde_json::to_string_pretty(&document()).expect("a schema serialises");
s.push('\n');
s
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_published_schema_matches_the_code() {
let fresh = render();
if std::env::var_os("DRE_UPDATE_SCHEMA").is_some() {
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("conformance");
std::fs::write(dir.join("schema.json"), &fresh).unwrap();
let go = dir.join("../../../go/plugin/plugintest/conformance");
for name in ["schema.json", "protocol.json", "delivery.json"] {
std::fs::copy(dir.join(name), go.join(name)).unwrap();
}
return;
}
assert!(
fresh == PUBLISHED,
"conformance/schema.json is out of date with msg.rs; regenerate it with \
`DRE_UPDATE_SCHEMA=1 cargo test -p dre-protocol --lib schema`"
);
}
#[test]
fn every_message_names_its_type() {
let doc = document();
for side in ["Request", "Response"] {
let text = doc["$defs"][side].to_string();
assert!(text.contains("\"type\""), "{side}: {text}");
}
assert_eq!(doc["x-dre"]["protocol"]["max_version"], MAX_VERSION);
}
}