1#![allow(non_snake_case)]
2
3pub mod TestControllerState;
29
30pub mod TestProviderState;
31
32pub mod TestResult;
33
34pub mod TestRun;
35
36pub mod TestRunStatus;
37
38use std::sync::Arc;
39
40use CommonLibrary::{
41 Environment::Requires::Requires,
42 Error::CommonError::CommonError,
43 IPC::{DTO::ProxyTarget::ProxyTarget, IPCProvider::IPCProvider, SkyEvent::SkyEvent},
44 Testing::TestController::TestController,
45};
46use async_trait::async_trait;
47use serde_json::{Value, json};
48use tauri::Emitter;
49use uuid::Uuid;
50
51use super::MountainEnvironment::MountainEnvironment;
52use crate::dev_log;
53
54#[async_trait]
55impl TestController for MountainEnvironment {
56 async fn RegisterTestController(&self, ControllerId:String, Label:String) -> Result<(), CommonError> {
57 dev_log!(
58 "extensions",
59 "[TestProvider] Registering test controller '{}' with label '{}'",
60 ControllerId,
61 Label
62 );
63
64 let SideCarIdentifier = Some("cocoon-main".to_string());
65
66 let ControllerState = TestControllerState::Struct {
67 ControllerIdentifier:ControllerId.clone(),
68
69 Label,
70
71 SideCarIdentifier,
72
73 IsActive:true,
74
75 SupportedTestTypes:vec!["unit".to_string(), "integration".to_string()],
76 };
77
78 let mut StateGuard = self.ApplicationState.TestProviderState.write().await;
79
80 StateGuard.Controllers.insert(ControllerId.clone(), ControllerState);
81
82 drop(StateGuard);
83
84 self.ApplicationHandle
85 .emit(
86 SkyEvent::TestRegistered.AsStr(),
87 json!({ "ControllerIdentifier": ControllerId }),
88 )
89 .map_err(|Error| {
90 CommonError::IPCError { Description:format!("Failed to emit test registration event: {}", Error) }
91 })?;
92
93 dev_log!(
94 "extensions",
95 "[TestProvider] Test controller '{}' registered successfully",
96 ControllerId
97 );
98
99 Ok(())
100 }
101
102 async fn RunTests(&self, ControllerIdentifier:String, TestRunRequest:Value) -> Result<(), CommonError> {
103 dev_log!(
104 "extensions",
105 "[TestProvider] Running tests for controller '{}': {:?}",
106 ControllerIdentifier,
107 TestRunRequest
108 );
109
110 let ControllerState = {
111 let StateGuard = self.ApplicationState.TestProviderState.read().await;
112
113 StateGuard.Controllers.get(&ControllerIdentifier).cloned().ok_or_else(|| {
114 CommonError::TestControllerNotFound { ControllerIdentifier:ControllerIdentifier.clone() }
115 })?
116 };
117
118 let RunIdentifier = Uuid::new_v4().to_string();
119
120 let TestRunRecord = TestRun::Struct {
121 RunIdentifier:RunIdentifier.clone(),
122
123 ControllerIdentifier:ControllerIdentifier.clone(),
124
125 Status:TestRunStatus::Enum::Queued,
126
127 StartedAt:std::time::Instant::now(),
128
129 Results:std::collections::HashMap::new(),
130 };
131
132 {
133 let mut StateGuard = self.ApplicationState.TestProviderState.write().await;
134
135 StateGuard.ActiveRuns.insert(RunIdentifier.clone(), TestRunRecord);
136 }
137
138 self.ApplicationHandle
139 .emit(
140 SkyEvent::TestRunStarted.AsStr(),
141 json!({ "RunIdentifier": RunIdentifier, "ControllerIdentifier": ControllerIdentifier }),
142 )
143 .map_err(|Error| {
144 CommonError::IPCError { Description:format!("Failed to emit test run started event: {}", Error) }
145 })?;
146
147 if let Some(SideCarIdentifier) = &ControllerState.SideCarIdentifier {
148 Self::RunProxiedTests(self, SideCarIdentifier, &RunIdentifier, TestRunRequest).await?;
149 } else {
150 dev_log!(
151 "extensions",
152 "warn: [TestProvider] Native test controllers not yet implemented for '{}'",
153 ControllerIdentifier
154 );
155
156 let _ = Self::UpdateRunStatus(self, &RunIdentifier, TestRunStatus::Enum::Skipped).await;
157 }
158
159 Ok(())
160 }
161}
162
163impl MountainEnvironment {
164 async fn RunProxiedTests(
165 &self,
166
167 SideCarIdentifier:&str,
168
169 RunIdentifier:&str,
170
171 TestRunRequest:Value,
172 ) -> Result<(), CommonError> {
173 dev_log!(
174 "extensions",
175 "[TestProvider] Running proxied tests for run '{}' on sidecar '{}'",
176 RunIdentifier,
177 SideCarIdentifier
178 );
179
180 let _ = Self::UpdateRunStatus(self, RunIdentifier, TestRunStatus::Enum::Running).await;
181
182 let IPCProviderHandle:Arc<dyn IPCProvider> = self.Require();
183
184 let RPCMethod = format!("{}$runTests", ProxyTarget::ExtHostTesting.GetTargetPrefix());
185
186 let RPCParams = json!({ "RunIdentifier": RunIdentifier, "TestRunRequest": TestRunRequest });
187
188 match IPCProviderHandle
189 .SendRequestToSideCar(SideCarIdentifier.to_string(), RPCMethod, RPCParams, 300000)
190 .await
191 {
192 Ok(Response) => {
193 if let Ok(Results) = serde_json::from_value::<Vec<TestResult::Struct>>(Response) {
194 let _ = Self::StoreTestResults(self, RunIdentifier, Results).await;
195
196 let FinalStatus = Self::CalculateRunStatus(self, RunIdentifier).await;
197
198 let _ = Self::UpdateRunStatus(self, RunIdentifier, FinalStatus).await;
199
200 dev_log!(
201 "extensions",
202 "[TestProvider] Test run '{}' completed with status {:?}",
203 RunIdentifier,
204 FinalStatus
205 );
206 } else {
207 dev_log!(
208 "extensions",
209 "error: [TestProvider] Failed to parse test results for run '{}'",
210 RunIdentifier
211 );
212
213 let _ = Self::UpdateRunStatus(self, RunIdentifier, TestRunStatus::Enum::Errored).await;
214 }
215
216 Ok(())
217 },
218
219 Err(Error) => {
220 dev_log!("extensions", "error: [TestProvider] Failed to run tests: {}", Error);
221
222 let _ = Self::UpdateRunStatus(self, RunIdentifier, TestRunStatus::Enum::Errored).await;
223
224 Err(Error)
225 },
226 }
227 }
228
229 async fn UpdateRunStatus(&self, RunIdentifier:&str, Status:TestRunStatus::Enum) -> Result<(), CommonError> {
230 let mut StateGuard = self.ApplicationState.TestProviderState.write().await;
231
232 if let Some(TestRunRecord) = StateGuard.ActiveRuns.get_mut(RunIdentifier) {
233 TestRunRecord.Status = Status;
234
235 drop(StateGuard);
236
237 self.ApplicationHandle
238 .emit(
239 SkyEvent::TestRunStatusChanged.AsStr(),
240 json!({ "RunIdentifier": RunIdentifier, "Status": Status }),
241 )
242 .map_err(|Error| {
243 CommonError::IPCError { Description:format!("Failed to emit test status change event: {}", Error) }
244 })?;
245
246 Ok(())
247 } else {
248 Err(CommonError::TestRunNotFound { RunIdentifier:RunIdentifier.to_string() })
249 }
250 }
251
252 async fn StoreTestResults(&self, RunIdentifier:&str, Results:Vec<TestResult::Struct>) -> Result<(), CommonError> {
253 let mut StateGuard = self.ApplicationState.TestProviderState.write().await;
254
255 if let Some(TestRunRecord) = StateGuard.ActiveRuns.get_mut(RunIdentifier) {
256 for Result in Results {
257 TestRunRecord.Results.insert(Result.TestIdentifier.clone(), Result);
258 }
259
260 Ok(())
261 } else {
262 Err(CommonError::TestRunNotFound { RunIdentifier:RunIdentifier.to_string() })
263 }
264 }
265
266 async fn CalculateRunStatus(&self, RunIdentifier:&str) -> TestRunStatus::Enum {
267 let StateGuard = self.ApplicationState.TestProviderState.read().await;
268
269 if let Some(TestRunRecord) = StateGuard.ActiveRuns.get(RunIdentifier) {
270 if TestRunRecord.Results.is_empty() {
271 TestRunStatus::Enum::Passed
272 } else {
273 let HasFailed = TestRunRecord.Results.values().any(|R| R.Status == TestRunStatus::Enum::Failed);
274
275 let HasErrored = TestRunRecord.Results.values().any(|R| R.Status == TestRunStatus::Enum::Errored);
276
277 if HasErrored {
278 TestRunStatus::Enum::Errored
279 } else if HasFailed {
280 TestRunStatus::Enum::Failed
281 } else {
282 TestRunStatus::Enum::Passed
283 }
284 }
285 } else {
286 TestRunStatus::Enum::Errored
287 }
288 }
289}