Files
k-frame/crates/adapters/http-json/tests/http_json_tests.rs
Gabriel Kaszewski a51d22649a internal data sources (clock, static text), connection indicator, rendering fixes
DataSourceConfig refactored to enum: External/Clock/StaticText. Clock
generates formatted time via chrono, static text emits configured string.

ESP32: connection status indicator (green/red dot bottom-right), per-widget
clear before redraw, RenderEvent enum for local + server messages.

Polling uses DataUpdate instead of ScreenUpdate to avoid wiping widget state.
Empty mappings passthrough raw source data for internal sources.
2026-06-19 11:26:49 +02:00

104 lines
2.9 KiB
Rust

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());
}