sparktest_api/
handlers.rs1use axum::{extract::Path, http::StatusCode, response::Json, Json as JsonBody};
2use serde::{Deserialize, Serialize};
3use sparktest_core::*;
4use uuid::Uuid;
5
6#[derive(Serialize)]
7pub struct HealthResponse {
8 pub status: String,
9 pub timestamp: String,
10}
11
12#[derive(Deserialize)]
13pub struct CreateRunRequest {
14 pub name: String,
15 pub image: String,
16 pub commands: Vec<String>,
17}
18
19pub async fn health_check() -> Json<HealthResponse> {
20 Json(HealthResponse {
21 status: "healthy".to_string(),
22 timestamp: chrono::Utc::now().to_rfc3339(),
23 })
24}
25
26pub async fn get_runs() -> Result<Json<Vec<TestRun>>, StatusCode> {
27 Ok(Json(vec![]))
29}
30
31pub async fn create_run(
32 JsonBody(req): JsonBody<CreateRunRequest>,
33) -> Result<Json<TestRun>, StatusCode> {
34 let run = TestRun {
36 id: Uuid::new_v4(),
37 name: req.name,
38 image: req.image,
39 commands: req.commands,
40 status: "pending".to_string(),
41 created_at: chrono::Utc::now(),
42 definition_id: None,
43 executor_id: None,
44 suite_id: None,
45 variables: None,
46 artifacts: None,
47 duration: None,
48 retries: None,
49 logs: None,
50 k8s_job_name: None,
51 pod_scheduled: None,
52 container_created: None,
53 container_started: None,
54 completed: None,
55 failed: None,
56 };
57
58 Ok(Json(run))
59}
60
61pub async fn get_run(Path(_id): Path<Uuid>) -> Result<Json<TestRun>, StatusCode> {
62 Err(StatusCode::NOT_FOUND)
64}
65
66pub async fn delete_run(Path(_id): Path<Uuid>) -> Result<StatusCode, StatusCode> {
67 Ok(StatusCode::NO_CONTENT)
69}
70
71pub async fn k8s_health() -> Json<serde_json::Value> {
72 Json(serde_json::json!({
73 "kubernetes_connected": true,
74 "timestamp": chrono::Utc::now().to_rfc3339()
75 }))
76}
77
78pub async fn get_job_logs(Path(job_name): Path<String>) -> Json<serde_json::Value> {
79 Json(serde_json::json!({
80 "job_name": job_name,
81 "pod_name": format!("pod-{}", job_name),
82 "logs": "Sample log output",
83 "timestamp": chrono::Utc::now().to_rfc3339(),
84 "status": "completed"
85 }))
86}
87
88pub async fn get_job_status(Path(job_name): Path<String>) -> Json<serde_json::Value> {
89 Json(serde_json::json!({
90 "job_name": job_name,
91 "status": "completed",
92 "timestamp": chrono::Utc::now().to_rfc3339()
93 }))
94}
95
96pub async fn delete_job(Path(job_name): Path<String>) -> Json<serde_json::Value> {
97 Json(serde_json::json!({
98 "message": format!("Job {} deleted successfully", job_name),
99 "timestamp": chrono::Utc::now().to_rfc3339()
100 }))
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use axum::Json as JsonBody;
107
108 #[tokio::test]
109 async fn test_health_check() {
110 let response = health_check().await;
111 assert_eq!(response.0.status, "healthy");
112 assert!(!response.0.timestamp.is_empty());
113 }
114
115 #[tokio::test]
116 async fn test_get_runs() {
117 let result = get_runs().await;
118 assert!(result.is_ok());
119 let runs = result.unwrap().0;
120 assert_eq!(runs.len(), 0);
121 }
122
123 #[tokio::test]
124 async fn test_create_run() {
125 let request = CreateRunRequest {
126 name: "Test Run".to_string(),
127 image: "test:latest".to_string(),
128 commands: vec!["echo".to_string(), "hello".to_string()],
129 };
130
131 let result = create_run(JsonBody(request)).await;
132 assert!(result.is_ok());
133
134 let run = result.unwrap().0;
135 assert_eq!(run.name, "Test Run");
136 assert_eq!(run.image, "test:latest");
137 assert_eq!(run.status, "pending");
138 assert_eq!(run.commands.len(), 2);
139 }
140
141 #[tokio::test]
142 async fn test_get_run() {
143 let id = Uuid::new_v4();
144 let result = get_run(Path(id)).await;
145 assert!(result.is_err());
146 assert_eq!(result.unwrap_err(), StatusCode::NOT_FOUND);
147 }
148
149 #[tokio::test]
150 async fn test_delete_run() {
151 let id = Uuid::new_v4();
152 let result = delete_run(Path(id)).await;
153 assert!(result.is_ok());
154 assert_eq!(result.unwrap(), StatusCode::NO_CONTENT);
155 }
156
157 #[tokio::test]
158 async fn test_k8s_health() {
159 let response = k8s_health().await;
160 let value = response.0;
161 assert_eq!(value["kubernetes_connected"], true);
162 assert!(value["timestamp"].is_string());
163 }
164
165 #[tokio::test]
166 async fn test_get_job_logs() {
167 let job_name = "test-job".to_string();
168 let response = get_job_logs(Path(job_name.clone())).await;
169 let value = response.0;
170 assert_eq!(value["job_name"], job_name);
171 assert_eq!(value["pod_name"], format!("pod-{}", job_name));
172 assert_eq!(value["logs"], "Sample log output");
173 assert_eq!(value["status"], "completed");
174 }
175
176 #[tokio::test]
177 async fn test_get_job_status() {
178 let job_name = "test-job".to_string();
179 let response = get_job_status(Path(job_name.clone())).await;
180 let value = response.0;
181 assert_eq!(value["job_name"], job_name);
182 assert_eq!(value["status"], "completed");
183 }
184
185 #[tokio::test]
186 async fn test_delete_job() {
187 let job_name = "test-job".to_string();
188 let response = delete_job(Path(job_name.clone())).await;
189 let value = response.0;
190 assert_eq!(
191 value["message"],
192 format!("Job {} deleted successfully", job_name)
193 );
194 }
195}