1use schemars::generate::SchemaSettings;
7use serde_json::{Value, json};
8
9use crate::msg::{ERROR_KINDS, Envelope, Request, Response};
10use crate::{CAPABILITIES, CORE_MIN_VERSION, MAX_VERSION, MIN_VERSION};
11
12pub const PUBLISHED: &str = include_str!("../conformance/schema.json");
14
15#[must_use]
18pub fn document() -> Value {
19 let mut generator = SchemaSettings::draft2020_12().into_generator();
20 generator.subschema_for::<Envelope<Request>>();
21 generator.subschema_for::<Envelope<Response>>();
22 let defs: serde_json::Map<String, Value> = generator.take_definitions(true).into_iter().collect();
23 json!({
24 "$schema": "https://json-schema.org/draft/2020-12/schema",
25 "title": "DRE plugin protocol messages",
26 "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.",
27 "anyOf": [{"$ref": "#/$defs/Request"}, {"$ref": "#/$defs/Response"}],
28 "x-dre": {
29 "protocol": {
30 "min_version": MIN_VERSION,
31 "max_version": MAX_VERSION,
32 "core_min_version": CORE_MIN_VERSION,
33 },
34 "capabilities": CAPABILITIES,
35 "error_kinds": ERROR_KINDS,
36 },
37 "$defs": defs,
38 })
39}
40
41#[must_use]
47pub fn render() -> String {
48 let mut s = serde_json::to_string_pretty(&document()).expect("a schema serialises");
49 s.push('\n');
50 s
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
61 fn the_published_schema_matches_the_code() {
62 let fresh = render();
63 if std::env::var_os("DRE_UPDATE_SCHEMA").is_some() {
64 let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("conformance");
65 std::fs::write(dir.join("schema.json"), &fresh).unwrap();
66 let go = dir.join("../../../go/plugin/plugintest/conformance");
68 for name in ["schema.json", "protocol.json", "delivery.json"] {
69 std::fs::copy(dir.join(name), go.join(name)).unwrap();
70 }
71 return;
72 }
73 assert!(
74 fresh == PUBLISHED,
75 "conformance/schema.json is out of date with msg.rs; regenerate it with \
76 `DRE_UPDATE_SCHEMA=1 cargo test -p dre-protocol --lib schema`"
77 );
78 }
79
80 #[test]
81 fn every_message_names_its_type() {
82 let doc = document();
83 for side in ["Request", "Response"] {
84 let text = doc["$defs"][side].to_string();
85 assert!(text.contains("\"type\""), "{side}: {text}");
86 }
87 assert_eq!(doc["x-dre"]["protocol"]["max_version"], MAX_VERSION);
88 }
89}