add tests for broadcasts
All checks were successful
CI/CD Pipeline / test (push) Successful in 3m46s
CI/CD Pipeline / deploy (push) Successful in 6m32s

This commit is contained in:
Philipp Hofer
2025-10-29 11:55:14 +01:00
parent 1cab4d0bf5
commit ad759e1ca9
2 changed files with 69 additions and 27 deletions

View File

@@ -1,22 +1,44 @@
use crate::Backend; use crate::Backend;
use chrono::DateTime; use chrono::DateTime;
use serde_json::Value; use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct InferenceStream {
#[serde(rename = "loopStreamId")]
pub loop_stream_id: String,
#[serde(rename = "start")]
pub start_timestamp: i64,
}
#[derive(Debug, Serialize, Deserialize)]
struct InferenceData {
pub title: String,
pub streams: Vec<InferenceStream>,
}
impl Backend { impl Backend {
pub(crate) async fn get_broadcast( pub(crate) async fn get_broadcast(
&self, &self,
url: String, url: String,
) -> Result<Option<Broadcast>, Box<dyn std::error::Error>> { ) -> Result<Option<Broadcast>, Box<dyn std::error::Error>> {
let data: Value = match self { let data: InferenceData = match self {
Backend::Prod => reqwest::get(&url).await?.json().await?, Backend::Prod => reqwest::get(&url).await?.json::<InferenceData>().await?,
#[cfg(test)] #[cfg(test)]
Backend::Test => todo!(), Backend::Test => InferenceData {
title: "test-title".into(),
streams: vec![InferenceStream {
loop_stream_id: "test.mp3".into(),
start_timestamp: 1761734636000,
}],
},
}; };
Broadcast::from_data(url, data).await Broadcast::from_data(url, data).await
} }
} }
#[derive(Clone)] #[derive(Debug, Clone)]
pub(crate) struct Broadcast { pub(crate) struct Broadcast {
pub(crate) url: String, pub(crate) url: String,
pub(crate) media_url: String, pub(crate) media_url: String,
@@ -27,32 +49,23 @@ pub(crate) struct Broadcast {
impl Broadcast { impl Broadcast {
async fn from_data( async fn from_data(
url: String, url: String,
data: Value, data: InferenceData,
) -> Result<Option<Self>, Box<dyn std::error::Error>> { ) -> Result<Option<Self>, Box<dyn std::error::Error>> {
let Some(streams) = data["streams"].as_array() else { if data.streams.is_empty() {
return Err(String::from("No 'streams' found").into());
};
if streams.is_empty() {
return Ok(None); return Ok(None);
} }
assert_eq!(streams.len(), 1); assert_eq!(data.streams.len(), 1);
let stream = &data.streams[0];
let Some(id) = streams[0]["loopStreamId"].as_str() else { let media_url = format!(
return Err(String::from("No 'loopStreamId' found").into()); "https://loopstream01.apa.at/?channel=oe1&shoutcast=0&id={}",
}; stream.loop_stream_id
let media_url = format!("https://loopstream01.apa.at/?channel=oe1&shoutcast=0&id={id}"); );
let Some(title) = data["title"].as_str() else { let Some(timestamp) = DateTime::from_timestamp(stream.start_timestamp / 1000, 0) else {
return Err(format!("{url} has no title").into());
};
let Some(timestamp) = data["start"].as_number() else {
return Err(format!("{url} has no start").into());
};
let Some(timestamp) = DateTime::from_timestamp(timestamp.as_i64().unwrap() / 1000, 0)
else {
return Err(format!( return Err(format!(
"broadcastDay in {url} not in a valid format (unix timestamp): {timestamp}" "broadcastDay in {url} not in a valid format (unix timestamp): {}",
stream.start_timestamp
) )
.into()); .into());
}; };
@@ -60,7 +73,7 @@ impl Broadcast {
Ok(Some(Self { Ok(Some(Self {
url, url,
media_url, media_url,
title: title.into(), title: data.title,
timestamp, timestamp,
})) }))
} }
@@ -71,3 +84,29 @@ impl PartialEq for Broadcast {
self.url == other.url self.url == other.url
} }
} }
#[cfg(test)]
mod tests {
use crate::Backend;
use chrono::{TimeZone, Utc};
#[tokio::test]
async fn happy() {
let backend = Backend::Test;
let actual = backend
.get_broadcast("test-url".into())
.await
.unwrap()
.unwrap();
assert_eq!(&actual.url, "test-url");
assert_eq!(
&actual.media_url,
"https://loopstream01.apa.at/?channel=oe1&shoutcast=0&id=test.mp3"
);
assert_eq!(&actual.title, "test-title");
assert_eq!(
actual.timestamp,
Utc.with_ymd_and_hms(2025, 10, 29, 10, 43, 56).unwrap()
);
}
}

View File

@@ -89,7 +89,10 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn filter_result() { async fn filter_result() {
let backend = Backend::Test; let backend = Backend::Test;
let actual = backend.get_broadcasts(&["test-href".into()]).await.unwrap(); let actual = backend
.get_broadcasts(&["test-title".into()])
.await
.unwrap();
assert_eq!(actual, vec!["test-href"]); assert_eq!(actual, vec!["test-href"]);
} }
} }