Link user id to song queue #159
Generated
+1
-1
@@ -752,7 +752,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "icarus"
|
||||
version = "0.1.92"
|
||||
version = "0.1.93"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"common-multipart-rfc7578",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "icarus"
|
||||
version = "0.1.92"
|
||||
version = "0.1.93"
|
||||
edition = "2024"
|
||||
rust-version = "1.88"
|
||||
|
||||
|
||||
+7
-8
@@ -1,14 +1,9 @@
|
||||
# Stage 1: Build the application
|
||||
# Use a specific Rust version for reproducibility. Choose one that matches your development environment.
|
||||
# Using slim variant for smaller base image
|
||||
FROM rust:1.88 as builder
|
||||
|
||||
# Set the working directory inside the container
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Install build dependencies if needed (e.g., for certain crates like sqlx with native TLS)
|
||||
# RUN apt-get update && apt-get install -y pkg-config libssl-dev
|
||||
|
||||
# Install build dependencies if needed (e.g., git for cloning)
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
pkg-config libssl3 \
|
||||
@@ -16,10 +11,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
openssh-client git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# << --- ADD HOST KEY HERE --- >>
|
||||
# Replace 'yourgithost.com' with the actual hostname (e.g., github.com)
|
||||
# Create .ssh/ directory for internal dependencies
|
||||
RUN mkdir -p -m 0700 ~/.ssh && \
|
||||
ssh-keyscan git.kundeng.us >> ~/.ssh/known_hosts
|
||||
echo "Host git.kundeng.us" >> ~/.ssh/config && \
|
||||
echo " User git" >> ~/.ssh/config && \
|
||||
chmod 600 ~/.ssh/config
|
||||
|
||||
# << --- ADD HOST KEY HERE --- >>
|
||||
RUN ssh-keyscan git.kundeng.us >> ~/.ssh/known_hosts
|
||||
|
||||
# Copy Cargo manifests
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
|
||||
@@ -6,7 +6,8 @@ CREATE TABLE IF NOT EXISTS "songQueue" (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
filename TEXT NOT NULL,
|
||||
status TEXT CHECK (status IN ('pending', 'ready', 'processing', 'done')),
|
||||
data BYTEA NULL
|
||||
data BYTEA NULL,
|
||||
user_id UUID NULL
|
||||
);
|
||||
|
||||
-- Table to store queued metadata
|
||||
|
||||
@@ -4,6 +4,7 @@ pub mod song;
|
||||
|
||||
pub mod endpoints {
|
||||
pub const QUEUESONG: &str = "/api/v2/song/queue";
|
||||
pub const QUEUESONGLINKUSERID: &str = "/api/v2/song/queue/link";
|
||||
pub const QUEUESONGDATA: &str = "/api/v2/song/queue/{id}";
|
||||
pub const QUEUESONGUPDATE: &str = "/api/v2/song/queue/{id}";
|
||||
pub const NEXTQUEUESONG: &str = "/api/v2/song/queue/next";
|
||||
@@ -17,3 +18,7 @@ pub mod endpoints {
|
||||
pub const CREATESONG: &str = "/api/v2/song";
|
||||
pub const CREATECOVERART: &str = "/api/v2/coverart";
|
||||
}
|
||||
|
||||
pub mod response {
|
||||
pub const SUCCESSFUL: &str = "SUCCESSFUL";
|
||||
}
|
||||
|
||||
+123
-30
@@ -84,6 +84,14 @@ pub mod request {
|
||||
pub song_queue_id: uuid::Uuid,
|
||||
}
|
||||
}
|
||||
|
||||
pub mod link_user_id {
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize)]
|
||||
pub struct Request {
|
||||
pub song_queue_id: uuid::Uuid,
|
||||
pub user_id: uuid::Uuid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod response {
|
||||
@@ -142,6 +150,14 @@ pub mod response {
|
||||
pub data: Vec<uuid::Uuid>,
|
||||
}
|
||||
}
|
||||
|
||||
pub mod link_user_id {
|
||||
#[derive(Debug, Default, serde::Deserialize, serde::Serialize)]
|
||||
pub struct Response {
|
||||
pub message: String,
|
||||
pub data: Vec<uuid::Uuid>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Might make a distinction between year and date in a song's tag at some point
|
||||
@@ -320,6 +336,7 @@ mod song_queue {
|
||||
pub id: uuid::Uuid,
|
||||
pub filename: String,
|
||||
pub status: String,
|
||||
pub user_id: uuid::Uuid,
|
||||
}
|
||||
|
||||
pub async fn insert(
|
||||
@@ -393,7 +410,7 @@ mod song_queue {
|
||||
FOR UPDATE SKIP LOCKED
|
||||
LIMIT 1
|
||||
)
|
||||
RETURNING id, filename, status;
|
||||
RETURNING id, filename, status, user_id;
|
||||
"#,
|
||||
)
|
||||
.bind(super::status::PROCESSING)
|
||||
@@ -405,20 +422,29 @@ mod song_queue {
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(row) => Ok(SongQueue {
|
||||
id: row
|
||||
.try_get("id")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
filename: row
|
||||
.try_get("filename")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
status: row
|
||||
.try_get("status")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
}),
|
||||
Ok(row) => {
|
||||
let user_id_result = row.try_get("user_id");
|
||||
let song_queue = SongQueue {
|
||||
id: row
|
||||
.try_get("id")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
filename: row
|
||||
.try_get("filename")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
status: row
|
||||
.try_get("status")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
user_id: match user_id_result {
|
||||
Ok(id) => id,
|
||||
Err(_) => uuid::Uuid::nil(),
|
||||
},
|
||||
};
|
||||
|
||||
Ok(song_queue)
|
||||
}
|
||||
Err(_err) => Err(sqlx::Error::RowNotFound),
|
||||
}
|
||||
}
|
||||
@@ -475,13 +501,40 @@ mod song_queue {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn link_user_id(
|
||||
pool: &sqlx::PgPool,
|
||||
id: &uuid::Uuid,
|
||||
user_id: &uuid::Uuid,
|
||||
) -> Result<uuid::Uuid, sqlx::Error> {
|
||||
let result = sqlx::query(
|
||||
r#"
|
||||
UPDATE "songQueue" SET user_id = $1 WHERE id = $2 RETURNING user_id;
|
||||
"#,
|
||||
)
|
||||
.bind(user_id)
|
||||
.bind(id)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
eprintln!("Error updating record {e}");
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(row) => Ok(row
|
||||
.try_get("user_id")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap()),
|
||||
Err(_) => Err(sqlx::Error::RowNotFound),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_song_queue(
|
||||
pool: &sqlx::PgPool,
|
||||
id: &uuid::Uuid,
|
||||
) -> Result<SongQueue, sqlx::Error> {
|
||||
let result = sqlx::query(
|
||||
r#"
|
||||
SELECT id, filename, status FROM "songQueue" WHERE id = $1
|
||||
SELECT id, filename, status, user_id FROM "songQueue" WHERE id = $1
|
||||
"#,
|
||||
)
|
||||
.bind(id)
|
||||
@@ -492,20 +545,29 @@ mod song_queue {
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(row) => Ok(SongQueue {
|
||||
id: row
|
||||
.try_get("id")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
filename: row
|
||||
.try_get("filename")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
status: row
|
||||
.try_get("status")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
}),
|
||||
Ok(row) => {
|
||||
let user_id_result = row.try_get("user_id");
|
||||
let song_queue = SongQueue {
|
||||
id: row
|
||||
.try_get("id")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
filename: row
|
||||
.try_get("filename")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
status: row
|
||||
.try_get("status")
|
||||
.map_err(|_e| sqlx::Error::RowNotFound)
|
||||
.unwrap(),
|
||||
user_id: match user_id_result {
|
||||
Ok(id) => id,
|
||||
Err(_) => uuid::Uuid::nil(),
|
||||
},
|
||||
};
|
||||
|
||||
Ok(song_queue)
|
||||
}
|
||||
Err(_err) => Err(sqlx::Error::RowNotFound),
|
||||
}
|
||||
}
|
||||
@@ -616,6 +678,37 @@ pub mod endpoint {
|
||||
(StatusCode::OK, Json(response))
|
||||
}
|
||||
|
||||
pub async fn link_user_id(
|
||||
axum::Extension(pool): axum::Extension<sqlx::PgPool>,
|
||||
axum::Json(payload): axum::Json<super::request::link_user_id::Request>,
|
||||
) -> (
|
||||
axum::http::StatusCode,
|
||||
axum::Json<super::response::link_user_id::Response>,
|
||||
) {
|
||||
let mut response = super::response::link_user_id::Response::default();
|
||||
|
||||
match super::song_queue::get_song_queue(&pool, &payload.song_queue_id).await {
|
||||
Ok(song_queue) => {
|
||||
match super::song_queue::link_user_id(&pool, &song_queue.id, &payload.user_id).await
|
||||
{
|
||||
Ok(user_id) => {
|
||||
response.message = String::from(crate::callers::response::SUCCESSFUL);
|
||||
response.data.push(user_id);
|
||||
(axum::http::StatusCode::OK, axum::Json(response))
|
||||
}
|
||||
Err(err) => {
|
||||
response.message = err.to_string();
|
||||
(axum::http::StatusCode::BAD_REQUEST, axum::Json(response))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
response.message = err.to_string();
|
||||
(axum::http::StatusCode::BAD_REQUEST, axum::Json(response))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn fetch_queue_song(
|
||||
axum::Extension(pool): axum::Extension<sqlx::PgPool>,
|
||||
) -> (
|
||||
|
||||
+369
-287
@@ -59,6 +59,10 @@ pub mod init {
|
||||
crate::callers::endpoints::QUEUESONG,
|
||||
patch(crate::callers::song::endpoint::update_song_queue_status),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUESONGLINKUSERID,
|
||||
patch(crate::callers::song::endpoint::link_user_id),
|
||||
)
|
||||
.route(
|
||||
crate::callers::endpoints::QUEUESONGDATA,
|
||||
get(crate::callers::song::endpoint::download_flac),
|
||||
@@ -237,6 +241,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Put the *_req() functions in their own module
|
||||
async fn song_queue_req(
|
||||
app: &axum::Router,
|
||||
) -> Result<axum::response::Response, std::convert::Infallible> {
|
||||
@@ -256,6 +261,26 @@ mod tests {
|
||||
app.clone().oneshot(req).await
|
||||
}
|
||||
|
||||
async fn song_queue_link_req(
|
||||
app: &axum::Router,
|
||||
song_queue_id: &uuid::Uuid,
|
||||
user_id: &uuid::Uuid,
|
||||
) -> Result<axum::response::Response, std::convert::Infallible> {
|
||||
let payload = serde_json::json!({
|
||||
"song_queue_id": song_queue_id,
|
||||
"user_id": user_id
|
||||
});
|
||||
|
||||
let req = axum::http::Request::builder()
|
||||
.method(axum::http::Method::PATCH)
|
||||
.uri(crate::callers::endpoints::QUEUESONGLINKUSERID)
|
||||
.header(axum::http::header::CONTENT_TYPE, "application/json")
|
||||
.body(axum::body::Body::from(payload.to_string()))
|
||||
.unwrap();
|
||||
|
||||
app.clone().oneshot(req).await
|
||||
}
|
||||
|
||||
async fn fetch_queue_req(
|
||||
app: &axum::Router,
|
||||
) -> Result<axum::response::Response, std::convert::Infallible> {
|
||||
@@ -380,6 +405,7 @@ mod tests {
|
||||
async fn create_song_req(
|
||||
app: &axum::Router,
|
||||
song_queue_id: &uuid::Uuid,
|
||||
user_id: &uuid::Uuid,
|
||||
) -> Result<axum::response::Response, std::convert::Infallible> {
|
||||
let payload = serde_json::json!({
|
||||
"title": "Power of Soul",
|
||||
@@ -394,7 +420,7 @@ mod tests {
|
||||
"disc_count": 1,
|
||||
"duration": 330,
|
||||
"audio_type": "flac",
|
||||
"user_id": "d6e159c1-9648-4c85-81e5-52f502ff53e4",
|
||||
"user_id": user_id,
|
||||
"song_queue_id": song_queue_id
|
||||
});
|
||||
|
||||
@@ -451,7 +477,7 @@ mod tests {
|
||||
// Flow for queueing song
|
||||
pub async fn queue_song_flow(
|
||||
app: &axum::Router,
|
||||
) -> Result<axum::response::Response, std::convert::Infallible> {
|
||||
) -> Result<(axum::response::Response, uuid::Uuid), std::convert::Infallible> {
|
||||
match super::song_queue_req(&app).await {
|
||||
Ok(response) => {
|
||||
let resp =
|
||||
@@ -462,21 +488,40 @@ mod tests {
|
||||
let song_queue_id = resp.data[0];
|
||||
assert_eq!(false, song_queue_id.is_nil(), "Should not be empty");
|
||||
|
||||
match super::queue_metadata_req(&app, &resp.data[0]).await {
|
||||
let user_id = uuid::Uuid::new_v4();
|
||||
|
||||
// match super::get_resp_data::<crate::callers::song::response::link_user_id::Response>(response).await {
|
||||
|
||||
match super::song_queue_link_req(&app, &song_queue_id, &user_id).await {
|
||||
Ok(response) => {
|
||||
let resp = super::get_resp_data::<
|
||||
crate::callers::song::response::Response,
|
||||
crate::callers::song::response::link_user_id::Response,
|
||||
>(response)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
assert_eq!(
|
||||
false,
|
||||
resp.data.is_empty(),
|
||||
"The response should not be empty"
|
||||
);
|
||||
|
||||
let id = resp.data[0];
|
||||
match super::queue_metadata_req(&app, &song_queue_id).await {
|
||||
Ok(response) => {
|
||||
let resp = super::get_resp_data::<
|
||||
crate::callers::song::response::Response,
|
||||
>(response)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
|
||||
match super::fetch_metadata_queue_req(&app, &id).await {
|
||||
Ok(response) => Ok(response),
|
||||
Err(err) => Err(err),
|
||||
let id = resp.data[0];
|
||||
|
||||
match super::fetch_metadata_queue_req(&app, &id).await {
|
||||
Ok(response) => Ok((response, user_id)),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
@@ -533,7 +578,7 @@ mod tests {
|
||||
app: &axum::Router,
|
||||
) -> Result<(axum::response::Response, uuid::Uuid), std::convert::Infallible> {
|
||||
match queue_song_flow(&app).await {
|
||||
Ok(song_response) => {
|
||||
Ok((song_response, user_id)) => {
|
||||
let resp = super::get_resp_data::<
|
||||
crate::callers::metadata::response::fetch_metadata::Response,
|
||||
>(song_response)
|
||||
@@ -541,7 +586,7 @@ mod tests {
|
||||
assert_eq!(false, resp.data.is_empty(), "Data should not be empty");
|
||||
let song_queue_id = resp.data[0].song_queue_id;
|
||||
|
||||
match super::create_song_req(&app, &song_queue_id).await {
|
||||
match super::create_song_req(&app, &song_queue_id, &user_id).await {
|
||||
Ok(response) => {
|
||||
let resp = super::get_resp_data::<
|
||||
crate::callers::song::response::create_metadata::Response,
|
||||
@@ -586,12 +631,14 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Put this in a util module
|
||||
pub async fn resp_to_bytes(
|
||||
response: axum::response::Response,
|
||||
) -> Result<axum::body::Bytes, axum::Error> {
|
||||
axum::body::to_bytes(response.into_body(), usize::MAX).await
|
||||
}
|
||||
|
||||
// TODO: Put this in a util module
|
||||
pub async fn get_resp_data<Data>(response: axum::response::Response) -> Data
|
||||
where
|
||||
Data: for<'a> serde::Deserialize<'a>,
|
||||
@@ -600,6 +647,7 @@ mod tests {
|
||||
serde_json::from_slice(&body).unwrap()
|
||||
}
|
||||
|
||||
// TODO: Change the name of the function to be more expressive and put into it's own module
|
||||
pub mod payload_data {
|
||||
pub async fn queue_metadata_payload_data(song_queue_id: &uuid::Uuid) -> serde_json::Value {
|
||||
serde_json::json!(
|
||||
@@ -655,69 +703,225 @@ mod tests {
|
||||
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
}
|
||||
|
||||
mod special_area {
|
||||
#[tokio::test]
|
||||
async fn test_song_queue_link_user_id() {
|
||||
let tm_pool = db_mgr::get_pool().await.unwrap();
|
||||
let db_name = db_mgr::generate_db_name().await;
|
||||
|
||||
use super::*;
|
||||
match db_mgr::create_database(&tm_pool, &db_name).await {
|
||||
Ok(_) => {
|
||||
println!("Success");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
use std::io::Write;
|
||||
let pool = db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||
db::migrations(&pool).await;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_song_fetch_queue_item() {
|
||||
let tm_pool = db_mgr::get_pool().await.unwrap();
|
||||
let db_name = db_mgr::generate_db_name().await;
|
||||
let app = init::app(pool).await;
|
||||
|
||||
match db_mgr::create_database(&tm_pool, &db_name).await {
|
||||
Ok(_) => {
|
||||
println!("Success");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
match song_queue_req(&app).await {
|
||||
Ok(response) => {
|
||||
let resp =
|
||||
get_resp_data::<crate::callers::song::response::Response>(response).await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
assert_eq!(false, resp.data[0].is_nil(), "Should not be empty");
|
||||
|
||||
let song_queue_id = &resp.data[0];
|
||||
let user_id = uuid::Uuid::new_v4();
|
||||
println!("User Id: {user_id:?}");
|
||||
|
||||
match song_queue_link_req(&app, &song_queue_id, &user_id).await {
|
||||
Ok(response) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::song::response::link_user_id::Response,
|
||||
>(response)
|
||||
.await;
|
||||
let collected_user_id = &resp.data[0];
|
||||
|
||||
assert!(
|
||||
!collected_user_id.is_nil(),
|
||||
"Collected user id should not be nil {collected_user_id:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
user_id, *collected_user_id,
|
||||
"User Id is different. First {user_id:?} Second {collected_user_id:?}"
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(
|
||||
false,
|
||||
"Error: {err:?} songQueue Id {song_queue_id:?} user id {user_id:?}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
};
|
||||
|
||||
let pool = db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||
db::migrations(&pool).await;
|
||||
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
}
|
||||
|
||||
let app = init::app(pool).await;
|
||||
#[tokio::test]
|
||||
async fn test_song_fetch_queue_item() {
|
||||
let tm_pool = db_mgr::get_pool().await.unwrap();
|
||||
let db_name = db_mgr::generate_db_name().await;
|
||||
|
||||
match sequence_flow::queue_song_and_coverart_flow(&app).await {
|
||||
Ok((resp_one, song_queue_id)) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::coverart::response::fetch_coverart_no_data::Response,
|
||||
>(resp_one)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
match db_mgr::create_database(&tm_pool, &db_name).await {
|
||||
Ok(_) => {
|
||||
println!("Success");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
let _resp_coverart_queue_id = resp.data[0].id;
|
||||
let pool = db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||
db::migrations(&pool).await;
|
||||
|
||||
let old = crate::callers::song::status::PENDING;
|
||||
let target_status = crate::callers::song::status::READY;
|
||||
let app = init::app(pool).await;
|
||||
|
||||
match update_song_queue_status_req(&app, &song_queue_id).await {
|
||||
Ok(response) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::song::response::update_status::Response,
|
||||
>(response)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
let changed_status = &resp.data[0];
|
||||
match sequence_flow::queue_song_and_coverart_flow(&app).await {
|
||||
Ok((resp_one, song_queue_id)) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::coverart::response::fetch_coverart_no_data::Response,
|
||||
>(resp_one)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
|
||||
assert_eq!(
|
||||
*old, changed_status.old_status,
|
||||
"Old status does not match"
|
||||
);
|
||||
assert_eq!(
|
||||
target_status, changed_status.new_status,
|
||||
"New status does not match"
|
||||
let _resp_coverart_queue_id = resp.data[0].id;
|
||||
|
||||
let old = crate::callers::song::status::PENDING;
|
||||
let target_status = crate::callers::song::status::READY;
|
||||
|
||||
match update_song_queue_status_req(&app, &song_queue_id).await {
|
||||
Ok(response) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::song::response::update_status::Response,
|
||||
>(response)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
let changed_status = &resp.data[0];
|
||||
|
||||
assert_eq!(*old, changed_status.old_status, "Old status does not match");
|
||||
assert_eq!(
|
||||
target_status, changed_status.new_status,
|
||||
"New status does not match"
|
||||
);
|
||||
|
||||
match fetch_queue_req(&app).await {
|
||||
Ok(response) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::song::response::fetch_queue_song::Response,
|
||||
>(response)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
};
|
||||
|
||||
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_update_song_from_queue() {
|
||||
let tm_pool = db_mgr::get_pool().await.unwrap();
|
||||
let db_name = db_mgr::generate_db_name().await;
|
||||
|
||||
match db_mgr::create_database(&tm_pool, &db_name).await {
|
||||
Ok(_) => {
|
||||
println!("Success");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
let pool = db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||
db::migrations(&pool).await;
|
||||
|
||||
let app = init::app(pool).await;
|
||||
|
||||
// Send request
|
||||
match song_queue_req(&app).await {
|
||||
Ok(response) => {
|
||||
let resp =
|
||||
get_resp_data::<crate::callers::song::response::Response>(response).await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
assert_eq!(false, resp.data[0].is_nil(), "Should not be empty");
|
||||
|
||||
let id = &resp.data[0];
|
||||
|
||||
match fetch_queue_data_req(&app, &id).await {
|
||||
Ok(response) => match resp_to_bytes(response).await {
|
||||
Ok(bytes) => {
|
||||
assert_eq!(false, bytes.is_empty(), "Queued data should not be empty");
|
||||
|
||||
let temp_file =
|
||||
tempfile::tempdir().expect("Could not create test directory");
|
||||
let test_dir = String::from(temp_file.path().to_str().unwrap());
|
||||
let new_file = format!("{}/new_file.flac", test_dir);
|
||||
|
||||
let mut file = std::fs::File::create(&new_file).unwrap();
|
||||
file.write_all(&bytes).unwrap();
|
||||
|
||||
let mut form = MultipartForm::default();
|
||||
let _ = form.add_file("flac", new_file);
|
||||
|
||||
// Create request
|
||||
let content_type = form.content_type();
|
||||
let body = MultipartBody::from(form);
|
||||
|
||||
let raw_uri = String::from(crate::callers::endpoints::QUEUESONGUPDATE);
|
||||
let end_index = raw_uri.len() - 5;
|
||||
|
||||
let uri = format!(
|
||||
"{}/{}",
|
||||
(&raw_uri[..end_index]).to_string(),
|
||||
id.to_string()
|
||||
);
|
||||
|
||||
match fetch_queue_req(&app).await {
|
||||
match app
|
||||
.clone()
|
||||
.oneshot(
|
||||
axum::http::Request::builder()
|
||||
.method(axum::http::Method::PATCH)
|
||||
.uri(uri)
|
||||
.header(axum::http::header::CONTENT_TYPE, content_type)
|
||||
.body(axum::body::Body::from_stream(body))
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(response) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::song::response::fetch_queue_song::Response,
|
||||
crate::callers::song::response::update_song_queue::Response,
|
||||
>(response)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
|
||||
let updated_song_queued_id = resp.data[0];
|
||||
assert_eq!(
|
||||
updated_song_queued_id, *id,
|
||||
"Song queue Id should match, but they don't. {:?} {:?}",
|
||||
updated_song_queued_id, id
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
@@ -727,247 +931,125 @@ mod tests {
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
};
|
||||
|
||||
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_song_fetch_queue_data() {
|
||||
let tm_pool = db_mgr::get_pool().await.unwrap();
|
||||
let db_name = db_mgr::generate_db_name().await;
|
||||
|
||||
match db_mgr::create_database(&tm_pool, &db_name).await {
|
||||
Ok(_) => {
|
||||
println!("Success");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_update_song_from_queue() {
|
||||
let tm_pool = db_mgr::get_pool().await.unwrap();
|
||||
let db_name = db_mgr::generate_db_name().await;
|
||||
let pool = db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||
db::migrations(&pool).await;
|
||||
|
||||
match db_mgr::create_database(&tm_pool, &db_name).await {
|
||||
Ok(_) => {
|
||||
println!("Success");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
let app = init::app(pool).await;
|
||||
|
||||
let pool = db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||
db::migrations(&pool).await;
|
||||
// Send request
|
||||
match song_queue_req(&app).await {
|
||||
Ok(response) => {
|
||||
let resp =
|
||||
get_resp_data::<crate::callers::song::response::Response>(response).await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
assert_eq!(false, resp.data[0].is_nil(), "Should not be empty");
|
||||
let id = resp.data[0];
|
||||
|
||||
let app = init::app(pool).await;
|
||||
|
||||
// Send request
|
||||
match song_queue_req(&app).await {
|
||||
Ok(response) => {
|
||||
let resp =
|
||||
get_resp_data::<crate::callers::song::response::Response>(response).await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
assert_eq!(false, resp.data[0].is_nil(), "Should not be empty");
|
||||
|
||||
let id = &resp.data[0];
|
||||
|
||||
match fetch_queue_data_req(&app, &id).await {
|
||||
Ok(response) => match resp_to_bytes(response).await {
|
||||
Ok(bytes) => {
|
||||
assert_eq!(
|
||||
false,
|
||||
bytes.is_empty(),
|
||||
"Queued data should not be empty"
|
||||
);
|
||||
|
||||
let temp_file =
|
||||
tempfile::tempdir().expect("Could not create test directory");
|
||||
let test_dir = String::from(temp_file.path().to_str().unwrap());
|
||||
let new_file = format!("{}/new_file.flac", test_dir);
|
||||
|
||||
let mut file = std::fs::File::create(&new_file).unwrap();
|
||||
file.write_all(&bytes).unwrap();
|
||||
|
||||
let mut form = MultipartForm::default();
|
||||
let _ = form.add_file("flac", new_file);
|
||||
|
||||
// Create request
|
||||
let content_type = form.content_type();
|
||||
let body = MultipartBody::from(form);
|
||||
|
||||
let raw_uri =
|
||||
String::from(crate::callers::endpoints::QUEUESONGUPDATE);
|
||||
let end_index = raw_uri.len() - 5;
|
||||
|
||||
let uri = format!(
|
||||
"{}/{}",
|
||||
(&raw_uri[..end_index]).to_string(),
|
||||
id.to_string()
|
||||
);
|
||||
|
||||
match app
|
||||
.clone()
|
||||
.oneshot(
|
||||
axum::http::Request::builder()
|
||||
.method(axum::http::Method::PATCH)
|
||||
.uri(uri)
|
||||
.header(axum::http::header::CONTENT_TYPE, content_type)
|
||||
.body(axum::body::Body::from_stream(body))
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(response) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::song::response::update_song_queue::Response,
|
||||
>(response)
|
||||
.await;
|
||||
assert_eq!(
|
||||
false,
|
||||
resp.data.is_empty(),
|
||||
"Should not be empty"
|
||||
);
|
||||
|
||||
let updated_song_queued_id = resp.data[0];
|
||||
assert_eq!(
|
||||
updated_song_queued_id, *id,
|
||||
"Song queue Id should match, but they don't. {:?} {:?}",
|
||||
updated_song_queued_id, id
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
};
|
||||
|
||||
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_song_fetch_queue_data() {
|
||||
let tm_pool = db_mgr::get_pool().await.unwrap();
|
||||
let db_name = db_mgr::generate_db_name().await;
|
||||
|
||||
match db_mgr::create_database(&tm_pool, &db_name).await {
|
||||
Ok(_) => {
|
||||
println!("Success");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
let pool = db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||
db::migrations(&pool).await;
|
||||
|
||||
let app = init::app(pool).await;
|
||||
|
||||
// Send request
|
||||
match song_queue_req(&app).await {
|
||||
Ok(response) => {
|
||||
let resp =
|
||||
get_resp_data::<crate::callers::song::response::Response>(response).await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
assert_eq!(false, resp.data[0].is_nil(), "Should not be empty");
|
||||
let id = resp.data[0];
|
||||
|
||||
match fetch_queue_data_req(&app, &id).await {
|
||||
Ok(response) => match resp_to_bytes(response).await {
|
||||
Ok(bytes) => {
|
||||
assert_eq!(
|
||||
false,
|
||||
bytes.is_empty(),
|
||||
"Queued data should not be empty"
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
};
|
||||
|
||||
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_song_queue_update_status() {
|
||||
let tm_pool = db_mgr::get_pool().await.unwrap();
|
||||
let db_name = db_mgr::generate_db_name().await;
|
||||
|
||||
match db_mgr::create_database(&tm_pool, &db_name).await {
|
||||
Ok(_) => {
|
||||
println!("Success");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
let pool = db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||
db::migrations(&pool).await;
|
||||
|
||||
let app = init::app(pool).await;
|
||||
|
||||
match sequence_flow::queue_song_and_coverart_flow(&app).await {
|
||||
Ok((resp_one, song_queue_id)) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::coverart::response::fetch_coverart_no_data::Response,
|
||||
>(resp_one)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
|
||||
let _resp_coverart_queue_id = resp.data[0].id;
|
||||
|
||||
let old = crate::callers::song::status::PENDING;
|
||||
let done = crate::callers::song::status::READY;
|
||||
|
||||
match update_song_queue_status_req(&app, &song_queue_id).await {
|
||||
Ok(response) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::song::response::update_status::Response,
|
||||
>(response)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
let changed_status = &resp.data[0];
|
||||
|
||||
assert_eq!(
|
||||
*old, changed_status.old_status,
|
||||
"Old status does not match"
|
||||
);
|
||||
assert_eq!(
|
||||
done, changed_status.new_status,
|
||||
"New status does not match"
|
||||
);
|
||||
match fetch_queue_data_req(&app, &id).await {
|
||||
Ok(response) => match resp_to_bytes(response).await {
|
||||
Ok(bytes) => {
|
||||
assert_eq!(false, bytes.is_empty(), "Queued data should not be empty");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
};
|
||||
|
||||
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_song_queue_update_status() {
|
||||
let tm_pool = db_mgr::get_pool().await.unwrap();
|
||||
let db_name = db_mgr::generate_db_name().await;
|
||||
|
||||
match db_mgr::create_database(&tm_pool, &db_name).await {
|
||||
Ok(_) => {
|
||||
println!("Success");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
let pool = db_mgr::connect_to_db(&db_name).await.unwrap();
|
||||
db::migrations(&pool).await;
|
||||
|
||||
let app = init::app(pool).await;
|
||||
|
||||
match sequence_flow::queue_song_and_coverart_flow(&app).await {
|
||||
Ok((resp_one, song_queue_id)) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::coverart::response::fetch_coverart_no_data::Response,
|
||||
>(resp_one)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
|
||||
let _resp_coverart_queue_id = resp.data[0].id;
|
||||
|
||||
let old = crate::callers::song::status::PENDING;
|
||||
let done = crate::callers::song::status::READY;
|
||||
|
||||
match update_song_queue_status_req(&app, &song_queue_id).await {
|
||||
Ok(response) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::song::response::update_status::Response,
|
||||
>(response)
|
||||
.await;
|
||||
assert_eq!(false, resp.data.is_empty(), "Should not be empty");
|
||||
let changed_status = &resp.data[0];
|
||||
|
||||
assert_eq!(*old, changed_status.old_status, "Old status does not match");
|
||||
assert_eq!(done, changed_status.new_status, "New status does not match");
|
||||
}
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
Err(err) => {
|
||||
assert!(false, "Error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
let _ = db_mgr::drop_database(&tm_pool, &db_name).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -1038,7 +1120,7 @@ mod tests {
|
||||
|
||||
// Send request
|
||||
match sequence_flow::queue_song_flow(&app).await {
|
||||
Ok(response) => {
|
||||
Ok((response, _user_id)) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::metadata::response::fetch_metadata::Response,
|
||||
>(response)
|
||||
@@ -1354,7 +1436,7 @@ mod tests {
|
||||
|
||||
// Send request
|
||||
match sequence_flow::queue_song_flow(&app).await {
|
||||
Ok(response) => {
|
||||
Ok((response, user_id)) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::metadata::response::fetch_metadata::Response,
|
||||
>(response)
|
||||
@@ -1362,7 +1444,7 @@ mod tests {
|
||||
assert_eq!(false, resp.data.is_empty(), "Data should not be empty");
|
||||
let song_q_id = resp.data[0].song_queue_id;
|
||||
|
||||
match create_song_req(&app, &song_q_id).await {
|
||||
match create_song_req(&app, &song_q_id, &user_id).await {
|
||||
Ok(response) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::song::response::create_metadata::Response,
|
||||
@@ -1417,7 +1499,7 @@ mod tests {
|
||||
|
||||
// Send request
|
||||
match sequence_flow::queue_song_flow(&app).await {
|
||||
Ok(response) => {
|
||||
Ok((response, user_id)) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::metadata::response::fetch_metadata::Response,
|
||||
>(response)
|
||||
@@ -1425,7 +1507,7 @@ mod tests {
|
||||
assert_eq!(false, resp.data.is_empty(), "Data should not be empty");
|
||||
let song_queue_id = resp.data[0].song_queue_id;
|
||||
|
||||
match create_song_req(&app, &song_queue_id).await {
|
||||
match create_song_req(&app, &song_queue_id, &user_id).await {
|
||||
Ok(response) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::song::response::create_metadata::Response,
|
||||
@@ -1512,7 +1594,7 @@ mod tests {
|
||||
|
||||
// Send request
|
||||
match sequence_flow::queue_song_flow(&app).await {
|
||||
Ok(response) => {
|
||||
Ok((response, user_id)) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::metadata::response::fetch_metadata::Response,
|
||||
>(response)
|
||||
@@ -1520,7 +1602,7 @@ mod tests {
|
||||
assert_eq!(false, resp.data.is_empty(), "Data should not be empty");
|
||||
let song_q_id = resp.data[0].song_queue_id;
|
||||
|
||||
match create_song_req(&app, &song_q_id).await {
|
||||
match create_song_req(&app, &song_q_id, &user_id).await {
|
||||
Ok(response) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::song::response::create_metadata::Response,
|
||||
@@ -1617,7 +1699,7 @@ mod tests {
|
||||
let app = init::app(pool).await;
|
||||
|
||||
match sequence_flow::queue_song_flow(&app).await {
|
||||
Ok(response) => {
|
||||
Ok((response, user_id)) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::metadata::response::fetch_metadata::Response,
|
||||
>(response)
|
||||
@@ -1625,7 +1707,7 @@ mod tests {
|
||||
assert_eq!(false, resp.data.is_empty(), "Data should not be empty");
|
||||
let song_queue_id = resp.data[0].song_queue_id;
|
||||
|
||||
match create_song_req(&app, &song_queue_id).await {
|
||||
match create_song_req(&app, &song_queue_id, &user_id).await {
|
||||
Ok(response) => {
|
||||
let resp = get_resp_data::<
|
||||
crate::callers::song::response::create_metadata::Response,
|
||||
|
||||
Reference in New Issue
Block a user