mirror of https://github.com/ChillFish8/lust.git
Add testing and automatic content type detection
This commit is contained in:
parent
43ff1229eb
commit
114137b7b0
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
@ -19,6 +19,7 @@ pub fn config() -> &'static RuntimeConfig {
|
|||
#[cfg(test)]
|
||||
pub fn init_test(data: &str) -> Result<()> {
|
||||
let cfg: RuntimeConfig = serde_yaml::from_str(data)?;
|
||||
dbg!(&cfg);
|
||||
let _ = CONFIG.set(cfg);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -84,7 +85,7 @@ impl RuntimeConfig {
|
|||
self
|
||||
.max_upload_size
|
||||
.map(|limit| size <= limit)
|
||||
.unwrap_or(false)
|
||||
.unwrap_or(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,6 +199,16 @@ impl ImageKind {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_guessed_format(fmt: image::ImageFormat) -> Option<Self> {
|
||||
match fmt {
|
||||
image::ImageFormat::Png => Some(Self::Png),
|
||||
image::ImageFormat::Jpeg => Some(Self::Jpeg),
|
||||
image::ImageFormat::Gif => Some(Self::Gif),
|
||||
image::ImageFormat::WebP => Some(Self::Webp),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_content_type(&self) -> String {
|
||||
format!("image/{}", self.as_file_extension())
|
||||
}
|
||||
|
|
|
@ -16,10 +16,6 @@ pub fn init_buckets(buckets: hashbrown::HashMap<u32, BucketController>) {
|
|||
let _ = BUCKETS.set(buckets);
|
||||
}
|
||||
|
||||
pub fn buckets() -> &'static hashbrown::HashMap<u32, BucketController> {
|
||||
BUCKETS.get_or_init(hashbrown::HashMap::new)
|
||||
}
|
||||
|
||||
pub fn get_bucket_by_id(bucket_id: u32) -> Option<&'static BucketController> {
|
||||
BUCKETS.get_or_init(hashbrown::HashMap::new).get(&bucket_id)
|
||||
}
|
||||
|
|
|
@ -29,6 +29,11 @@ pub enum UploadResponse {
|
|||
#[oai(status = 404)]
|
||||
NotFound,
|
||||
|
||||
/// The image format was incorrect or the system was
|
||||
/// unable to guess the format of the image.
|
||||
#[oai(status = 400)]
|
||||
InvalidImageFormat,
|
||||
|
||||
/// The upload exceeds the configured maximum file size.
|
||||
#[oai(status = 413)]
|
||||
TooBig,
|
||||
|
@ -127,7 +132,7 @@ impl LustApi {
|
|||
|
||||
/// The total size of the image in bytes.
|
||||
#[oai(name = "content-length")] content_length: Header<usize>,
|
||||
format: Query<ImageKind>,
|
||||
format: Query<Option<ImageKind>>,
|
||||
|
||||
/// The raw binary data of the image.
|
||||
file: Binary<Body>,
|
||||
|
@ -164,7 +169,26 @@ impl LustApi {
|
|||
}
|
||||
}
|
||||
|
||||
let info = bucket.upload(format.0, allocated_image).await?;
|
||||
let format = if let Some(format) = format.0 {
|
||||
let validate = image::load_from_memory_with_format(&allocated_image, format.into());
|
||||
if let Err(_) = validate {
|
||||
return Ok(UploadResponse::InvalidImageFormat)
|
||||
}
|
||||
|
||||
format
|
||||
} else {
|
||||
let maybe_guessed = image::guess_format(&allocated_image)
|
||||
.map(ImageKind::from_guessed_format)
|
||||
.map_err(anyhow::Error::from)?;
|
||||
|
||||
if let Some(guessed) = maybe_guessed {
|
||||
guessed
|
||||
} else {
|
||||
return Ok(UploadResponse::InvalidImageFormat)
|
||||
}
|
||||
};
|
||||
|
||||
let info = bucket.upload(format, allocated_image).await?;
|
||||
Ok(UploadResponse::Ok(Json(info)))
|
||||
}
|
||||
|
||||
|
|
78
src/tests.rs
78
src/tests.rs
|
@ -1,13 +1,48 @@
|
|||
use poem::{IntoEndpoint, Route};
|
||||
use std::sync::Arc;
|
||||
use poem::Route;
|
||||
use poem::http::StatusCode;
|
||||
use poem_openapi::OpenApiService;
|
||||
use poem::test::TestClient;
|
||||
use poem::web::headers;
|
||||
use tokio::sync::Semaphore;
|
||||
|
||||
use crate::ServerConfig;
|
||||
use crate::{BucketController, config, controller, StorageBackend};
|
||||
|
||||
const EXAMPLE_CONFIG: &str = include_str!("../examples/example.yaml");
|
||||
const TEST_IMAGE: &[u8] = include_bytes!()
|
||||
const TEST_IMAGE: &[u8] = include_bytes!("../examples/example.jpeg");
|
||||
|
||||
async fn setup_environment() -> anyhow::Result<TestClient<Route>> {
|
||||
config::init_test(EXAMPLE_CONFIG)?;
|
||||
|
||||
let global_limiter = config::config()
|
||||
.max_concurrency
|
||||
.map(Semaphore::new)
|
||||
.map(Arc::new);
|
||||
|
||||
let storage: Arc<dyn StorageBackend> = config::config()
|
||||
.backend
|
||||
.connect()
|
||||
.await?;
|
||||
|
||||
let buckets = config::config()
|
||||
.buckets
|
||||
.iter()
|
||||
.map(|(bucket, cfg)| {
|
||||
let bucket_id = crate::utils::crc_hash(bucket);
|
||||
let pipeline = cfg.mode.build_pipeline(cfg);
|
||||
let controller = BucketController::new(
|
||||
bucket_id,
|
||||
global_limiter.clone(),
|
||||
cfg.clone(),
|
||||
pipeline,
|
||||
storage.clone(),
|
||||
);
|
||||
(bucket_id, controller)
|
||||
})
|
||||
.collect();
|
||||
|
||||
controller::init_buckets(buckets);
|
||||
|
||||
fn setup_environment() -> TestClient<Route> {
|
||||
let app = OpenApiService::new(
|
||||
crate::routes::LustApi,
|
||||
"Lust API",
|
||||
|
@ -15,41 +50,54 @@ fn setup_environment() -> TestClient<Route> {
|
|||
);
|
||||
|
||||
let app = Route::new().nest("/v1", app);
|
||||
TestClient::new(app)
|
||||
Ok(TestClient::new(app))
|
||||
}
|
||||
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_basic_aot_upload_retrieval() -> anyhow::Result<()> {
|
||||
crate::config::init_test(EXAMPLE_CONFIG)?;
|
||||
let app = setup_environment();
|
||||
let app = setup_environment().await?;
|
||||
|
||||
app.post("/v1/user-profiles")
|
||||
.body()
|
||||
let res = app.post("/v1/user-profiles")
|
||||
.body(TEST_IMAGE)
|
||||
.content_type("application/octet-stream".to_string())
|
||||
.typed_header(headers::ContentLength(TEST_IMAGE.len() as u64))
|
||||
.query("format".to_string(), &"jpeg".to_string())
|
||||
.send()
|
||||
.await;
|
||||
|
||||
res.assert_status(StatusCode::OK);
|
||||
|
||||
// let res = app.post("/v1/user-profiles")
|
||||
// .body(TEST_IMAGE)
|
||||
// .content_type("application/octet-stream".to_string())
|
||||
// .typed_header(headers::ContentLength(TEST_IMAGE.len() as u64))
|
||||
// .query("format".to_string(), &"jpeg".to_string())
|
||||
// .send()
|
||||
// .await;
|
||||
//
|
||||
// res.assert_status(StatusCode::OK);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_basic_jit_upload_retrieval() -> anyhow::Result<()> {
|
||||
crate::config::init_test(EXAMPLE_CONFIG)?;
|
||||
let app = setup_environment();
|
||||
let app = setup_environment().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_basic_realtime_upload_retrieval() -> anyhow::Result<()> {
|
||||
crate::config::init_test(EXAMPLE_CONFIG)?;
|
||||
let app = setup_environment();
|
||||
let app = setup_environment().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_realtime_resizing() -> anyhow::Result<()> {
|
||||
crate::config::init_test(EXAMPLE_CONFIG)?;
|
||||
let app = setup_environment();
|
||||
let app = setup_environment().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue