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