2025-10-12 19:52:41 +02:00
|
|
|
//! Integration tests for pmoparadise
|
|
|
|
|
|
2025-10-26 08:02:53 +01:00
|
|
|
use pmoparadise::{Block, RadioParadiseClient};
|
2025-10-12 19:52:41 +02:00
|
|
|
use serde_json::json;
|
|
|
|
|
use wiremock::matchers::{method, path, query_param};
|
|
|
|
|
use wiremock::{Mock, MockServer, ResponseTemplate};
|
|
|
|
|
|
|
|
|
|
/// Create a mock Block JSON response
|
|
|
|
|
fn mock_block_json(event: u64, end_event: u64) -> serde_json::Value {
|
|
|
|
|
json!({
|
|
|
|
|
"event": event,
|
|
|
|
|
"end_event": end_event,
|
|
|
|
|
"length": 900000,
|
|
|
|
|
"url": format!("https://apps.radioparadise.com/blocks/chan/0/4/{}-{}.flac", event, end_event),
|
|
|
|
|
"image_base": "https://img.radioparadise.com/covers/l/",
|
|
|
|
|
"song": {
|
|
|
|
|
"0": {
|
|
|
|
|
"artist": "Miles Davis",
|
|
|
|
|
"title": "So What",
|
|
|
|
|
"album": "Kind of Blue",
|
|
|
|
|
"year": 1959,
|
|
|
|
|
"elapsed": 0,
|
|
|
|
|
"duration": 540000,
|
|
|
|
|
"cover": "B00000I0JF.jpg",
|
|
|
|
|
"rating": 9.2
|
|
|
|
|
},
|
|
|
|
|
"1": {
|
|
|
|
|
"artist": "John Coltrane",
|
|
|
|
|
"title": "Giant Steps",
|
|
|
|
|
"album": "Giant Steps",
|
|
|
|
|
"year": 1960,
|
|
|
|
|
"elapsed": 540000,
|
|
|
|
|
"duration": 360000,
|
|
|
|
|
"cover": "B000002I4U.jpg",
|
|
|
|
|
"rating": 9.5
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn test_get_current_block() {
|
|
|
|
|
// Start mock server
|
|
|
|
|
let mock_server = MockServer::start().await;
|
|
|
|
|
|
|
|
|
|
// Setup mock response
|
|
|
|
|
Mock::given(method("GET"))
|
|
|
|
|
.and(path("/api/get_block"))
|
|
|
|
|
.and(query_param("bitrate", "4"))
|
|
|
|
|
.and(query_param("info", "true"))
|
|
|
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(mock_block_json(1234, 5678)))
|
|
|
|
|
.mount(&mock_server)
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
// Create client with mock server URL
|
|
|
|
|
let client = RadioParadiseClient::builder()
|
|
|
|
|
.api_base(format!("{}/api", mock_server.uri()))
|
|
|
|
|
.build()
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
// Test get_block
|
|
|
|
|
let block = client.get_block(None).await.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(block.event, 1234);
|
|
|
|
|
assert_eq!(block.end_event, 5678);
|
|
|
|
|
assert_eq!(block.length, 900000);
|
|
|
|
|
assert_eq!(block.song_count(), 2);
|
|
|
|
|
|
|
|
|
|
// Check songs
|
|
|
|
|
let songs = block.songs_ordered();
|
|
|
|
|
assert_eq!(songs.len(), 2);
|
|
|
|
|
assert_eq!(songs[0].1.artist, "Miles Davis");
|
|
|
|
|
assert_eq!(songs[1].1.artist, "John Coltrane");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn test_get_specific_block() {
|
|
|
|
|
let mock_server = MockServer::start().await;
|
|
|
|
|
|
|
|
|
|
Mock::given(method("GET"))
|
|
|
|
|
.and(path("/api/get_block"))
|
|
|
|
|
.and(query_param("bitrate", "4"))
|
|
|
|
|
.and(query_param("info", "true"))
|
|
|
|
|
.and(query_param("event", "5678"))
|
|
|
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(mock_block_json(5678, 9012)))
|
|
|
|
|
.mount(&mock_server)
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = RadioParadiseClient::builder()
|
|
|
|
|
.api_base(format!("{}/api", mock_server.uri()))
|
|
|
|
|
.build()
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let block = client.get_block(Some(5678)).await.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(block.event, 5678);
|
|
|
|
|
assert_eq!(block.end_event, 9012);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn test_now_playing() {
|
|
|
|
|
let mock_server = MockServer::start().await;
|
|
|
|
|
|
|
|
|
|
Mock::given(method("GET"))
|
|
|
|
|
.and(path("/api/get_block"))
|
|
|
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(mock_block_json(1234, 5678)))
|
|
|
|
|
.mount(&mock_server)
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = RadioParadiseClient::builder()
|
|
|
|
|
.api_base(format!("{}/api", mock_server.uri()))
|
|
|
|
|
.build()
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let now_playing = client.now_playing().await.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(now_playing.block.event, 1234);
|
|
|
|
|
assert_eq!(now_playing.current_song_index, Some(0));
|
|
|
|
|
assert!(now_playing.current_song.is_some());
|
|
|
|
|
|
|
|
|
|
if let Some(song) = &now_playing.current_song {
|
|
|
|
|
assert_eq!(song.artist, "Miles Davis");
|
|
|
|
|
assert_eq!(song.title, "So What");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn test_prefetch_next() {
|
|
|
|
|
let mock_server = MockServer::start().await;
|
|
|
|
|
|
|
|
|
|
// First block
|
|
|
|
|
Mock::given(method("GET"))
|
|
|
|
|
.and(query_param("event", "1234"))
|
|
|
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(mock_block_json(1234, 5678)))
|
|
|
|
|
.mount(&mock_server)
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
// Next block
|
|
|
|
|
Mock::given(method("GET"))
|
|
|
|
|
.and(query_param("event", "5678"))
|
|
|
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(mock_block_json(5678, 9012)))
|
|
|
|
|
.mount(&mock_server)
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let mut client = RadioParadiseClient::builder()
|
|
|
|
|
.api_base(format!("{}/api", mock_server.uri()))
|
|
|
|
|
.build()
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
let current_block = client.get_block(Some(1234)).await.unwrap();
|
|
|
|
|
assert_eq!(current_block.end_event, 5678);
|
|
|
|
|
|
|
|
|
|
client.prefetch_next(¤t_block).await.unwrap();
|
|
|
|
|
|
|
|
|
|
let next_url = client.next_block_url().unwrap();
|
|
|
|
|
assert!(next_url.contains("5678-9012.flac"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn test_block_parse_url_events() {
|
|
|
|
|
let json = mock_block_json(1234, 5678);
|
|
|
|
|
let block: Block = serde_json::from_value(json).unwrap();
|
|
|
|
|
|
|
|
|
|
let (start, end) = block.parse_url_events().unwrap();
|
|
|
|
|
assert_eq!(start, 1234);
|
|
|
|
|
assert_eq!(end, 5678);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn test_song_timing() {
|
|
|
|
|
let json = mock_block_json(1234, 5678);
|
|
|
|
|
let block: Block = serde_json::from_value(json).unwrap();
|
|
|
|
|
|
|
|
|
|
// Find song at 0ms (should be first song)
|
|
|
|
|
let (idx, song) = block.song_at_timestamp(0).unwrap();
|
|
|
|
|
assert_eq!(idx, 0);
|
|
|
|
|
assert_eq!(song.title, "So What");
|
|
|
|
|
|
|
|
|
|
// Find song at 600000ms (should be second song)
|
|
|
|
|
let (idx, song) = block.song_at_timestamp(600000).unwrap();
|
|
|
|
|
assert_eq!(idx, 1);
|
|
|
|
|
assert_eq!(song.title, "Giant Steps");
|
|
|
|
|
|
|
|
|
|
// Timestamp beyond block
|
|
|
|
|
assert!(block.song_at_timestamp(1000000).is_none());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn test_song_cover_url() {
|
|
|
|
|
let json = mock_block_json(1234, 5678);
|
|
|
|
|
let block: Block = serde_json::from_value(json).unwrap();
|
|
|
|
|
|
|
|
|
|
let song = block.get_song(0).unwrap();
|
|
|
|
|
let cover_url = block.cover_url(song.cover.as_ref().unwrap()).unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
cover_url,
|
|
|
|
|
"https://img.radioparadise.com/covers/l/B00000I0JF.jpg"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "per-track")]
|
|
|
|
|
#[tokio::test]
|
|
|
|
|
async fn test_track_position_seconds() {
|
|
|
|
|
let client = RadioParadiseClient::new().await.unwrap();
|
|
|
|
|
let json = mock_block_json(1234, 5678);
|
|
|
|
|
let block: Block = serde_json::from_value(json).unwrap();
|
|
|
|
|
|
|
|
|
|
let (start, duration) = client.track_position_seconds(&block, 0).unwrap();
|
|
|
|
|
assert_eq!(start, 0.0);
|
|
|
|
|
assert_eq!(duration, 540.0);
|
|
|
|
|
|
|
|
|
|
let (start, duration) = client.track_position_seconds(&block, 1).unwrap();
|
|
|
|
|
assert_eq!(start, 540.0);
|
|
|
|
|
assert_eq!(duration, 360.0);
|
|
|
|
|
}
|