sparktest_api/
handlers.rs

1use 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    // In a real implementation, this would fetch from database
28    Ok(Json(vec![]))
29}
30
31pub async fn create_run(
32    JsonBody(req): JsonBody<CreateRunRequest>,
33) -> Result<Json<TestRun>, StatusCode> {
34    // In a real implementation, this would create a run in the database
35    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    // In a real implementation, this would fetch from database
63    Err(StatusCode::NOT_FOUND)
64}
65
66pub async fn delete_run(Path(_id): Path<Uuid>) -> Result<StatusCode, StatusCode> {
67    // In a real implementation, this would delete from database
68    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}