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