1use axum::Json;
7use axum::response::IntoResponse;
8use scope::market::{MarketVenue, VenueRegistry};
9
10use super::{error_response, status_for};
11
12pub async fn handle() -> impl IntoResponse {
14 let registry = match VenueRegistry::load() {
15 Ok(r) => r,
16 Err(e) => {
17 return error_response(
18 status_for(&e),
19 format!("Failed to load venue registry: {e}"),
20 );
21 }
22 };
23
24 let venues = MarketVenue::listings(®istry);
26 let output = serde_json::json!({
27 "total": venues.len(),
28 "venues": venues,
29 "user_venues_dir": VenueRegistry::user_venues_dir().display().to_string(),
30 });
31
32 Json(output).into_response()
33}
34
35#[cfg(test)]
36mod tests {
37 use super::*;
38 use axum::response::IntoResponse;
39
40 #[tokio::test]
41 async fn test_handle_venues() {
42 let response = handle().await.into_response();
43 let status = response.status();
44 assert!(status.is_success());
45 }
46
47 #[tokio::test]
48 async fn test_handle_venues_returns_all_built_in() {
49 let response = handle().await.into_response();
50 let status = response.status();
51 assert!(status.is_success());
52
53 let body = axum::body::to_bytes(response.into_body(), 1024 * 1024)
55 .await
56 .unwrap();
57 let json: serde_json::Value = serde_json::from_slice(&body).unwrap();
58 assert!(json["total"].as_u64().unwrap() >= 11);
59 assert!(json["venues"].is_array());
60 let venues = json["venues"].as_array().unwrap();
61 assert!(venues.iter().any(|v| v["id"] == "binance"));
62 assert!(venues.iter().any(|v| v["id"] == "kraken"));
63 for venue in venues {
65 assert!(venue["id"].is_string());
66 assert!(venue["name"].is_string());
67 assert_eq!(venue["base_url"].is_string(), venue["kind"] == "cex");
69 assert!(venue["capabilities"].is_array());
70 }
71 }
72
73 #[tokio::test]
74 async fn test_handle_venues_response_structure() {
75 let response = handle().await.into_response();
76 assert!(response.status().is_success());
77 let body = axum::body::to_bytes(response.into_body(), 1024 * 1024)
78 .await
79 .unwrap();
80 let json: serde_json::Value = serde_json::from_slice(&body).unwrap();
81 assert!(json["total"].as_u64().unwrap() >= 11);
82 let venues = json["venues"].as_array().unwrap();
83 for v in venues {
84 assert!(v["id"].is_string());
85 assert!(v["name"].is_string());
86 assert!(v["capabilities"].is_array());
87 }
88 assert!(json["user_venues_dir"].is_string());
89 }
90
91 #[tokio::test]
93 async fn test_handle_venues_lists_dex_venues() {
94 let response = handle().await.into_response();
95 let body = axum::body::to_bytes(response.into_body(), 1024 * 1024)
96 .await
97 .unwrap();
98 let json: serde_json::Value = serde_json::from_slice(&body).unwrap();
99 let dex: Vec<&serde_json::Value> = json["venues"]
100 .as_array()
101 .unwrap()
102 .iter()
103 .filter(|v| v["kind"] == "dex")
104 .collect();
105 let ids: Vec<&str> = dex.iter().map(|v| v["id"].as_str().unwrap()).collect();
106 assert_eq!(ids, ["ethereum", "solana"]);
107 assert_eq!(dex[1]["name"], "Solana DEX");
108 assert_eq!(dex[1]["chain"], "solana");
109 }
110}