mirror of
https://github.com/lennart-k/rustical.git
synced 2025-12-14 16:32:29 +00:00
add integration tests
This commit is contained in:
@@ -2,7 +2,10 @@ use crate::{
|
|||||||
SqliteStore, addressbook_store::SqliteAddressbookStore, calendar_store::SqliteCalendarStore,
|
SqliteStore, addressbook_store::SqliteAddressbookStore, calendar_store::SqliteCalendarStore,
|
||||||
principal_store::SqlitePrincipalStore,
|
principal_store::SqlitePrincipalStore,
|
||||||
};
|
};
|
||||||
use rustical_store::auth::{AuthenticationProvider, Principal, PrincipalType};
|
use rustical_store::{
|
||||||
|
Secret,
|
||||||
|
auth::{AuthenticationProvider, Principal, PrincipalType},
|
||||||
|
};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
@@ -31,6 +34,10 @@ async fn get_test_db() -> SqlitePool {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
principal_store
|
||||||
|
.add_app_token("user", "test".to_string(), "pass".to_string())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
db
|
db
|
||||||
})
|
})
|
||||||
|
|||||||
111
src/integration_tests/caldav/mod.rs
Normal file
111
src/integration_tests/caldav/mod.rs
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
use crate::integration_tests::{ResponseExtractString, get_app};
|
||||||
|
use axum::body::Body;
|
||||||
|
use axum::extract::Request;
|
||||||
|
use headers::{Authorization, HeaderMapExt};
|
||||||
|
use http::{HeaderValue, StatusCode};
|
||||||
|
use rstest::rstest;
|
||||||
|
use tower::ServiceExt;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_caldav_root(
|
||||||
|
#[from(get_app)]
|
||||||
|
#[future]
|
||||||
|
app: axum::Router,
|
||||||
|
) {
|
||||||
|
let app = app.await;
|
||||||
|
|
||||||
|
let request_template = || {
|
||||||
|
Request::builder()
|
||||||
|
.method("PROPFIND")
|
||||||
|
.uri("/caldav")
|
||||||
|
.body(Body::empty())
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try without authentication
|
||||||
|
let request = request_template();
|
||||||
|
let response = app.clone().oneshot(request).await.unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||||
|
let body = response.extract_string().await;
|
||||||
|
insta::assert_snapshot!(body);
|
||||||
|
|
||||||
|
// Try with wrong password
|
||||||
|
let mut request = request_template();
|
||||||
|
request
|
||||||
|
.headers_mut()
|
||||||
|
.typed_insert(Authorization::basic("user", "wrongpass"));
|
||||||
|
let response = app.clone().oneshot(request).await.unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||||
|
let body = response.extract_string().await;
|
||||||
|
insta::assert_snapshot!(body);
|
||||||
|
|
||||||
|
// Try with correct credentials
|
||||||
|
let mut request = request_template();
|
||||||
|
request
|
||||||
|
.headers_mut()
|
||||||
|
.typed_insert(Authorization::basic("user", "pass"));
|
||||||
|
|
||||||
|
let response = app.oneshot(request).await.unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::MULTI_STATUS);
|
||||||
|
let body = response.extract_string().await;
|
||||||
|
insta::assert_snapshot!(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_caldav_principal(
|
||||||
|
#[from(get_app)]
|
||||||
|
#[future]
|
||||||
|
app: axum::Router,
|
||||||
|
) {
|
||||||
|
let app = app.await;
|
||||||
|
|
||||||
|
let request_template = || {
|
||||||
|
Request::builder()
|
||||||
|
.method("PROPFIND")
|
||||||
|
.uri("/caldav/principal/user")
|
||||||
|
.body(Body::empty())
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try without authentication
|
||||||
|
let request = request_template();
|
||||||
|
let response = app.clone().oneshot(request).await.unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||||
|
let body = response.extract_string().await;
|
||||||
|
insta::assert_snapshot!(body);
|
||||||
|
|
||||||
|
// Try with wrong password
|
||||||
|
let mut request = request_template();
|
||||||
|
request
|
||||||
|
.headers_mut()
|
||||||
|
.typed_insert(Authorization::basic("user", "wrongpass"));
|
||||||
|
let response = app.clone().oneshot(request).await.unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||||
|
let body = response.extract_string().await;
|
||||||
|
insta::assert_snapshot!(body);
|
||||||
|
|
||||||
|
// Try with correct credentials
|
||||||
|
let mut request = request_template();
|
||||||
|
request
|
||||||
|
.headers_mut()
|
||||||
|
.typed_insert(Authorization::basic("user", "pass"));
|
||||||
|
let response = app.clone().oneshot(request).await.unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::MULTI_STATUS);
|
||||||
|
let body = response.extract_string().await;
|
||||||
|
insta::assert_snapshot!(body);
|
||||||
|
|
||||||
|
// Try with Depth: 1
|
||||||
|
let mut request = request_template();
|
||||||
|
request
|
||||||
|
.headers_mut()
|
||||||
|
.typed_insert(Authorization::basic("user", "pass"));
|
||||||
|
request
|
||||||
|
.headers_mut()
|
||||||
|
.insert("Depth", HeaderValue::from_static("1"));
|
||||||
|
let response = app.clone().oneshot(request).await.unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::MULTI_STATUS);
|
||||||
|
let body = response.extract_string().await;
|
||||||
|
insta::assert_snapshot!(body);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
source: src/integration_tests/caldav/mod.rs
|
||||||
|
expression: body
|
||||||
|
---
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
source: src/integration_tests/caldav/mod.rs
|
||||||
|
expression: body
|
||||||
|
---
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<multistatus xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/" xmlns:PUSH="https://bitfire.at/webdav-push">
|
||||||
|
<response xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/" xmlns:PUSH="https://bitfire.at/webdav-push">
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
<propstat>
|
||||||
|
<prop>
|
||||||
|
<CAL:calendar-user-type>INDIVIDUAL</CAL:calendar-user-type>
|
||||||
|
<CAL:calendar-user-address-set>
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
</CAL:calendar-user-address-set>
|
||||||
|
<principal-URL>
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
</principal-URL>
|
||||||
|
<group-membership>
|
||||||
|
</group-membership>
|
||||||
|
<group-member-set>
|
||||||
|
</group-member-set>
|
||||||
|
<alternate-URI-set/>
|
||||||
|
<supported-report-set>
|
||||||
|
<supported-report>
|
||||||
|
<report>
|
||||||
|
<principal-match/>
|
||||||
|
</report>
|
||||||
|
</supported-report>
|
||||||
|
</supported-report-set>
|
||||||
|
<CAL:calendar-home-set>
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
</CAL:calendar-home-set>
|
||||||
|
<resourcetype>
|
||||||
|
<collection/>
|
||||||
|
<principal/>
|
||||||
|
</resourcetype>
|
||||||
|
<displayname>user</displayname>
|
||||||
|
<current-user-principal>
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
</current-user-principal>
|
||||||
|
<current-user-privilege-set>
|
||||||
|
<privilege>
|
||||||
|
<all/>
|
||||||
|
</privilege>
|
||||||
|
</current-user-privilege-set>
|
||||||
|
<owner>
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
</owner>
|
||||||
|
</prop>
|
||||||
|
<status>HTTP/1.1 200 OK</status>
|
||||||
|
</propstat>
|
||||||
|
</response>
|
||||||
|
</multistatus>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
source: src/integration_tests/caldav/mod.rs
|
||||||
|
expression: body
|
||||||
|
---
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<multistatus xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/" xmlns:PUSH="https://bitfire.at/webdav-push">
|
||||||
|
<response xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/" xmlns:PUSH="https://bitfire.at/webdav-push">
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
<propstat>
|
||||||
|
<prop>
|
||||||
|
<CAL:calendar-user-type>INDIVIDUAL</CAL:calendar-user-type>
|
||||||
|
<CAL:calendar-user-address-set>
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
</CAL:calendar-user-address-set>
|
||||||
|
<principal-URL>
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
</principal-URL>
|
||||||
|
<group-membership>
|
||||||
|
</group-membership>
|
||||||
|
<group-member-set>
|
||||||
|
</group-member-set>
|
||||||
|
<alternate-URI-set/>
|
||||||
|
<supported-report-set>
|
||||||
|
<supported-report>
|
||||||
|
<report>
|
||||||
|
<principal-match/>
|
||||||
|
</report>
|
||||||
|
</supported-report>
|
||||||
|
</supported-report-set>
|
||||||
|
<CAL:calendar-home-set>
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
</CAL:calendar-home-set>
|
||||||
|
<resourcetype>
|
||||||
|
<collection/>
|
||||||
|
<principal/>
|
||||||
|
</resourcetype>
|
||||||
|
<displayname>user</displayname>
|
||||||
|
<current-user-principal>
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
</current-user-principal>
|
||||||
|
<current-user-privilege-set>
|
||||||
|
<privilege>
|
||||||
|
<all/>
|
||||||
|
</privilege>
|
||||||
|
</current-user-privilege-set>
|
||||||
|
<owner>
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
</owner>
|
||||||
|
</prop>
|
||||||
|
<status>HTTP/1.1 200 OK</status>
|
||||||
|
</propstat>
|
||||||
|
</response>
|
||||||
|
</multistatus>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
source: src/integration_tests/caldav/mod.rs
|
||||||
|
expression: body
|
||||||
|
---
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
source: src/integration_tests/caldav/mod.rs
|
||||||
|
expression: body
|
||||||
|
---
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
source: src/integration_tests/caldav/mod.rs
|
||||||
|
expression: body
|
||||||
|
---
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<multistatus xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/" xmlns:PUSH="https://bitfire.at/webdav-push">
|
||||||
|
<response xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/" xmlns:PUSH="https://bitfire.at/webdav-push">
|
||||||
|
<href>/caldav/</href>
|
||||||
|
<propstat>
|
||||||
|
<prop>
|
||||||
|
<resourcetype>
|
||||||
|
<collection/>
|
||||||
|
</resourcetype>
|
||||||
|
<displayname>RustiCal DAV root</displayname>
|
||||||
|
<current-user-principal>
|
||||||
|
<href>/caldav/principal/user/</href>
|
||||||
|
</current-user-principal>
|
||||||
|
<current-user-privilege-set>
|
||||||
|
<privilege>
|
||||||
|
<all/>
|
||||||
|
</privilege>
|
||||||
|
</current-user-privilege-set>
|
||||||
|
</prop>
|
||||||
|
<status>HTTP/1.1 200 OK</status>
|
||||||
|
</propstat>
|
||||||
|
</response>
|
||||||
|
</multistatus>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
source: src/integration_tests/caldav/mod.rs
|
||||||
|
expression: body
|
||||||
|
---
|
||||||
|
|
||||||
53
src/integration_tests/carddav/mod.rs
Normal file
53
src/integration_tests/carddav/mod.rs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
use crate::integration_tests::{ResponseExtractString, get_app};
|
||||||
|
use axum::body::Body;
|
||||||
|
use axum::extract::Request;
|
||||||
|
use headers::{Authorization, HeaderMapExt};
|
||||||
|
use http::StatusCode;
|
||||||
|
use rstest::rstest;
|
||||||
|
use tower::ServiceExt;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_carddav_root(
|
||||||
|
#[from(get_app)]
|
||||||
|
#[future]
|
||||||
|
app: axum::Router,
|
||||||
|
) {
|
||||||
|
let app = app.await;
|
||||||
|
|
||||||
|
let request_template = || {
|
||||||
|
Request::builder()
|
||||||
|
.method("PROPFIND")
|
||||||
|
.uri("/carddav")
|
||||||
|
.body(Body::empty())
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try without authentication
|
||||||
|
let request = request_template();
|
||||||
|
let response = app.clone().oneshot(request).await.unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||||
|
let body = response.extract_string().await;
|
||||||
|
insta::assert_snapshot!(body);
|
||||||
|
|
||||||
|
// Try with wrong password
|
||||||
|
let mut request = request_template();
|
||||||
|
request
|
||||||
|
.headers_mut()
|
||||||
|
.typed_insert(Authorization::basic("user", "wrongpass"));
|
||||||
|
let response = app.clone().oneshot(request).await.unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||||
|
let body = response.extract_string().await;
|
||||||
|
insta::assert_snapshot!(body);
|
||||||
|
|
||||||
|
// Try with correct credentials
|
||||||
|
let mut request = request_template();
|
||||||
|
request
|
||||||
|
.headers_mut()
|
||||||
|
.typed_insert(Authorization::basic("user", "pass"));
|
||||||
|
|
||||||
|
let response = app.oneshot(request).await.unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::MULTI_STATUS);
|
||||||
|
let body = response.extract_string().await;
|
||||||
|
insta::assert_snapshot!(body);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
source: src/integration_tests/carddav/mod.rs
|
||||||
|
expression: body
|
||||||
|
---
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
source: src/integration_tests/carddav/mod.rs
|
||||||
|
expression: body
|
||||||
|
---
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<multistatus xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/" xmlns:PUSH="https://bitfire.at/webdav-push">
|
||||||
|
<response xmlns="DAV:" xmlns:CAL="urn:ietf:params:xml:ns:caldav" xmlns:CARD="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/" xmlns:PUSH="https://bitfire.at/webdav-push">
|
||||||
|
<href>/carddav/</href>
|
||||||
|
<propstat>
|
||||||
|
<prop>
|
||||||
|
<resourcetype>
|
||||||
|
<collection/>
|
||||||
|
</resourcetype>
|
||||||
|
<displayname>RustiCal DAV root</displayname>
|
||||||
|
<current-user-principal>
|
||||||
|
<href>/carddav/principal/user/</href>
|
||||||
|
</current-user-principal>
|
||||||
|
<current-user-privilege-set>
|
||||||
|
<privilege>
|
||||||
|
<all/>
|
||||||
|
</privilege>
|
||||||
|
</current-user-privilege-set>
|
||||||
|
</prop>
|
||||||
|
<status>HTTP/1.1 200 OK</status>
|
||||||
|
</propstat>
|
||||||
|
</response>
|
||||||
|
</multistatus>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
source: src/integration_tests/carddav/mod.rs
|
||||||
|
expression: body
|
||||||
|
---
|
||||||
|
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
use crate::{app::make_app, config::NextcloudLoginConfig};
|
use crate::{app::make_app, config::NextcloudLoginConfig};
|
||||||
|
use axum::extract::Request;
|
||||||
|
use axum::{body::Body, response::Response};
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
use rustical_frontend::FrontendConfig;
|
use rustical_frontend::FrontendConfig;
|
||||||
use rustical_store_sqlite::{
|
use rustical_store_sqlite::{
|
||||||
@@ -12,10 +14,10 @@ use rustical_store_sqlite::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use tower::ServiceExt;
|
||||||
|
|
||||||
#[rstest]
|
#[rstest::fixture]
|
||||||
#[tokio::test]
|
pub async fn get_app(
|
||||||
async fn test_app(
|
|
||||||
#[from(get_test_calendar_store)]
|
#[from(get_test_calendar_store)]
|
||||||
#[future]
|
#[future]
|
||||||
cal_store: SqliteCalendarStore,
|
cal_store: SqliteCalendarStore,
|
||||||
@@ -28,13 +30,13 @@ async fn test_app(
|
|||||||
#[from(get_test_subscription_store)]
|
#[from(get_test_subscription_store)]
|
||||||
#[future]
|
#[future]
|
||||||
sub_store: SqliteStore,
|
sub_store: SqliteStore,
|
||||||
) {
|
) -> axum::Router {
|
||||||
let addr_store = Arc::new(addr_store.await);
|
let addr_store = Arc::new(addr_store.await);
|
||||||
let cal_store = Arc::new(cal_store.await);
|
let cal_store = Arc::new(cal_store.await);
|
||||||
let sub_store = Arc::new(sub_store.await);
|
let sub_store = Arc::new(sub_store.await);
|
||||||
let principal_store = Arc::new(principal_store.await);
|
let principal_store = Arc::new(principal_store.await);
|
||||||
|
|
||||||
let _app = make_app(
|
make_app(
|
||||||
addr_store,
|
addr_store,
|
||||||
cal_store,
|
cal_store,
|
||||||
sub_store,
|
sub_store,
|
||||||
@@ -48,5 +50,38 @@ async fn test_app(
|
|||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
20,
|
20,
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ResponseExtractString {
|
||||||
|
#[allow(async_fn_in_trait)]
|
||||||
|
async fn extract_string(self) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResponseExtractString for Response {
|
||||||
|
async fn extract_string(self) -> String {
|
||||||
|
let bytes = axum::body::to_bytes(self.into_body(), usize::MAX)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
String::from_utf8(bytes.to_vec()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_ping(
|
||||||
|
#[from(get_app)]
|
||||||
|
#[future]
|
||||||
|
app: axum::Router,
|
||||||
|
) {
|
||||||
|
let app = app.await;
|
||||||
|
|
||||||
|
let response = app
|
||||||
|
.oneshot(Request::builder().uri("/ping").body(Body::empty()).unwrap())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
}
|
||||||
|
|
||||||
|
mod caldav;
|
||||||
|
mod carddav;
|
||||||
@@ -30,9 +30,9 @@ use tracing::info;
|
|||||||
mod app;
|
mod app;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod config;
|
mod config;
|
||||||
mod setup_tracing;
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
pub mod integration_tests;
|
||||||
|
mod setup_tracing;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
|
|||||||
Reference in New Issue
Block a user