Add unit test for server

This commit is contained in:
2022-09-23 04:29:05 +00:00
committed by GitHub
parent 2bd7bcef6f
commit 970a4ec731
10 changed files with 119 additions and 7 deletions

View File

@@ -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()

View File

@@ -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)
}

View File

@@ -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 {

View File

@@ -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! {})
}
},

View File

@@ -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),
},

View File

@@ -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>,

View File

@@ -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;

View 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(())
}

View 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(())
}

View File

@@ -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()})?)
}
}