zerodds_corba_dnc/
node.rs1use alloc::collections::BTreeMap;
11use alloc::string::String;
12use alloc::vec::Vec;
13
14use crate::plan::InstanceDeploymentDescription;
15
16#[derive(Debug, Clone, PartialEq, Eq, Default)]
18pub struct NodeApplication {
19 pub node: String,
21 pub instances: Vec<InstanceDeploymentDescription>,
23 pub active: Vec<String>,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct NodeApplicationManager {
30 node: String,
31 instances: Vec<InstanceDeploymentDescription>,
32}
33
34impl NodeApplicationManager {
35 #[must_use]
37 pub fn new(node: String, instances: Vec<InstanceDeploymentDescription>) -> Self {
38 Self { node, instances }
39 }
40
41 #[must_use]
43 pub fn start_launch(&self) -> NodeApplication {
44 NodeApplication {
45 node: self.node.clone(),
46 instances: self.instances.clone(),
47 active: self.instances.iter().map(|i| i.name.clone()).collect(),
48 }
49 }
50
51 pub fn destroy_application(app: &mut NodeApplication) {
53 app.active.clear();
54 }
55}
56
57#[derive(Debug, Default, Clone, PartialEq, Eq)]
59pub struct NodeManager {
60 pub name: String,
62 apps: BTreeMap<String, NodeApplication>,
64}
65
66impl NodeManager {
67 #[must_use]
69 pub fn new(name: String) -> Self {
70 Self {
71 name,
72 apps: BTreeMap::new(),
73 }
74 }
75
76 #[must_use]
80 pub fn prepare_plan(
81 &self,
82 instances: Vec<InstanceDeploymentDescription>,
83 ) -> NodeApplicationManager {
84 NodeApplicationManager::new(self.name.clone(), instances)
85 }
86
87 pub fn register_application(&mut self, plan_label: String, app: NodeApplication) {
90 self.apps.insert(plan_label, app);
91 }
92
93 #[must_use]
95 pub fn active_plans(&self) -> Vec<String> {
96 self.apps.keys().cloned().collect()
97 }
98
99 pub fn unregister_application(&mut self, plan_label: &str) -> Option<NodeApplication> {
101 self.apps.remove(plan_label)
102 }
103}
104
105#[cfg(test)]
106#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
107mod tests {
108 use super::*;
109 use alloc::string::ToString;
110
111 fn make_inst(name: &str) -> InstanceDeploymentDescription {
112 InstanceDeploymentDescription {
113 name: name.into(),
114 implementation: "I".into(),
115 node: "N1".into(),
116 ..InstanceDeploymentDescription::default()
117 }
118 }
119
120 #[test]
121 fn prepare_plan_then_start_launch() {
122 let nm = NodeManager::new("N1".into());
123 let app_mgr = nm.prepare_plan(alloc::vec![make_inst("a"), make_inst("b")]);
124 let app = app_mgr.start_launch();
125 assert_eq!(app.node, "N1");
126 assert_eq!(app.active.len(), 2);
127 assert!(app.active.iter().any(|s| s == "a"));
128 assert!(app.active.iter().any(|s| s == "b"));
129 }
130
131 #[test]
132 fn destroy_application_clears_active() {
133 let nm = NodeManager::new("N1".into());
134 let mut app = nm.prepare_plan(alloc::vec![make_inst("a")]).start_launch();
135 NodeApplicationManager::destroy_application(&mut app);
136 assert!(app.active.is_empty());
137 assert_eq!(app.instances.len(), 1, "instance metadata bleibt erhalten");
138 }
139
140 #[test]
141 fn register_and_unregister_application() {
142 let mut nm = NodeManager::new("N1".into());
143 let app = nm.prepare_plan(alloc::vec![make_inst("a")]).start_launch();
144 nm.register_application("Plan1".into(), app);
145 assert_eq!(nm.active_plans(), alloc::vec!["Plan1".to_string()]);
146 let popped = nm.unregister_application("Plan1");
147 assert!(popped.is_some());
148 assert!(nm.active_plans().is_empty());
149 }
150
151 #[test]
152 fn unregister_unknown_returns_none() {
153 let mut nm = NodeManager::new("N".into());
154 assert!(nm.unregister_application("nope").is_none());
155 }
156}