zerodds_ami4ccm/
deployment.rs1use alloc::format;
22use alloc::string::String;
23use alloc::vec;
24use alloc::vec::Vec;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct ConnectorImplementation {
30 pub original_interface: String,
32 pub client_instance: String,
35 pub artifact_path: String,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq)]
41pub struct ImplementationDescriptor {
42 pub label: String,
44 pub uuid: String,
46 pub artifacts: Vec<String>,
48 pub realizes: String,
50}
51
52impl ImplementationDescriptor {
53 #[must_use]
56 pub fn for_connector(impl_: &ConnectorImplementation) -> Self {
57 let connector_name = format!("AMI4CCM_{}_Connector", impl_.original_interface);
58 Self {
59 label: format!("{connector_name}_Impl"),
60 uuid: format!(
61 "ami4ccm-{}-impl-uuid",
62 impl_.original_interface.to_lowercase()
63 ),
64 artifacts: vec![impl_.artifact_path.clone()],
65 realizes: format!("IDL:omg.org/CCM_AMI/{connector_name}:1.0"),
66 }
67 }
68}
69
70#[derive(Debug, Clone, PartialEq, Eq)]
72pub struct PlanInstance {
73 pub name: String,
75 pub implementation: String,
77 pub co_locate_with: Option<String>,
79}
80
81#[derive(Debug, Clone, PartialEq, Eq)]
84pub struct ConnectorPlanFragment {
85 pub implementation: ImplementationDescriptor,
87 pub instance: PlanInstance,
89}
90
91impl ConnectorPlanFragment {
92 #[must_use]
94 pub fn build(impl_: &ConnectorImplementation) -> Self {
95 let implementation = ImplementationDescriptor::for_connector(impl_);
96 let instance = PlanInstance {
97 name: format!("{}_AMI4CCM_Connector", impl_.client_instance),
98 implementation: implementation.label.clone(),
99 co_locate_with: Some(impl_.client_instance.clone()),
100 };
101 Self {
102 implementation,
103 instance,
104 }
105 }
106
107 #[must_use]
109 pub fn is_co_located(&self) -> bool {
110 self.instance.co_locate_with.is_some()
111 }
112
113 #[must_use]
116 pub fn to_dnc_xml(&self) -> String {
117 let mut xml = String::new();
118 xml.push_str("<deploymentPlan>\n");
119 xml.push_str(" <implementation>\n");
120 xml.push_str(&format!(" <name>{}</name>\n", self.implementation.label));
121 xml.push_str(&format!(" <UUID>{}</UUID>\n", self.implementation.uuid));
122 for art in &self.implementation.artifacts {
123 xml.push_str(&format!(" <artifact>{art}</artifact>\n"));
124 }
125 xml.push_str(&format!(
126 " <realizes>{}</realizes>\n",
127 self.implementation.realizes
128 ));
129 xml.push_str(" </implementation>\n");
130 xml.push_str(" <instance>\n");
131 xml.push_str(&format!(" <name>{}</name>\n", self.instance.name));
132 xml.push_str(&format!(
133 " <implementation>{}</implementation>\n",
134 self.instance.implementation
135 ));
136 if let Some(ref c) = self.instance.co_locate_with {
137 xml.push_str(&format!(" <coLocateWith>{c}</coLocateWith>\n"));
138 }
139 xml.push_str(" </instance>\n");
140 xml.push_str("</deploymentPlan>\n");
141 xml
142 }
143}
144
145#[cfg(test)]
146#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
147mod tests {
148 use super::*;
149
150 fn sample_impl() -> ConnectorImplementation {
151 ConnectorImplementation {
152 original_interface: "StockManager".to_string(),
153 client_instance: "TraderClient".to_string(),
154 artifact_path: "lib/ami4ccm_stockmanager.so".to_string(),
155 }
156 }
157
158 #[test]
159 fn idd_realizes_correct_repository_id() {
160 let impl_ = sample_impl();
161 let idd = ImplementationDescriptor::for_connector(&impl_);
162 assert_eq!(
163 idd.realizes,
164 "IDL:omg.org/CCM_AMI/AMI4CCM_StockManager_Connector:1.0"
165 );
166 assert!(!idd.artifacts.is_empty());
167 }
168
169 #[test]
170 fn plan_fragment_is_co_located() {
171 let impl_ = sample_impl();
172 let frag = ConnectorPlanFragment::build(&impl_);
173 assert!(frag.is_co_located());
174 assert_eq!(
175 frag.instance.co_locate_with.as_deref(),
176 Some("TraderClient")
177 );
178 }
179
180 #[test]
181 fn plan_instance_name_combines_client_and_connector() {
182 let impl_ = sample_impl();
183 let frag = ConnectorPlanFragment::build(&impl_);
184 assert_eq!(frag.instance.name, "TraderClient_AMI4CCM_Connector");
185 }
186
187 #[test]
188 fn xml_roundtrip_includes_co_location() {
189 let impl_ = sample_impl();
190 let frag = ConnectorPlanFragment::build(&impl_);
191 let xml = frag.to_dnc_xml();
192 assert!(xml.contains("<deploymentPlan>"));
193 assert!(xml.contains("<coLocateWith>TraderClient</coLocateWith>"));
194 assert!(xml.contains("AMI4CCM_StockManager_Connector"));
195 }
196
197 #[test]
198 fn xml_lists_all_artifacts() {
199 let mut impl_ = sample_impl();
200 impl_.artifact_path = "lib/a.so".into();
201 let frag = ConnectorPlanFragment::build(&impl_);
202 let xml = frag.to_dnc_xml();
203 assert!(xml.contains("<artifact>lib/a.so</artifact>"));
204 }
205}