use axum::{Router, response::Json, routing::get}; use domain::{DataSource, DataSourceConfig, DataSourcePort, DataSourceType, Value}; use http_json::HttpJsonAdapter; use std::time::Duration; async fn start_fake_api() -> String { let app = Router::new() .route( "/weather", get(|| async { Json(serde_json::json!({ "main": {"temp": 5.4, "humidity": 80}, "weather": [{"icon": "cloud_rain"}] })) }), ) .route( "/simple", get(|| async { Json(serde_json::json!({"value": "hello"})) }), ) .route("/not-json", get(|| async { "plain text" })); let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); let addr = listener.local_addr().unwrap(); tokio::spawn(async move { axum::serve(listener, app).await.unwrap(); }); format!("http://{addr}") } fn make_source(url: String) -> DataSource { DataSource { id: 1, name: "test".into(), source_type: DataSourceType::HttpJson, poll_interval: Duration::from_secs(60), config: DataSourceConfig::External { url: Some(url), headers: vec![], api_key: None, }, } } #[tokio::test] async fn polls_url_and_returns_nested_json_as_value() { let base = start_fake_api().await; let adapter = HttpJsonAdapter::new(); let source = make_source(format!("{base}/weather")); let result = adapter.poll(&source).await.unwrap(); assert_eq!(result.get_path("$.main.temp"), Some(&Value::Number(5.4))); assert_eq!( result.get_path("$.main.humidity"), Some(&Value::Number(80.0)) ); assert_eq!( result.get_path("$.weather[0].icon"), Some(&Value::String("cloud_rain".into())) ); } #[tokio::test] async fn polls_simple_json() { let base = start_fake_api().await; let adapter = HttpJsonAdapter::new(); let source = make_source(format!("{base}/simple")); let result = adapter.poll(&source).await.unwrap(); assert_eq!( result.get_path("$.value"), Some(&Value::String("hello".into())) ); } #[tokio::test] async fn returns_error_when_no_url() { let adapter = HttpJsonAdapter::new(); let source = DataSource { id: 1, name: "bad".into(), source_type: DataSourceType::HttpJson, poll_interval: Duration::from_secs(60), config: DataSourceConfig::External { url: None, headers: vec![], api_key: None, }, }; let result = adapter.poll(&source).await; assert!(result.is_err()); } #[tokio::test] async fn returns_error_on_connection_refused() { let adapter = HttpJsonAdapter::new(); let source = make_source("http://127.0.0.1:1".into()); let result = adapter.poll(&source).await; assert!(result.is_err()); }