mirror of
https://github.com/lifegpc/pixiv_downloader.git
synced 2026-07-08 01:32:41 +08:00
Add unit test for server
This commit is contained in:
@@ -114,7 +114,7 @@ pub fn async_timeout_test(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let f = async {
|
||||
#(#stmts)*
|
||||
};
|
||||
tokio::time::timeout(dura, f).await.unwrap();
|
||||
tokio::time::timeout(dura, f).await.unwrap()
|
||||
}
|
||||
};
|
||||
stream.into()
|
||||
|
||||
@@ -16,7 +16,7 @@ pub use traits::PixivDownloaderDb;
|
||||
pub use user::User;
|
||||
pub type PixivDownloaderDbError = anyhow::Error;
|
||||
|
||||
use crate::{get_helper, gettext};
|
||||
use crate::gettext;
|
||||
|
||||
#[cfg(feature = "db_sqlite")]
|
||||
impl From<SqliteError> for PixivDownloaderDbError {
|
||||
@@ -29,8 +29,9 @@ impl From<SqliteError> for PixivDownloaderDbError {
|
||||
compile_error!("No database backend is enabled.");
|
||||
|
||||
/// Open the database
|
||||
pub fn open_database() -> Result<Box<dyn PixivDownloaderDb + Send + Sync>, PixivDownloaderDbError> {
|
||||
let cfg = get_helper().db();
|
||||
pub fn open_database(
|
||||
cfg: PixivDownloaderDbConfig,
|
||||
) -> Result<Box<dyn PixivDownloaderDb + Send + Sync>, PixivDownloaderDbError> {
|
||||
if cfg.is_none() {
|
||||
return Err(PixivDownloaderDbError::msg(String::from(gettext(
|
||||
"No database configuration provided.",
|
||||
@@ -49,8 +50,9 @@ pub fn open_database() -> Result<Box<dyn PixivDownloaderDb + Send + Sync>, Pixiv
|
||||
|
||||
/// Open the database and initialize it
|
||||
pub async fn open_and_init_database(
|
||||
cfg: PixivDownloaderDbConfig,
|
||||
) -> Result<Box<dyn PixivDownloaderDb + Send + Sync>, PixivDownloaderDbError> {
|
||||
let db = open_database()?;
|
||||
let db = open_database(cfg)?;
|
||||
db.init().await?;
|
||||
Ok(db)
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ pub enum PixivDownloaderError {
|
||||
FromUtf8Error(std::string::FromUtf8Error),
|
||||
#[cfg(feature = "server")]
|
||||
ToStrError(http::header::ToStrError),
|
||||
#[cfg(all(feature = "server", feature = "db_sqlite", test))]
|
||||
JSONError(json::Error),
|
||||
}
|
||||
|
||||
impl From<&str> for PixivDownloaderError {
|
||||
|
||||
@@ -45,6 +45,22 @@ impl AuthUserContext {
|
||||
.try_err((3, gettext("No password specified.")))?;
|
||||
let password = base64::decode(password)
|
||||
.try_err3(4, gettext("Failed to decode password with base64:"))?;
|
||||
let rsa_key = self.ctx.rsa_key.lock().await;
|
||||
match *rsa_key {
|
||||
Some(ref key) => {
|
||||
if key.is_too_old() {
|
||||
return Err((
|
||||
6,
|
||||
gettext("RSA key is too old. A new key should be generated."),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
let password = key
|
||||
.decrypt(&password)
|
||||
.try_err3(7, gettext("Failed to decrypt password with RSA:"))?;
|
||||
}
|
||||
None => return Err((5, gettext("No RSA key found.")).into()),
|
||||
}
|
||||
Ok(json::object! {})
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use super::auth::RSAKey;
|
||||
use super::cors::CorsContext;
|
||||
use crate::db::{open_and_init_database, PixivDownloaderDb};
|
||||
use crate::get_helper;
|
||||
use crate::gettext;
|
||||
use futures_util::lock::Mutex;
|
||||
|
||||
@@ -14,7 +15,7 @@ impl ServerContext {
|
||||
pub async fn default() -> Self {
|
||||
Self {
|
||||
cors: CorsContext::default(),
|
||||
db: match open_and_init_database().await {
|
||||
db: match open_and_init_database(get_helper().db()).await {
|
||||
Ok(db) => db,
|
||||
Err(e) => panic!("{} {}", gettext("Failed to open database:"), e),
|
||||
},
|
||||
|
||||
@@ -361,6 +361,15 @@ pub struct CorsContext {
|
||||
}
|
||||
|
||||
impl CorsContext {
|
||||
#[cfg(test)]
|
||||
pub fn new(allow_all: bool, entries: Vec<CorsEntry>, hosts: Vec<CorsHost>) -> Self {
|
||||
Self {
|
||||
allow_all,
|
||||
entries,
|
||||
hosts,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn matches<T: Clone>(&self, host: T) -> CorsResult
|
||||
where
|
||||
CorsEntry: PartialEq<T>,
|
||||
|
||||
@@ -15,5 +15,7 @@ pub mod route;
|
||||
pub mod service;
|
||||
/// Traits
|
||||
pub mod traits;
|
||||
#[cfg(all(test, feature = "db_sqlite"))]
|
||||
mod unittest;
|
||||
/// Version
|
||||
pub mod version;
|
||||
|
||||
67
src/server/unittest/mod.rs
Normal file
67
src/server/unittest/mod.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
mod version;
|
||||
|
||||
use super::context::ServerContext;
|
||||
use super::cors::CorsContext;
|
||||
use super::route::ServerRoutes;
|
||||
use crate::db::{open_and_init_database, PixivDownloaderDbConfig};
|
||||
use crate::error::PixivDownloaderError;
|
||||
use futures_util::lock::Mutex;
|
||||
use hyper::{Body, Request, Response};
|
||||
use json::JsonValue;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct UnitTestContext {
|
||||
ctx: Arc<ServerContext>,
|
||||
routes: ServerRoutes,
|
||||
}
|
||||
|
||||
impl UnitTestContext {
|
||||
pub async fn new() -> Self {
|
||||
Self {
|
||||
ctx: Arc::new(ServerContext {
|
||||
cors: CorsContext::new(true, vec![], vec![]),
|
||||
db: open_and_init_database(
|
||||
PixivDownloaderDbConfig::new(&json::object! {
|
||||
"type": "sqlite",
|
||||
"path": "test/server.db",
|
||||
})
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap(),
|
||||
rsa_key: Mutex::new(None),
|
||||
}),
|
||||
routes: ServerRoutes::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn request(
|
||||
&self,
|
||||
req: Request<Body>,
|
||||
) -> Result<Option<Response<Body>>, PixivDownloaderError> {
|
||||
Ok(match self.routes.match_route(&req, &self.ctx) {
|
||||
Some(r) => Some(r.response(req).await?),
|
||||
None => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn request_json(
|
||||
&self,
|
||||
req: Request<Body>,
|
||||
) -> Result<Option<JsonValue>, PixivDownloaderError> {
|
||||
Ok(match self.request(req).await? {
|
||||
Some(r) => Some(json::parse(&String::from_utf8_lossy(
|
||||
&hyper::body::to_bytes(r.into_body()).await?,
|
||||
))?),
|
||||
None => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macros::async_timeout_test(120s)]
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test() -> Result<(), PixivDownloaderError> {
|
||||
let ctx = UnitTestContext::new().await;
|
||||
version::test(&ctx).await?;
|
||||
Ok(())
|
||||
}
|
||||
11
src/server/unittest/version.rs
Normal file
11
src/server/unittest/version.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
use super::super::version::VERSION;
|
||||
use super::UnitTestContext;
|
||||
use crate::error::PixivDownloaderError;
|
||||
use hyper::{Body, Request};
|
||||
|
||||
pub async fn test(ctx: &UnitTestContext) -> Result<(), PixivDownloaderError> {
|
||||
let re = Request::builder().uri("/version").body(Body::empty())?;
|
||||
let res = ctx.request_json(re).await?.unwrap();
|
||||
assert_eq!(res, json::object! {"version": VERSION.to_vec()});
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
use super::preclude::*;
|
||||
|
||||
pub const VERSION: [u8; 4] = [0, 0, 1, 0];
|
||||
|
||||
pub struct VersionContext {
|
||||
ctx: Arc<ServerContext>,
|
||||
}
|
||||
@@ -26,7 +28,7 @@ impl ResponseJsonFor<Body> for VersionContext {
|
||||
OPTIONS,
|
||||
POST,
|
||||
);
|
||||
Ok(builder.body(json::object! {"version": [0, 0, 1, 0]})?)
|
||||
Ok(builder.body(json::object! {"version": VERSION.to_vec()})?)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user