use domain::{DataSource, DataSourceConfig, DataSourcePort, DataSourceType, Value}; use media_adapter::MediaAdapter; use std::time::Duration; fn subsonic_response(playing: bool) -> serde_json::Value { if playing { serde_json::json!({ "subsonic-response": { "status": "ok", "nowPlaying": { "entry": [{ "title": "Believer", "artist": "Imagine Dragons", "album": "Evolve", "duration": 204 }] } } }) } else { serde_json::json!({ "subsonic-response": { "status": "ok", "nowPlaying": {} } }) } } async fn start_fake_subsonic(playing: bool) -> String { let app = axum::Router::new().route( "/rest/getNowPlaying.view", axum::routing::get(move || async move { axum::response::Json(subsonic_response(playing)) }), ); 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: "navidrome".into(), source_type: DataSourceType::Media, poll_interval: Duration::from_secs(5), config: DataSourceConfig::External { url: Some(url), headers: vec![ ("username".into(), "test".into()), ("password".into(), "testpass".into()), ], api_key: None, }, } } #[tokio::test] async fn returns_now_playing_info() { let base = start_fake_subsonic(true).await; let adapter = MediaAdapter::new(); let source = make_source(base); let result = adapter.poll(&source).await.unwrap(); assert_eq!(result.get_path("$.playing"), Some(&Value::Bool(true))); assert_eq!( result.get_path("$.title"), Some(&Value::String("Believer".into())) ); assert_eq!( result.get_path("$.artist"), Some(&Value::String("Imagine Dragons".into())) ); } #[tokio::test] async fn returns_not_playing_when_empty() { let base = start_fake_subsonic(false).await; let adapter = MediaAdapter::new(); let source = make_source(base); let result = adapter.poll(&source).await.unwrap(); assert_eq!(result.get_path("$.playing"), Some(&Value::Bool(false))); }