API versioning tests
This commit is contained in:
parent
caa8907297
commit
caf6feea7a
10 changed files with 179 additions and 86 deletions
|
@ -1,8 +1,30 @@
|
|||
use error::APIError;
|
||||
|
||||
mod dto;
|
||||
mod error;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
pub enum APIMajorVersion {
|
||||
V7,
|
||||
V8,
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for APIMajorVersion {
|
||||
type Error = APIError;
|
||||
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
7 => Ok(Self::V7),
|
||||
8 => Ok(Self::V8),
|
||||
_ => Err(APIError::UnsupportedAPIVersion),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const API_MAJOR_VERSION: i32 = 8;
|
||||
pub const API_MINOR_VERSION: i32 = 0;
|
||||
|
||||
mod axum;
|
||||
pub use axum::*;
|
||||
|
|
|
@ -12,11 +12,10 @@ use percent_encoding::percent_decode_str;
|
|||
|
||||
use crate::{
|
||||
app::{config, ddns, index, lastfm, playlist, scanner, settings, thumbnail, user, vfs, App},
|
||||
server::{dto, error::APIError},
|
||||
server::{dto, error::APIError, APIMajorVersion, API_MAJOR_VERSION, API_MINOR_VERSION},
|
||||
};
|
||||
|
||||
use super::auth::{AdminRights, Auth};
|
||||
use super::version::Version;
|
||||
|
||||
pub fn router() -> Router<App> {
|
||||
Router::new()
|
||||
|
@ -68,8 +67,8 @@ pub fn router() -> Router<App> {
|
|||
|
||||
async fn get_version() -> Json<dto::Version> {
|
||||
let current_version = dto::Version {
|
||||
major: dto::API_MAJOR_VERSION,
|
||||
minor: dto::API_MINOR_VERSION,
|
||||
major: API_MAJOR_VERSION,
|
||||
minor: API_MINOR_VERSION,
|
||||
};
|
||||
Json(current_version)
|
||||
}
|
||||
|
@ -254,16 +253,19 @@ async fn post_trigger_index(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn collection_files_to_response(files: Vec<index::CollectionFile>, version: Version) -> Response {
|
||||
match version {
|
||||
Version::V7 => Json(
|
||||
fn collection_files_to_response(
|
||||
files: Vec<index::CollectionFile>,
|
||||
api_version: APIMajorVersion,
|
||||
) -> Response {
|
||||
match api_version {
|
||||
APIMajorVersion::V7 => Json(
|
||||
files
|
||||
.into_iter()
|
||||
.map(|f| f.into())
|
||||
.collect::<Vec<dto::v7::CollectionFile>>(),
|
||||
)
|
||||
.into_response(),
|
||||
Version::V8 => Json(
|
||||
APIMajorVersion::V8 => Json(
|
||||
files
|
||||
.into_iter()
|
||||
.map(|f| f.into())
|
||||
|
@ -273,16 +275,16 @@ fn collection_files_to_response(files: Vec<index::CollectionFile>, version: Vers
|
|||
}
|
||||
}
|
||||
|
||||
fn songs_to_response(files: Vec<scanner::Song>, version: Version) -> Response {
|
||||
match version {
|
||||
Version::V7 => Json(
|
||||
fn songs_to_response(files: Vec<scanner::Song>, api_version: APIMajorVersion) -> Response {
|
||||
match api_version {
|
||||
APIMajorVersion::V7 => Json(
|
||||
files
|
||||
.into_iter()
|
||||
.map(|f| f.into())
|
||||
.collect::<Vec<dto::v7::Song>>(),
|
||||
)
|
||||
.into_response(),
|
||||
Version::V8 => Json(
|
||||
APIMajorVersion::V8 => Json(
|
||||
files
|
||||
.into_iter()
|
||||
.map(|f| f.into())
|
||||
|
@ -292,16 +294,19 @@ fn songs_to_response(files: Vec<scanner::Song>, version: Version) -> Response {
|
|||
}
|
||||
}
|
||||
|
||||
fn directories_to_response(files: Vec<scanner::Directory>, version: Version) -> Response {
|
||||
match version {
|
||||
Version::V7 => Json(
|
||||
fn directories_to_response(
|
||||
files: Vec<scanner::Directory>,
|
||||
api_version: APIMajorVersion,
|
||||
) -> Response {
|
||||
match api_version {
|
||||
APIMajorVersion::V7 => Json(
|
||||
files
|
||||
.into_iter()
|
||||
.map(|f| f.into())
|
||||
.collect::<Vec<dto::v7::Directory>>(),
|
||||
)
|
||||
.into_response(),
|
||||
Version::V8 => Json(
|
||||
APIMajorVersion::V8 => Json(
|
||||
files
|
||||
.into_iter()
|
||||
.map(|f| f.into())
|
||||
|
@ -313,19 +318,19 @@ fn directories_to_response(files: Vec<scanner::Directory>, version: Version) ->
|
|||
|
||||
async fn get_browse_root(
|
||||
_auth: Auth,
|
||||
version: Version,
|
||||
api_version: APIMajorVersion,
|
||||
State(index): State<index::Index>,
|
||||
) -> Response {
|
||||
let result = match index.browse(std::path::Path::new("")).await {
|
||||
Ok(r) => r,
|
||||
Err(e) => return APIError::from(e).into_response(),
|
||||
};
|
||||
collection_files_to_response(result, version)
|
||||
collection_files_to_response(result, api_version)
|
||||
}
|
||||
|
||||
async fn get_browse(
|
||||
_auth: Auth,
|
||||
version: Version,
|
||||
api_version: APIMajorVersion,
|
||||
State(index): State<index::Index>,
|
||||
Path(path): Path<String>,
|
||||
) -> Response {
|
||||
|
@ -334,24 +339,24 @@ async fn get_browse(
|
|||
Ok(r) => r,
|
||||
Err(e) => return APIError::from(e).into_response(),
|
||||
};
|
||||
collection_files_to_response(result, version)
|
||||
collection_files_to_response(result, api_version)
|
||||
}
|
||||
|
||||
async fn get_flatten_root(
|
||||
_auth: Auth,
|
||||
version: Version,
|
||||
api_version: APIMajorVersion,
|
||||
State(index): State<index::Index>,
|
||||
) -> Response {
|
||||
let songs = match index.flatten(std::path::Path::new("")).await {
|
||||
Ok(s) => s,
|
||||
Err(e) => return APIError::from(e).into_response(),
|
||||
};
|
||||
songs_to_response(songs, version)
|
||||
songs_to_response(songs, api_version)
|
||||
}
|
||||
|
||||
async fn get_flatten(
|
||||
_auth: Auth,
|
||||
version: Version,
|
||||
api_version: APIMajorVersion,
|
||||
State(index): State<index::Index>,
|
||||
Path(path): Path<String>,
|
||||
) -> Response {
|
||||
|
@ -360,40 +365,48 @@ async fn get_flatten(
|
|||
Ok(s) => s,
|
||||
Err(e) => return APIError::from(e).into_response(),
|
||||
};
|
||||
songs_to_response(songs, version)
|
||||
songs_to_response(songs, api_version)
|
||||
}
|
||||
|
||||
async fn get_random(_auth: Auth, version: Version, State(index): State<index::Index>) -> Response {
|
||||
async fn get_random(
|
||||
_auth: Auth,
|
||||
api_version: APIMajorVersion,
|
||||
State(index): State<index::Index>,
|
||||
) -> Response {
|
||||
let directories = match index.get_random_albums(20).await {
|
||||
Ok(d) => d,
|
||||
Err(e) => return APIError::from(e).into_response(),
|
||||
};
|
||||
directories_to_response(directories, version)
|
||||
directories_to_response(directories, api_version)
|
||||
}
|
||||
|
||||
async fn get_recent(_auth: Auth, version: Version, State(index): State<index::Index>) -> Response {
|
||||
async fn get_recent(
|
||||
_auth: Auth,
|
||||
api_version: APIMajorVersion,
|
||||
State(index): State<index::Index>,
|
||||
) -> Response {
|
||||
let directories = match index.get_recent_albums(20).await {
|
||||
Ok(d) => d,
|
||||
Err(e) => return APIError::from(e).into_response(),
|
||||
};
|
||||
directories_to_response(directories, version)
|
||||
directories_to_response(directories, api_version)
|
||||
}
|
||||
|
||||
async fn get_search_root(
|
||||
_auth: Auth,
|
||||
version: Version,
|
||||
api_version: APIMajorVersion,
|
||||
State(index): State<index::Index>,
|
||||
) -> Response {
|
||||
let files = match index.search("").await {
|
||||
Ok(f) => f,
|
||||
Err(e) => return APIError::from(e).into_response(),
|
||||
};
|
||||
collection_files_to_response(files, version)
|
||||
collection_files_to_response(files, api_version)
|
||||
}
|
||||
|
||||
async fn get_search(
|
||||
_auth: Auth,
|
||||
version: Version,
|
||||
api_version: APIMajorVersion,
|
||||
State(index): State<index::Index>,
|
||||
Path(query): Path<String>,
|
||||
) -> Response {
|
||||
|
@ -401,7 +414,7 @@ async fn get_search(
|
|||
Ok(f) => f,
|
||||
Err(e) => return APIError::from(e).into_response(),
|
||||
};
|
||||
collection_files_to_response(files, version)
|
||||
collection_files_to_response(files, api_version)
|
||||
}
|
||||
|
||||
async fn get_playlists(
|
||||
|
@ -431,7 +444,7 @@ async fn put_playlist(
|
|||
|
||||
async fn get_playlist(
|
||||
auth: Auth,
|
||||
version: Version,
|
||||
api_version: APIMajorVersion,
|
||||
State(playlist_manager): State<playlist::Manager>,
|
||||
Path(name): Path<String>,
|
||||
) -> Response {
|
||||
|
@ -442,7 +455,7 @@ async fn get_playlist(
|
|||
Ok(s) => s,
|
||||
Err(e) => return APIError::from(e).into_response(),
|
||||
};
|
||||
songs_to_response(songs, version)
|
||||
songs_to_response(songs, api_version)
|
||||
}
|
||||
|
||||
async fn delete_playlist(
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
use axum::{async_trait, extract::FromRequestParts};
|
||||
use http::request::Parts;
|
||||
|
||||
use crate::server::{dto, error::APIError};
|
||||
|
||||
pub enum Version {
|
||||
V7,
|
||||
V8,
|
||||
}
|
||||
use crate::server::{error::APIError, APIMajorVersion};
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for Version
|
||||
impl<S> FromRequestParts<S> for APIMajorVersion
|
||||
where
|
||||
S: Send + Sync,
|
||||
{
|
||||
|
@ -19,18 +14,14 @@ where
|
|||
let version_header = match parts.headers.get("Accept-Version").map(|h| h.to_str()) {
|
||||
Some(Ok(h)) => h,
|
||||
Some(Err(_)) => return Err(APIError::InvalidAPIVersionHeader),
|
||||
None => return Ok(Version::V7), // TODO Drop support for implicit version in future release
|
||||
None => return Ok(APIMajorVersion::V7), // TODO Drop support for implicit version in future release
|
||||
};
|
||||
|
||||
let version: dto::Version = match serde_json::from_str(version_header) {
|
||||
let version = match str::parse::<i32>(version_header) {
|
||||
Ok(v) => v,
|
||||
Err(_) => return Err(APIError::APIVersionHeaderParseError),
|
||||
};
|
||||
|
||||
Ok(match version.major {
|
||||
7 => Version::V7,
|
||||
8 => Version::V8,
|
||||
_ => return Err(APIError::UnsupportedAPIVersion),
|
||||
})
|
||||
APIMajorVersion::try_from(version)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
pub mod v7;
|
||||
pub mod v8;
|
||||
|
||||
pub const API_MAJOR_VERSION: i32 = 8;
|
||||
pub const API_MINOR_VERSION: i32 = 0;
|
||||
|
||||
pub use v8::*;
|
||||
|
|
|
@ -24,6 +24,7 @@ mod web;
|
|||
|
||||
use crate::server::dto;
|
||||
use crate::server::test::constants::*;
|
||||
use protocol::V8;
|
||||
|
||||
pub use crate::server::axum::test::ServiceType;
|
||||
|
||||
|
@ -116,7 +117,7 @@ pub trait TestService {
|
|||
assert_eq!(response.status(), StatusCode::OK);
|
||||
|
||||
loop {
|
||||
let browse_request = protocol::browse(Path::new(""));
|
||||
let browse_request = protocol::browse::<V8>(Path::new(""));
|
||||
let response = self
|
||||
.fetch_json::<(), Vec<dto::CollectionFile>>(&browse_request)
|
||||
.await;
|
||||
|
@ -128,7 +129,7 @@ pub trait TestService {
|
|||
}
|
||||
|
||||
loop {
|
||||
let flatten_request = protocol::flatten(Path::new(""));
|
||||
let flatten_request = protocol::flatten::<V8>(Path::new(""));
|
||||
let response = self.fetch_json::<_, Vec<dto::Song>>(&flatten_request).await;
|
||||
let entries = response.body();
|
||||
if !entries.is_empty() {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use http::StatusCode;
|
||||
|
||||
use crate::server::dto;
|
||||
use crate::server::test::protocol::V8;
|
||||
use crate::server::test::{protocol, ServiceType, TestService};
|
||||
use crate::test_name;
|
||||
|
||||
|
@ -47,7 +48,7 @@ async fn trigger_index_golden_path() {
|
|||
service.complete_initial_setup().await;
|
||||
service.login_admin().await;
|
||||
|
||||
let request = protocol::random();
|
||||
let request = protocol::random::<V8>();
|
||||
|
||||
let response = service.fetch_json::<_, Vec<dto::Directory>>(&request).await;
|
||||
let entries = response.body();
|
||||
|
|
|
@ -2,6 +2,7 @@ use headers::{self, HeaderMapExt};
|
|||
use http::StatusCode;
|
||||
|
||||
use crate::server::dto;
|
||||
use crate::server::test::protocol::V8;
|
||||
use crate::server::test::{constants::*, protocol, ServiceType, TestService};
|
||||
use crate::test_name;
|
||||
|
||||
|
@ -45,7 +46,7 @@ async fn authentication_via_bearer_http_header_rejects_bad_token() {
|
|||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
service.complete_initial_setup().await;
|
||||
|
||||
let mut request = protocol::random();
|
||||
let mut request = protocol::random::<V8>();
|
||||
let bearer = headers::Authorization::bearer("garbage").unwrap();
|
||||
request.headers_mut().typed_insert(bearer);
|
||||
|
||||
|
@ -67,7 +68,7 @@ async fn authentication_via_bearer_http_header_golden_path() {
|
|||
|
||||
service.logout().await;
|
||||
|
||||
let mut request = protocol::random();
|
||||
let mut request = protocol::random::<V8>();
|
||||
let bearer = headers::Authorization::bearer(&authorization.token).unwrap();
|
||||
request.headers_mut().typed_insert(bearer);
|
||||
let response = service.fetch(&request).await;
|
||||
|
@ -79,7 +80,7 @@ async fn authentication_via_query_param_rejects_bad_token() {
|
|||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
service.complete_initial_setup().await;
|
||||
|
||||
let mut request = protocol::random();
|
||||
let mut request = protocol::random::<V8>();
|
||||
*request.uri_mut() = (request.uri().to_string() + "?auth_token=garbage-token")
|
||||
.parse()
|
||||
.unwrap();
|
||||
|
@ -102,7 +103,7 @@ async fn authentication_via_query_param_golden_path() {
|
|||
|
||||
service.logout().await;
|
||||
|
||||
let mut request = protocol::random();
|
||||
let mut request = protocol::random::<V8>();
|
||||
*request.uri_mut() = format!("{}?auth_token={}", request.uri(), authorization.token)
|
||||
.parse()
|
||||
.unwrap();
|
||||
|
|
|
@ -2,13 +2,14 @@ use http::StatusCode;
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::server::dto;
|
||||
use crate::server::test::protocol::{V7, V8};
|
||||
use crate::server::test::{add_trailing_slash, constants::*, protocol, ServiceType, TestService};
|
||||
use crate::test_name;
|
||||
|
||||
#[tokio::test]
|
||||
async fn browse_requires_auth() {
|
||||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
let request = protocol::browse(&PathBuf::new());
|
||||
let request = protocol::browse::<V8>(&PathBuf::new());
|
||||
let response = service.fetch(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
|
@ -21,7 +22,7 @@ async fn browse_root() {
|
|||
service.index().await;
|
||||
service.login().await;
|
||||
|
||||
let request = protocol::browse(&PathBuf::new());
|
||||
let request = protocol::browse::<V8>(&PathBuf::new());
|
||||
let response = service
|
||||
.fetch_json::<_, Vec<dto::CollectionFile>>(&request)
|
||||
.await;
|
||||
|
@ -39,7 +40,7 @@ async fn browse_directory() {
|
|||
service.login().await;
|
||||
|
||||
let path: PathBuf = [TEST_MOUNT_NAME, "Khemmis", "Hunted"].iter().collect();
|
||||
let request = protocol::browse(&path);
|
||||
let request = protocol::browse::<V8>(&path);
|
||||
let response = service
|
||||
.fetch_json::<_, Vec<dto::CollectionFile>>(&request)
|
||||
.await;
|
||||
|
@ -49,21 +50,43 @@ async fn browse_directory() {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn browse_bad_directory() {
|
||||
async fn browse_missing_directory() {
|
||||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
service.complete_initial_setup().await;
|
||||
service.login().await;
|
||||
|
||||
let path: PathBuf = ["not_my_collection"].iter().collect();
|
||||
let request = protocol::browse(&path);
|
||||
let request = protocol::browse::<V8>(&path);
|
||||
let response = service.fetch(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn browse_directory_api_v7() {
|
||||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
service.complete_initial_setup().await;
|
||||
service.login_admin().await;
|
||||
service.index().await;
|
||||
service.login().await;
|
||||
|
||||
let path: PathBuf = [TEST_MOUNT_NAME, "Khemmis", "Hunted"].iter().collect();
|
||||
let request = protocol::browse::<V7>(&path);
|
||||
let response = service
|
||||
.fetch_json::<_, Vec<dto::v7::CollectionFile>>(&request)
|
||||
.await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let entries = response.body();
|
||||
assert_eq!(entries.len(), 5);
|
||||
match &entries[0] {
|
||||
dto::v7::CollectionFile::Song(s) => assert_eq!(s.artist.as_deref(), Some("Khemmis")),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn flatten_requires_auth() {
|
||||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
let request = protocol::flatten(&PathBuf::new());
|
||||
let request = protocol::flatten::<V8>(&PathBuf::new());
|
||||
let response = service.fetch(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
|
@ -76,7 +99,7 @@ async fn flatten_root() {
|
|||
service.index().await;
|
||||
service.login().await;
|
||||
|
||||
let request = protocol::flatten(&PathBuf::new());
|
||||
let request = protocol::flatten::<V8>(&PathBuf::new());
|
||||
let response = service.fetch_json::<_, Vec<dto::Song>>(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let entries = response.body();
|
||||
|
@ -91,7 +114,7 @@ async fn flatten_directory() {
|
|||
service.index().await;
|
||||
service.login().await;
|
||||
|
||||
let request = protocol::flatten(Path::new(TEST_MOUNT_NAME));
|
||||
let request = protocol::flatten::<V8>(Path::new(TEST_MOUNT_NAME));
|
||||
let response = service.fetch_json::<_, Vec<dto::Song>>(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let entries = response.body();
|
||||
|
@ -99,21 +122,39 @@ async fn flatten_directory() {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn flatten_bad_directory() {
|
||||
async fn flatten_missing_directory() {
|
||||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
service.complete_initial_setup().await;
|
||||
service.login().await;
|
||||
|
||||
let path: PathBuf = ["not_my_collection"].iter().collect();
|
||||
let request = protocol::flatten(&path);
|
||||
let request = protocol::flatten::<V8>(&path);
|
||||
let response = service.fetch(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn flatten_directory_api_v7() {
|
||||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
service.complete_initial_setup().await;
|
||||
service.login_admin().await;
|
||||
service.index().await;
|
||||
service.login().await;
|
||||
|
||||
let path: PathBuf = [TEST_MOUNT_NAME, "Khemmis", "Hunted"].iter().collect();
|
||||
let request = protocol::flatten::<V7>(&path);
|
||||
let response = service.fetch_json::<_, Vec<dto::v7::Song>>(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let entries = response.body();
|
||||
assert_eq!(entries.len(), 5);
|
||||
|
||||
assert_eq!(entries[0].artist.as_deref(), Some("Khemmis"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn random_requires_auth() {
|
||||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
let request = protocol::random();
|
||||
let request = protocol::random::<V8>();
|
||||
let response = service.fetch(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
|
@ -126,7 +167,7 @@ async fn random_golden_path() {
|
|||
service.index().await;
|
||||
service.login().await;
|
||||
|
||||
let request = protocol::random();
|
||||
let request = protocol::random::<V8>();
|
||||
let response = service.fetch_json::<_, Vec<dto::Directory>>(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let entries = response.body();
|
||||
|
@ -141,7 +182,7 @@ async fn random_with_trailing_slash() {
|
|||
service.index().await;
|
||||
service.login().await;
|
||||
|
||||
let mut request = protocol::random();
|
||||
let mut request = protocol::random::<V8>();
|
||||
add_trailing_slash(&mut request);
|
||||
let response = service.fetch_json::<_, Vec<dto::Directory>>(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
|
@ -152,7 +193,7 @@ async fn random_with_trailing_slash() {
|
|||
#[tokio::test]
|
||||
async fn recent_requires_auth() {
|
||||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
let request = protocol::recent();
|
||||
let request = protocol::recent::<V8>();
|
||||
let response = service.fetch(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
|
@ -165,7 +206,7 @@ async fn recent_golden_path() {
|
|||
service.index().await;
|
||||
service.login().await;
|
||||
|
||||
let request = protocol::recent();
|
||||
let request = protocol::recent::<V8>();
|
||||
let response = service.fetch_json::<_, Vec<dto::Directory>>(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let entries = response.body();
|
||||
|
@ -180,7 +221,7 @@ async fn recent_with_trailing_slash() {
|
|||
service.index().await;
|
||||
service.login().await;
|
||||
|
||||
let mut request = protocol::recent();
|
||||
let mut request = protocol::recent::<V8>();
|
||||
add_trailing_slash(&mut request);
|
||||
let response = service.fetch_json::<_, Vec<dto::Directory>>(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
|
@ -191,7 +232,7 @@ async fn recent_with_trailing_slash() {
|
|||
#[tokio::test]
|
||||
async fn search_requires_auth() {
|
||||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
let request = protocol::search("");
|
||||
let request = protocol::search::<V8>("");
|
||||
let response = service.fetch(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
|
@ -202,7 +243,7 @@ async fn search_without_query() {
|
|||
service.complete_initial_setup().await;
|
||||
service.login().await;
|
||||
|
||||
let request = protocol::search("");
|
||||
let request = protocol::search::<V8>("");
|
||||
let response = service
|
||||
.fetch_json::<_, Vec<dto::CollectionFile>>(&request)
|
||||
.await;
|
||||
|
@ -217,7 +258,7 @@ async fn search_with_query() {
|
|||
service.index().await;
|
||||
service.login().await;
|
||||
|
||||
let request = protocol::search("door");
|
||||
let request = protocol::search::<V8>("door");
|
||||
let response = service
|
||||
.fetch_json::<_, Vec<dto::CollectionFile>>(&request)
|
||||
.await;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use http::StatusCode;
|
||||
|
||||
use crate::server::dto;
|
||||
use crate::server::test::protocol::V8;
|
||||
use crate::server::test::{constants::*, protocol, ServiceType, TestService};
|
||||
use crate::test_name;
|
||||
|
||||
|
@ -63,7 +64,7 @@ async fn save_playlist_large() {
|
|||
#[tokio::test]
|
||||
async fn get_playlist_requires_auth() {
|
||||
let mut service = ServiceType::new(&test_name!()).await;
|
||||
let request = protocol::read_playlist(TEST_PLAYLIST_NAME);
|
||||
let request = protocol::read_playlist::<V8>(TEST_PLAYLIST_NAME);
|
||||
let response = service.fetch(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
|
@ -81,7 +82,7 @@ async fn get_playlist_golden_path() {
|
|||
assert_eq!(response.status(), StatusCode::OK);
|
||||
}
|
||||
|
||||
let request = protocol::read_playlist(TEST_PLAYLIST_NAME);
|
||||
let request = protocol::read_playlist::<V8>(TEST_PLAYLIST_NAME);
|
||||
let response = service.fetch_json::<_, Vec<dto::Song>>(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
}
|
||||
|
@ -92,7 +93,7 @@ async fn get_playlist_bad_name_returns_not_found() {
|
|||
service.complete_initial_setup().await;
|
||||
service.login().await;
|
||||
|
||||
let request = protocol::read_playlist(TEST_PLAYLIST_NAME);
|
||||
let request = protocol::read_playlist::<V8>(TEST_PLAYLIST_NAME);
|
||||
let response = service.fetch(&request).await;
|
||||
assert_eq!(response.status(), StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,25 @@ use std::path::Path;
|
|||
use crate::server::dto;
|
||||
use crate::{app::user, server::dto::ThumbnailSize};
|
||||
|
||||
pub trait ProtocolVersion {
|
||||
fn header_value() -> i32;
|
||||
}
|
||||
|
||||
pub struct V7;
|
||||
pub struct V8;
|
||||
|
||||
impl ProtocolVersion for V7 {
|
||||
fn header_value() -> i32 {
|
||||
7
|
||||
}
|
||||
}
|
||||
|
||||
impl ProtocolVersion for V8 {
|
||||
fn header_value() -> i32 {
|
||||
8
|
||||
}
|
||||
}
|
||||
|
||||
pub fn web_index() -> Request<()> {
|
||||
Request::builder()
|
||||
.method(Method::GET)
|
||||
|
@ -145,45 +164,50 @@ pub fn trigger_index() -> Request<()> {
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn browse(path: &Path) -> Request<()> {
|
||||
pub fn browse<VERSION: ProtocolVersion>(path: &Path) -> Request<()> {
|
||||
let path = path.to_string_lossy();
|
||||
let endpoint = format!("/api/browse/{}", url_encode(path.as_ref()));
|
||||
Request::builder()
|
||||
.header("Accept-Version", VERSION::header_value())
|
||||
.method(Method::GET)
|
||||
.uri(&endpoint)
|
||||
.body(())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn flatten(path: &Path) -> Request<()> {
|
||||
pub fn flatten<VERSION: ProtocolVersion>(path: &Path) -> Request<()> {
|
||||
let path = path.to_string_lossy();
|
||||
let endpoint = format!("/api/flatten/{}", url_encode(path.as_ref()));
|
||||
Request::builder()
|
||||
.header("Accept-Version", VERSION::header_value())
|
||||
.method(Method::GET)
|
||||
.uri(&endpoint)
|
||||
.body(())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn random() -> Request<()> {
|
||||
pub fn random<VERSION: ProtocolVersion>() -> Request<()> {
|
||||
Request::builder()
|
||||
.header("Accept-Version", VERSION::header_value())
|
||||
.method(Method::GET)
|
||||
.uri("/api/random")
|
||||
.body(())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn recent() -> Request<()> {
|
||||
pub fn recent<VERSION: ProtocolVersion>() -> Request<()> {
|
||||
Request::builder()
|
||||
.header("Accept-Version", VERSION::header_value())
|
||||
.method(Method::GET)
|
||||
.uri("/api/recent")
|
||||
.body(())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn search(query: &str) -> Request<()> {
|
||||
pub fn search<VERSION: ProtocolVersion>(query: &str) -> Request<()> {
|
||||
let endpoint = format!("/api/search/{}", url_encode(query));
|
||||
Request::builder()
|
||||
.header("Accept-Version", VERSION::header_value())
|
||||
.method(Method::GET)
|
||||
.uri(&endpoint)
|
||||
.body(())
|
||||
|
@ -253,9 +277,10 @@ pub fn save_playlist(
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn read_playlist(name: &str) -> Request<()> {
|
||||
pub fn read_playlist<VERSION: ProtocolVersion>(name: &str) -> Request<()> {
|
||||
let endpoint = format!("/api/playlist/{}", url_encode(name));
|
||||
Request::builder()
|
||||
.header("Accept-Version", VERSION::header_value())
|
||||
.method(Method::GET)
|
||||
.uri(&endpoint)
|
||||
.body(())
|
||||
|
|
Loading…
Add table
Reference in a new issue