- Implement unit tests for PreviewClipRequest/PreviewStatusRequest serialization and deserialization. - Add tests for PreviewDao (insert, update, batch retrieval, and status-based queries). - Extend Actix-web integration tests for `/video/preview/status` endpoint scenarios. - Introduce in-memory TestPreviewDao for mock database interactions. - Update README with new config parameters for preview clips.
171 lines
4.5 KiB
Rust
171 lines
4.5 KiB
Rust
use actix_web::{
|
|
HttpResponse,
|
|
body::{BoxBody, MessageBody},
|
|
};
|
|
|
|
use crate::database::models::{User, VideoPreviewClip};
|
|
use crate::database::{DbError, DbErrorKind, PreviewDao, UserDao};
|
|
use std::cell::RefCell;
|
|
use std::collections::HashMap;
|
|
use std::option::Option;
|
|
use std::sync::Mutex as StdMutex;
|
|
|
|
pub struct TestUserDao {
|
|
pub user_map: RefCell<Vec<User>>,
|
|
}
|
|
|
|
impl TestUserDao {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
user_map: RefCell::new(Vec::new()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl UserDao for TestUserDao {
|
|
fn create_user(&mut self, username: &str, password: &str) -> Option<User> {
|
|
let u = User {
|
|
id: (self.user_map.borrow().len() + 1) as i32,
|
|
username: username.to_string(),
|
|
password: password.to_string(),
|
|
};
|
|
|
|
self.user_map.borrow_mut().push(u.clone());
|
|
|
|
Some(u)
|
|
}
|
|
|
|
fn get_user(&mut self, user: &str, pass: &str) -> Option<User> {
|
|
match self
|
|
.user_map
|
|
.borrow()
|
|
.iter()
|
|
.find(|&u| u.username == user && u.password == pass)
|
|
{
|
|
Some(u) => {
|
|
let copy = (*u).clone();
|
|
Some(copy)
|
|
}
|
|
None => None,
|
|
}
|
|
}
|
|
|
|
fn user_exists(&mut self, user: &str) -> bool {
|
|
self.user_map.borrow().iter().any(|u| u.username == user)
|
|
}
|
|
}
|
|
|
|
pub trait BodyReader {
|
|
fn read_to_str(self) -> String;
|
|
}
|
|
|
|
impl BodyReader for HttpResponse<BoxBody> {
|
|
fn read_to_str(self) -> String {
|
|
let body = self.into_body().try_into_bytes().unwrap();
|
|
std::str::from_utf8(&body).unwrap().to_string()
|
|
}
|
|
}
|
|
|
|
pub struct TestPreviewDao {
|
|
pub clips: StdMutex<HashMap<String, VideoPreviewClip>>,
|
|
next_id: StdMutex<i32>,
|
|
}
|
|
|
|
impl TestPreviewDao {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
clips: StdMutex::new(HashMap::new()),
|
|
next_id: StdMutex::new(1),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PreviewDao for TestPreviewDao {
|
|
fn insert_preview(
|
|
&mut self,
|
|
_context: &opentelemetry::Context,
|
|
file_path_val: &str,
|
|
status_val: &str,
|
|
) -> Result<(), DbError> {
|
|
let mut clips = self.clips.lock().unwrap();
|
|
// insert_or_ignore semantics: skip if key already exists
|
|
if clips.contains_key(file_path_val) {
|
|
return Ok(());
|
|
}
|
|
let mut id = self.next_id.lock().unwrap();
|
|
let now = chrono::Utc::now().to_rfc3339();
|
|
clips.insert(
|
|
file_path_val.to_string(),
|
|
VideoPreviewClip {
|
|
id: *id,
|
|
file_path: file_path_val.to_string(),
|
|
status: status_val.to_string(),
|
|
duration_seconds: None,
|
|
file_size_bytes: None,
|
|
error_message: None,
|
|
created_at: now.clone(),
|
|
updated_at: now,
|
|
},
|
|
);
|
|
*id += 1;
|
|
Ok(())
|
|
}
|
|
|
|
fn update_status(
|
|
&mut self,
|
|
_context: &opentelemetry::Context,
|
|
file_path_val: &str,
|
|
status_val: &str,
|
|
duration: Option<f32>,
|
|
size: Option<i32>,
|
|
error: Option<&str>,
|
|
) -> Result<(), DbError> {
|
|
let mut clips = self.clips.lock().unwrap();
|
|
if let Some(clip) = clips.get_mut(file_path_val) {
|
|
clip.status = status_val.to_string();
|
|
clip.duration_seconds = duration;
|
|
clip.file_size_bytes = size;
|
|
clip.error_message = error.map(|s| s.to_string());
|
|
clip.updated_at = chrono::Utc::now().to_rfc3339();
|
|
Ok(())
|
|
} else {
|
|
Err(DbError {
|
|
kind: DbErrorKind::UpdateError,
|
|
})
|
|
}
|
|
}
|
|
|
|
fn get_preview(
|
|
&mut self,
|
|
_context: &opentelemetry::Context,
|
|
file_path_val: &str,
|
|
) -> Result<Option<VideoPreviewClip>, DbError> {
|
|
Ok(self.clips.lock().unwrap().get(file_path_val).cloned())
|
|
}
|
|
|
|
fn get_previews_batch(
|
|
&mut self,
|
|
_context: &opentelemetry::Context,
|
|
file_paths: &[String],
|
|
) -> Result<Vec<VideoPreviewClip>, DbError> {
|
|
let clips = self.clips.lock().unwrap();
|
|
Ok(file_paths
|
|
.iter()
|
|
.filter_map(|p| clips.get(p).cloned())
|
|
.collect())
|
|
}
|
|
|
|
fn get_by_status(
|
|
&mut self,
|
|
_context: &opentelemetry::Context,
|
|
status_val: &str,
|
|
) -> Result<Vec<VideoPreviewClip>, DbError> {
|
|
let clips = self.clips.lock().unwrap();
|
|
Ok(clips
|
|
.values()
|
|
.filter(|c| c.status == status_val)
|
|
.cloned()
|
|
.collect())
|
|
}
|
|
}
|