featherbit/graph/
prepare.rs1use crate::config::{GatewayConfig, PluginConfigDef, PolicyConfig, SupernodeConfig};
6use crate::graph::{expand_policy, validate_policy};
7
8pub fn prepare_policy(
14 policy: PolicyConfig,
15 supernodes: &[SupernodeConfig],
16 plugin_configs: &[PluginConfigDef],
17) -> Result<PolicyConfig, String> {
18 if let Err(errors) = validate_policy(&policy) {
19 return Err(errors.join("; "));
20 }
21 let mut tmp: GatewayConfig = serde_yaml::from_str("{}").expect("empty config parses");
22 tmp.policies = vec![policy];
23 tmp.supernodes = supernodes.to_vec();
24 tmp.plugin_configs = plugin_configs.to_vec();
25 let resolved = crate::config::resolve_plugin_configs(&tmp)?;
26 for warning in crate::config::collect_template_warnings(&resolved) {
27 tracing::warn!("{warning}");
28 }
29 let policy = resolved
30 .policies
31 .into_iter()
32 .next()
33 .expect("one policy in, one policy out");
34 expand_policy(&policy, &resolved.supernodes)
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40
41 fn policy(yaml: &str) -> PolicyConfig {
42 serde_yaml::from_str(yaml).unwrap()
43 }
44
45 #[test]
46 fn rejects_structural_errors_with_joined_messages() {
47 let p = policy("name: p\nnodes:\n - id: l\n type: listener\nedges: []\n");
48 let err = prepare_policy(p, &[], &[]).unwrap_err();
49 assert!(err.contains("client"), "{err}");
50 }
51
52 #[test]
53 fn resolves_config_ref_and_passes_valid_policy_through() {
54 let p = policy(
55 "name: p\nnodes:\n - id: l\n type: listener\n - id: e\n type: echo\n config_ref: shared-echo\n - id: c\n type: client\nedges:\n - from: l.out\n to: e.in\n - from: e.out\n to: c.in\n",
56 );
57 let pc: PluginConfigDef =
58 serde_yaml::from_str("name: shared-echo\ntype: echo\nconfig:\n body: hi\n").unwrap();
59 let out = prepare_policy(p, &[], &[pc]).unwrap();
60 let echo = out.nodes.iter().find(|n| n.id == "e").unwrap();
61 assert_eq!(echo.config.get("body").and_then(|v| v.as_str()), Some("hi"));
62 }
63
64 #[test]
65 fn unknown_config_ref_is_an_error() {
66 let p = policy(
67 "name: p\nnodes:\n - id: l\n type: listener\n - id: e\n type: echo\n config_ref: nope\n - id: c\n type: client\nedges:\n - from: l.out\n to: e.in\n - from: e.out\n to: c.in\n",
68 );
69 let err = prepare_policy(p, &[], &[]).unwrap_err();
70 assert!(err.contains("nope"), "{err}");
71 }
72}