restructure test directory
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
use std::panic;
|
||||
|
||||
use futures::{stream::StreamExt, SinkExt};
|
||||
use mpvipc::{parse_event_property, Mpv, MpvDataType, MpvExt, Property};
|
||||
use serde_json::json;
|
||||
use test_log::test;
|
||||
use tokio::{net::UnixStream, task::JoinHandle};
|
||||
use tokio_util::codec::{Framed, LinesCodec, LinesCodecError};
|
||||
|
||||
fn test_socket(
|
||||
answers: Vec<(bool, String)>,
|
||||
) -> (UnixStream, JoinHandle<Result<(), LinesCodecError>>) {
|
||||
let (socket, server) = UnixStream::pair().unwrap();
|
||||
let join_handle = tokio::spawn(async move {
|
||||
let mut framed = Framed::new(socket, LinesCodec::new());
|
||||
for (unsolicited, answer) in answers {
|
||||
if !unsolicited {
|
||||
framed.next().await;
|
||||
}
|
||||
framed.send(answer).await?;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
(server, join_handle)
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_observe_event_successful() {
|
||||
let (server, join_handle) = test_socket(vec![
|
||||
(
|
||||
false,
|
||||
json!({ "request_id": 0, "error": "success" }).to_string(),
|
||||
),
|
||||
(
|
||||
false,
|
||||
json!({ "request_id": 0, "error": "success" }).to_string(),
|
||||
),
|
||||
(
|
||||
true,
|
||||
json!({ "data": 64.0, "event": "property-change", "id": 1, "name": "volume" })
|
||||
.to_string(),
|
||||
),
|
||||
]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
|
||||
mpv.observe_property(1, "volume").await.unwrap();
|
||||
|
||||
let mpv2 = mpv.clone();
|
||||
tokio::spawn(async move {
|
||||
let event = mpv2.get_event_stream().await.next().await.unwrap().unwrap();
|
||||
|
||||
let data = match parse_event_property(event) {
|
||||
Ok((_, Property::Unknown { name, data })) => {
|
||||
assert_eq!(name, "volume");
|
||||
data
|
||||
}
|
||||
Ok((_, property)) => panic!("{:?}", property),
|
||||
Err(err) => panic!("{:?}", err),
|
||||
};
|
||||
match data {
|
||||
Some(MpvDataType::Double(data)) => assert_eq!(data, 64.0),
|
||||
Some(data) => panic!("Unexpected value: {:?}", data),
|
||||
None => panic!("No data"),
|
||||
}
|
||||
});
|
||||
|
||||
mpv.set_property("volume", 64.0).await.unwrap();
|
||||
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
use std::{panic, time::Duration};
|
||||
|
||||
use futures::{stream::FuturesUnordered, SinkExt, StreamExt};
|
||||
use mpvipc::{MpvError, Mpv, MpvExt, Playlist, PlaylistEntry};
|
||||
use serde_json::{json, Value};
|
||||
use test_log::test;
|
||||
use tokio::{net::UnixStream, task::JoinHandle};
|
||||
use tokio_util::codec::{Framed, LinesCodec, LinesCodecError};
|
||||
|
||||
fn test_socket(answers: Vec<String>) -> (UnixStream, JoinHandle<Result<(), LinesCodecError>>) {
|
||||
let (socket, server) = UnixStream::pair().unwrap();
|
||||
let join_handle = tokio::spawn(async move {
|
||||
let mut framed = Framed::new(socket, LinesCodec::new());
|
||||
for answer in answers {
|
||||
framed.next().await;
|
||||
framed.send(answer).await?;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
(server, join_handle)
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_get_property_successful() {
|
||||
let (server, join_handle) = test_socket(vec![
|
||||
json!({ "data": 100.0, "request_id": 0, "error": "success" }).to_string(),
|
||||
]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
let volume: f64 = mpv.get_property("volume").await.unwrap();
|
||||
|
||||
assert_eq!(volume, 100.0);
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_get_property_broken_pipe() {
|
||||
let (server, join_handle) = test_socket(vec![]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
let maybe_volume = mpv.get_property::<f64>("volume").await;
|
||||
|
||||
match maybe_volume {
|
||||
Err(MpvError::MpvSocketConnectionError(err)) => {
|
||||
assert_eq!(err.to_string(), "Broken pipe (os error 32)");
|
||||
}
|
||||
_ => panic!("Unexpected result: {:?}", maybe_volume),
|
||||
}
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_get_property_wrong_type() {
|
||||
let (server, join_handle) = test_socket(vec![
|
||||
json!({ "data": 100.0, "request_id": 0, "error": "success" }).to_string(),
|
||||
]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
let maybe_volume = mpv.get_property::<bool>("volume").await;
|
||||
|
||||
match maybe_volume {
|
||||
Err(MpvError::ValueContainsUnexpectedType {
|
||||
expected_type,
|
||||
received,
|
||||
}) => {
|
||||
assert_eq!(expected_type, "bool");
|
||||
assert_eq!(received, json!(100.0));
|
||||
}
|
||||
_ => panic!("Unexpected result: {:?}", maybe_volume),
|
||||
}
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_get_property_error() {
|
||||
let (server, join_handle) = test_socket(vec![
|
||||
json!({ "error": "property unavailable", "request_id": 0 }).to_string(),
|
||||
]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
let maybe_volume = mpv.get_property::<f64>("volume").await;
|
||||
|
||||
match maybe_volume {
|
||||
Err(MpvError::MpvError(err)) => {
|
||||
assert_eq!(err, "property unavailable");
|
||||
}
|
||||
_ => panic!("Unexpected result: {:?}", maybe_volume),
|
||||
}
|
||||
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_get_property_simultaneous_requests() {
|
||||
let (socket, server) = UnixStream::pair().unwrap();
|
||||
let mpv_handle: JoinHandle<Result<(), LinesCodecError>> = tokio::spawn(async move {
|
||||
let mut framed = Framed::new(socket, LinesCodec::new());
|
||||
|
||||
while let Some(request) = framed.next().await {
|
||||
if let Ok(json) = serde_json::from_str::<Value>(&request.unwrap()) {
|
||||
let property = json["command"][1].as_str().unwrap();
|
||||
log::info!("Received request for property: {:?}", property);
|
||||
match property {
|
||||
"volume" => {
|
||||
let response =
|
||||
json!({ "data": 100.0, "request_id": 0, "error": "success" })
|
||||
.to_string();
|
||||
framed.send(response).await.unwrap();
|
||||
}
|
||||
"pause" => {
|
||||
let response = json!({ "data": true, "request_id": 0, "error": "success" })
|
||||
.to_string();
|
||||
framed.send(response).await.unwrap();
|
||||
}
|
||||
_ => {
|
||||
let response =
|
||||
json!({ "error": "property unavailable", "request_id": 0 }).to_string();
|
||||
framed.send(response).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
|
||||
let mpv_clone_1 = mpv.clone();
|
||||
let mpv_poller_1 = tokio::spawn(async move {
|
||||
loop {
|
||||
let volume: f64 = mpv_clone_1.get_property("volume").await.unwrap();
|
||||
assert_eq!(volume, 100.0);
|
||||
}
|
||||
});
|
||||
|
||||
let mpv_clone_2 = mpv.clone();
|
||||
let mpv_poller_2 = tokio::spawn(async move {
|
||||
loop {
|
||||
tokio::time::sleep(Duration::from_millis(1)).await;
|
||||
let paused: bool = mpv_clone_2.get_property("pause").await.unwrap();
|
||||
assert!(paused);
|
||||
}
|
||||
});
|
||||
|
||||
let mpv_clone_3 = mpv.clone();
|
||||
let mpv_poller_3 = tokio::spawn(async move {
|
||||
loop {
|
||||
tokio::time::sleep(Duration::from_millis(2)).await;
|
||||
let maybe_volume = mpv_clone_3.get_property::<f64>("nonexistent").await;
|
||||
match maybe_volume {
|
||||
Err(MpvError::MpvError(err)) => {
|
||||
assert_eq!(err, "property unavailable");
|
||||
}
|
||||
_ => panic!("Unexpected result: {:?}", maybe_volume),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut tasks = FuturesUnordered::new();
|
||||
tasks.push(mpv_handle);
|
||||
tasks.push(mpv_poller_1);
|
||||
tasks.push(mpv_poller_2);
|
||||
tasks.push(mpv_poller_3);
|
||||
|
||||
if tokio::time::timeout(Duration::from_millis(200), tasks.next())
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
panic!("One of the pollers quit unexpectedly");
|
||||
};
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_get_playlist() {
|
||||
let expected = Playlist(vec![
|
||||
PlaylistEntry {
|
||||
id: 0,
|
||||
filename: "file1".to_string(),
|
||||
title: "title1".to_string(),
|
||||
current: false,
|
||||
},
|
||||
PlaylistEntry {
|
||||
id: 1,
|
||||
filename: "file2".to_string(),
|
||||
title: "title2".to_string(),
|
||||
current: true,
|
||||
},
|
||||
PlaylistEntry {
|
||||
id: 2,
|
||||
filename: "file3".to_string(),
|
||||
title: "title3".to_string(),
|
||||
current: false,
|
||||
},
|
||||
]);
|
||||
|
||||
let (server, join_handle) = test_socket(vec![json!({
|
||||
"data": expected.0.iter().map(|entry| {
|
||||
json!({
|
||||
"filename": entry.filename,
|
||||
"title": entry.title,
|
||||
"current": entry.current
|
||||
})
|
||||
}).collect::<Vec<Value>>(),
|
||||
"request_id": 0,
|
||||
"error": "success"
|
||||
})
|
||||
.to_string()]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
let playlist = mpv.get_playlist().await.unwrap();
|
||||
|
||||
assert_eq!(playlist, expected);
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_get_playlist_empty() {
|
||||
let (server, join_handle) = test_socket(vec![
|
||||
json!({ "data": [], "request_id": 0, "error": "success" }).to_string(),
|
||||
]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
let playlist = mpv.get_playlist().await.unwrap();
|
||||
|
||||
assert_eq!(playlist, Playlist(vec![]));
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
mod events;
|
||||
mod get_property;
|
||||
mod set_property;
|
||||
@@ -0,0 +1,233 @@
|
||||
use std::{panic, time::Duration};
|
||||
|
||||
use futures::{stream::FuturesUnordered, SinkExt, StreamExt};
|
||||
use mpvipc::{MpvError, Mpv, MpvExt, Playlist, PlaylistEntry};
|
||||
use serde_json::{json, Value};
|
||||
use test_log::test;
|
||||
use tokio::{net::UnixStream, task::JoinHandle};
|
||||
use tokio_util::codec::{Framed, LinesCodec, LinesCodecError};
|
||||
|
||||
fn test_socket(answers: Vec<String>) -> (UnixStream, JoinHandle<Result<(), LinesCodecError>>) {
|
||||
let (socket, server) = UnixStream::pair().unwrap();
|
||||
let join_handle = tokio::spawn(async move {
|
||||
let mut framed = Framed::new(socket, LinesCodec::new());
|
||||
for answer in answers {
|
||||
framed.next().await;
|
||||
framed.send(answer).await?;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
(server, join_handle)
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_set_property_successful() {
|
||||
let (server, join_handle) = test_socket(vec![
|
||||
json!({ "data": null, "request_id": 0, "error": "success" }).to_string(),
|
||||
]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
let volume = mpv.set_property("volume", 64.0).await;
|
||||
|
||||
assert!(volume.is_ok());
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_set_property_broken_pipe() {
|
||||
let (server, join_handle) = test_socket(vec![]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
let maybe_set_volume = mpv.set_property("volume", 64.0).await;
|
||||
|
||||
match maybe_set_volume {
|
||||
Err(MpvError::MpvSocketConnectionError(err)) => {
|
||||
assert_eq!(err.to_string(), "Broken pipe (os error 32)");
|
||||
}
|
||||
_ => panic!("Unexpected result: {:?}", maybe_set_volume),
|
||||
}
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_set_property_wrong_type() {
|
||||
let (server, join_handle) = test_socket(vec![
|
||||
json!({"request_id":0,"error":"unsupported format for accessing property"}).to_string(),
|
||||
]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
let maybe_volume = mpv.set_property::<bool>("volume", true).await;
|
||||
|
||||
match maybe_volume {
|
||||
Err(MpvError::MpvError(err)) => {
|
||||
assert_eq!(err, "unsupported format for accessing property");
|
||||
}
|
||||
_ => panic!("Unexpected result: {:?}", maybe_volume),
|
||||
}
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_get_property_error() {
|
||||
let (server, join_handle) = test_socket(vec![
|
||||
json!({"request_id":0,"error":"property not found"}).to_string(),
|
||||
]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
let maybe_volume = mpv.set_property("nonexistent", true).await;
|
||||
|
||||
match maybe_volume {
|
||||
Err(MpvError::MpvError(err)) => {
|
||||
assert_eq!(err, "property not found");
|
||||
}
|
||||
_ => panic!("Unexpected result: {:?}", maybe_volume),
|
||||
}
|
||||
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_set_property_simultaneous_requests() {
|
||||
let (socket, server) = UnixStream::pair().unwrap();
|
||||
let mpv_handle: JoinHandle<Result<(), LinesCodecError>> = tokio::spawn(async move {
|
||||
let mut framed = Framed::new(socket, LinesCodec::new());
|
||||
|
||||
while let Some(request) = framed.next().await {
|
||||
if let Ok(json) = serde_json::from_str::<Value>(&request.unwrap()) {
|
||||
let property = json["command"][1].as_str().unwrap();
|
||||
let value = &json["command"][2];
|
||||
log::info!(
|
||||
"Received set property command: {:?} => {:?}",
|
||||
property,
|
||||
value
|
||||
);
|
||||
match property {
|
||||
"volume" => {
|
||||
let response = json!({ "request_id": 0, "error": "success" }).to_string();
|
||||
framed.send(response).await.unwrap();
|
||||
}
|
||||
"pause" => {
|
||||
let response = json!({ "request_id": 0, "error": "success" }).to_string();
|
||||
framed.send(response).await.unwrap();
|
||||
}
|
||||
_ => {
|
||||
let response =
|
||||
json!({ "error":"property not found", "request_id": 0 }).to_string();
|
||||
framed.send(response).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
|
||||
let mpv_clone_1 = mpv.clone();
|
||||
let mpv_poller_1 = tokio::spawn(async move {
|
||||
loop {
|
||||
let status = mpv_clone_1.set_property("volume", 100).await;
|
||||
match status {
|
||||
Ok(()) => {},
|
||||
_ => panic!("Unexpected result: {:?}", status),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mpv_clone_2 = mpv.clone();
|
||||
let mpv_poller_2 = tokio::spawn(async move {
|
||||
loop {
|
||||
tokio::time::sleep(Duration::from_millis(1)).await;
|
||||
let status = mpv_clone_2.set_property("pause", false).await;
|
||||
match status {
|
||||
Ok(()) => {},
|
||||
_ => panic!("Unexpected result: {:?}", status),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mpv_clone_3 = mpv.clone();
|
||||
let mpv_poller_3 = tokio::spawn(async move {
|
||||
loop {
|
||||
tokio::time::sleep(Duration::from_millis(2)).await;
|
||||
let maybe_volume = mpv_clone_3.set_property("nonexistent", "a").await;
|
||||
match maybe_volume {
|
||||
Err(MpvError::MpvError(err)) => {
|
||||
assert_eq!(err, "property not found");
|
||||
}
|
||||
_ => panic!("Unexpected result: {:?}", maybe_volume),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut tasks = FuturesUnordered::new();
|
||||
tasks.push(mpv_handle);
|
||||
tasks.push(mpv_poller_1);
|
||||
tasks.push(mpv_poller_2);
|
||||
tasks.push(mpv_poller_3);
|
||||
|
||||
if tokio::time::timeout(Duration::from_millis(200), tasks.next())
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
panic!("One of the pollers quit unexpectedly");
|
||||
};
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_get_playlist() {
|
||||
let expected = Playlist(vec![
|
||||
PlaylistEntry {
|
||||
id: 0,
|
||||
filename: "file1".to_string(),
|
||||
title: "title1".to_string(),
|
||||
current: false,
|
||||
},
|
||||
PlaylistEntry {
|
||||
id: 1,
|
||||
filename: "file2".to_string(),
|
||||
title: "title2".to_string(),
|
||||
current: true,
|
||||
},
|
||||
PlaylistEntry {
|
||||
id: 2,
|
||||
filename: "file3".to_string(),
|
||||
title: "title3".to_string(),
|
||||
current: false,
|
||||
},
|
||||
]);
|
||||
|
||||
let (server, join_handle) = test_socket(vec![json!({
|
||||
"data": expected.0.iter().map(|entry| {
|
||||
json!({
|
||||
"filename": entry.filename,
|
||||
"title": entry.title,
|
||||
"current": entry.current
|
||||
})
|
||||
}).collect::<Vec<Value>>(),
|
||||
"request_id": 0,
|
||||
"error": "success"
|
||||
})
|
||||
.to_string()]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
let playlist = mpv.get_playlist().await.unwrap();
|
||||
|
||||
assert_eq!(playlist, expected);
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
|
||||
#[test(tokio::test)]
|
||||
async fn test_get_playlist_empty() {
|
||||
let (server, join_handle) = test_socket(vec![
|
||||
json!({ "data": [], "request_id": 0, "error": "success" }).to_string(),
|
||||
]);
|
||||
|
||||
let mpv = Mpv::connect_socket(server).await.unwrap();
|
||||
let playlist = mpv.get_playlist().await.unwrap();
|
||||
|
||||
assert_eq!(playlist, Playlist(vec![]));
|
||||
join_handle.await.unwrap().unwrap();
|
||||
}
|
||||
Reference in New Issue
Block a user