From 4b8a8c61f2a53afe9cba0e1f7e44525784510e1b Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Wed, 31 Dec 2025 01:05:56 +0100 Subject: [PATCH] Tests: Fix scope of store --- crates/caldav/src/principal/tests.rs | 29 ++- .../benches/insert_calendar_object.rs | 4 +- .../store_sqlite/src/addressbook_store/mod.rs | 2 +- crates/store_sqlite/src/calendar_store.rs | 2 +- crates/store_sqlite/src/lib.rs | 2 +- crates/store_sqlite/src/principal_store.rs | 2 +- .../src/tests/addressbook_store.rs | 8 +- .../store_sqlite/src/tests/calendar_store.rs | 10 +- crates/store_sqlite/src/tests/mod.rs | 88 ++++---- src/integration_tests/caldav/calendar.rs | 14 +- src/integration_tests/caldav/mod.rs | 13 +- ...ation_tests__caldav__propfind_depth_1.snap | 188 ------------------ src/integration_tests/carddav/mod.rs | 7 +- src/integration_tests/mod.rs | 50 ++--- 14 files changed, 103 insertions(+), 316 deletions(-) diff --git a/crates/caldav/src/principal/tests.rs b/crates/caldav/src/principal/tests.rs index 75ac6c0..2a1954f 100644 --- a/crates/caldav/src/principal/tests.rs +++ b/crates/caldav/src/principal/tests.rs @@ -5,32 +5,27 @@ use crate::{ use rstest::rstest; use rustical_dav::resource::{Resource, ResourceService}; use rustical_store::auth::{Principal, PrincipalType::Individual}; -use rustical_store_sqlite::{ - SqliteStore, - calendar_store::SqliteCalendarStore, - principal_store::SqlitePrincipalStore, - tests::{get_test_calendar_store, get_test_principal_store, get_test_subscription_store}, -}; +use rustical_store_sqlite::tests::{TestStoreContext, test_store_context}; use rustical_xml::XmlSerializeRoot; use std::sync::Arc; #[rstest] #[tokio::test] async fn test_principal_resource( - #[from(get_test_calendar_store)] #[future] - cal_store: SqliteCalendarStore, - #[from(get_test_principal_store)] - #[future] - auth_provider: SqlitePrincipalStore, - #[from(get_test_subscription_store)] - #[future] - sub_store: SqliteStore, + #[from(test_store_context)] + context: TestStoreContext, ) { + let TestStoreContext { + cal_store, + sub_store, + principal_store: auth_provider, + .. + } = context.await; let service = PrincipalResourceService { - cal_store: Arc::new(cal_store.await), - sub_store: Arc::new(sub_store.await), - auth_provider: Arc::new(auth_provider.await), + cal_store: Arc::new(cal_store), + sub_store: Arc::new(sub_store), + auth_provider: Arc::new(auth_provider), simplified_home_set: false, }; diff --git a/crates/store_sqlite/benches/insert_calendar_object.rs b/crates/store_sqlite/benches/insert_calendar_object.rs index 1926075..02f0d42 100644 --- a/crates/store_sqlite/benches/insert_calendar_object.rs +++ b/crates/store_sqlite/benches/insert_calendar_object.rs @@ -1,12 +1,12 @@ use criterion::{Criterion, criterion_group, criterion_main}; use rustical_ical::{CalendarObject, CalendarObjectType}; use rustical_store::{Calendar, CalendarMetadata, CalendarStore}; -use rustical_store_sqlite::tests::get_test_calendar_store; +use rustical_store_sqlite::tests::test_store_context; fn benchmark(c: &mut Criterion) { let runtime = tokio::runtime::Runtime::new().unwrap(); let cal_store = runtime.block_on(async { - let cal_store = get_test_calendar_store().await; + let cal_store = test_store_context().await.cal_store; cal_store .insert_calendar(Calendar { diff --git a/crates/store_sqlite/src/addressbook_store/mod.rs b/crates/store_sqlite/src/addressbook_store/mod.rs index ff44464..b026c3d 100644 --- a/crates/store_sqlite/src/addressbook_store/mod.rs +++ b/crates/store_sqlite/src/addressbook_store/mod.rs @@ -27,7 +27,7 @@ impl TryFrom for AddressObject { } } -#[derive(Debug, Constructor)] +#[derive(Debug, Clone, Constructor)] pub struct SqliteAddressbookStore { db: SqlitePool, sender: Sender, diff --git a/crates/store_sqlite/src/calendar_store.rs b/crates/store_sqlite/src/calendar_store.rs index ea4d2a8..f49f293 100644 --- a/crates/store_sqlite/src/calendar_store.rs +++ b/crates/store_sqlite/src/calendar_store.rs @@ -87,7 +87,7 @@ impl From for Calendar { } } -#[derive(Debug, Constructor)] +#[derive(Debug, Clone, Constructor)] pub struct SqliteCalendarStore { db: SqlitePool, sender: Sender, diff --git a/crates/store_sqlite/src/lib.rs b/crates/store_sqlite/src/lib.rs index fca8f27..50b9428 100644 --- a/crates/store_sqlite/src/lib.rs +++ b/crates/store_sqlite/src/lib.rs @@ -24,7 +24,7 @@ pub(crate) enum ChangeOperation { Delete, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct SqliteStore { db: SqlitePool, } diff --git a/crates/store_sqlite/src/principal_store.rs b/crates/store_sqlite/src/principal_store.rs index bdcbac7..a289791 100644 --- a/crates/store_sqlite/src/principal_store.rs +++ b/crates/store_sqlite/src/principal_store.rs @@ -41,7 +41,7 @@ impl TryFrom for Principal { } } -#[derive(Debug, Constructor)] +#[derive(Debug, Clone, Constructor)] pub struct SqlitePrincipalStore { db: SqlitePool, } diff --git a/crates/store_sqlite/src/tests/addressbook_store.rs b/crates/store_sqlite/src/tests/addressbook_store.rs index c61c87e..50b1759 100644 --- a/crates/store_sqlite/src/tests/addressbook_store.rs +++ b/crates/store_sqlite/src/tests/addressbook_store.rs @@ -1,17 +1,17 @@ #[cfg(test)] mod tests { - use crate::{addressbook_store::SqliteAddressbookStore, tests::get_test_addressbook_store}; + use crate::tests::{TestStoreContext, test_store_context}; use rstest::rstest; use rustical_store::{Addressbook, AddressbookStore}; #[rstest] #[tokio::test] async fn test_addressbook_store( - #[from(get_test_addressbook_store)] + #[from(test_store_context)] #[future] - addr_store: SqliteAddressbookStore, + context: TestStoreContext, ) { - let addr_store = addr_store.await; + let addr_store = context.await.addr_store; let cal = Addressbook { id: "addr".to_string(), diff --git a/crates/store_sqlite/src/tests/calendar_store.rs b/crates/store_sqlite/src/tests/calendar_store.rs index e12cefd..df3eab2 100644 --- a/crates/store_sqlite/src/tests/calendar_store.rs +++ b/crates/store_sqlite/src/tests/calendar_store.rs @@ -1,17 +1,19 @@ #[cfg(test)] mod tests { - use crate::{calendar_store::SqliteCalendarStore, tests::get_test_calendar_store}; + use crate::tests::{TestStoreContext, test_store_context}; use rstest::rstest; use rustical_store::{Calendar, CalendarMetadata, CalendarStore}; #[rstest] #[tokio::test] async fn test_calendar_store( - #[from(get_test_calendar_store)] #[future] - cal_store: SqliteCalendarStore, + #[from(test_store_context)] + context: TestStoreContext, ) { - let cal_store = cal_store.await; + let TestStoreContext { cal_store, .. } = context.await; + + let cal_store = cal_store; let cal = Calendar { principal: "fake-user".to_string(), diff --git a/crates/store_sqlite/src/tests/mod.rs b/crates/store_sqlite/src/tests/mod.rs index 755cdf0..aee4f21 100644 --- a/crates/store_sqlite/src/tests/mod.rs +++ b/crates/store_sqlite/src/tests/mod.rs @@ -2,61 +2,59 @@ use crate::{ SqliteStore, addressbook_store::SqliteAddressbookStore, calendar_store::SqliteCalendarStore, principal_store::SqlitePrincipalStore, }; +use rstest::fixture; use rustical_store::auth::{AuthenticationProvider, Principal, PrincipalType}; use sqlx::SqlitePool; -use tokio::sync::OnceCell; - -static DB: OnceCell = OnceCell::const_new(); mod addressbook_store; mod calendar_store; async fn get_test_db() -> SqlitePool { - DB.get_or_init(async || { - let db = SqlitePool::connect("sqlite::memory:").await.unwrap(); - sqlx::migrate!("./migrations").run(&db).await.unwrap(); + let db = SqlitePool::connect("sqlite::memory:").await.unwrap(); + sqlx::migrate!("./migrations").run(&db).await.unwrap(); - // Populate with test data - let principal_store = SqlitePrincipalStore::new(db.clone()); - principal_store - .insert_principal( - Principal { - id: "user".to_owned(), - displayname: None, - memberships: vec![], - password: None, - principal_type: PrincipalType::Individual, - }, - false, - ) - .await - .unwrap(); - principal_store - .add_app_token("user", "test".to_string(), "pass".to_string()) - .await - .unwrap(); + // Populate with test data + let principal_store = SqlitePrincipalStore::new(db.clone()); + principal_store + .insert_principal( + Principal { + id: "user".to_owned(), + displayname: None, + memberships: vec![], + password: None, + principal_type: PrincipalType::Individual, + }, + false, + ) + .await + .unwrap(); + principal_store + .add_app_token("user", "test".to_string(), "pass".to_string()) + .await + .unwrap(); - db - }) - .await - .clone() + db } -#[rstest::fixture] -pub async fn get_test_addressbook_store() -> SqliteAddressbookStore { - let (send, _recv) = tokio::sync::mpsc::channel(1000); - SqliteAddressbookStore::new(get_test_db().await, send) +#[derive(Debug, Clone)] +pub struct TestStoreContext { + pub db: SqlitePool, + pub addr_store: SqliteAddressbookStore, + pub cal_store: SqliteCalendarStore, + pub principal_store: SqlitePrincipalStore, + pub sub_store: SqliteStore, } -#[rstest::fixture] -pub async fn get_test_calendar_store() -> SqliteCalendarStore { - let (send, _recv) = tokio::sync::mpsc::channel(1000); - SqliteCalendarStore::new(get_test_db().await, send) -} -#[rstest::fixture] -pub async fn get_test_subscription_store() -> SqliteStore { - SqliteStore::new(get_test_db().await) -} -#[rstest::fixture] -pub async fn get_test_principal_store() -> SqlitePrincipalStore { - SqlitePrincipalStore::new(get_test_db().await) + +#[fixture] +pub async fn test_store_context() -> TestStoreContext { + let (send_addr, _recv) = tokio::sync::mpsc::channel(1); + let (send_cal, _recv) = tokio::sync::mpsc::channel(1); + let db = get_test_db().await; + TestStoreContext { + db: db.clone(), + addr_store: SqliteAddressbookStore::new(db.clone(), send_addr), + cal_store: SqliteCalendarStore::new(db.clone(), send_cal), + principal_store: SqlitePrincipalStore::new(db.clone()), + sub_store: SqliteStore::new(db), + } } diff --git a/src/integration_tests/caldav/calendar.rs b/src/integration_tests/caldav/calendar.rs index a1df6b7..b4478f2 100644 --- a/src/integration_tests/caldav/calendar.rs +++ b/src/integration_tests/caldav/calendar.rs @@ -5,7 +5,7 @@ use headers::{Authorization, HeaderMapExt}; use http::{HeaderValue, StatusCode}; use rstest::rstest; use rustical_store::{CalendarMetadata, CalendarStore}; -use rustical_store_sqlite::{calendar_store::SqliteCalendarStore, tests::get_test_calendar_store}; +use rustical_store_sqlite::tests::{TestStoreContext, test_store_context}; use tower::ServiceExt; fn mkcalendar_template( @@ -48,15 +48,13 @@ fn mkcalendar_template( #[rstest] #[tokio::test] async fn test_caldav_calendar( - #[from(get_app)] + #[from(test_store_context)] #[future] - app: axum::Router, - #[from(get_test_calendar_store)] - #[future] - cal_store: SqliteCalendarStore, + context: TestStoreContext, ) { - let app = app.await; - let cal_store = cal_store.await; + let context = context.await; + let app = get_app(context.clone()); + let cal_store = context.cal_store; let mut calendar_meta = CalendarMetadata { displayname: Some("Calendar".to_string()), diff --git a/src/integration_tests/caldav/mod.rs b/src/integration_tests/caldav/mod.rs index a34f104..101acc6 100644 --- a/src/integration_tests/caldav/mod.rs +++ b/src/integration_tests/caldav/mod.rs @@ -4,6 +4,7 @@ use axum::extract::Request; use headers::{Authorization, HeaderMapExt}; use http::{HeaderValue, StatusCode}; use rstest::rstest; +use rustical_store_sqlite::tests::{TestStoreContext, test_store_context}; use tower::ServiceExt; mod calendar; @@ -11,11 +12,11 @@ mod calendar; #[rstest] #[tokio::test] async fn test_caldav_root( - #[from(get_app)] + #[from(test_store_context)] #[future] - app: axum::Router, + context: TestStoreContext, ) { - let app = app.await; + let app = get_app(context.await); let request_template = || { Request::builder() @@ -53,11 +54,11 @@ async fn test_caldav_root( #[rstest] #[tokio::test] async fn test_caldav_principal( - #[from(get_app)] + #[from(test_store_context)] #[future] - app: axum::Router, + context: TestStoreContext, ) { - let app = app.await; + let app = get_app(context.await); let request_template = || { Request::builder() diff --git a/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__propfind_depth_1.snap b/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__propfind_depth_1.snap index 7e33986..dfabdac 100644 --- a/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__propfind_depth_1.snap +++ b/src/integration_tests/caldav/snapshots/rustical__integration_tests__caldav__propfind_depth_1.snap @@ -50,192 +50,4 @@ expression: body HTTP/1.1 200 OK - - /caldav/principal/user/calendar/ - - - #00FF00 - Description - BEGIN:VCALENDAR -PRODID:-//github.com/lennart-k/vzic-rs//RustiCal Calendar server//EN -VERSION:2.0 -BEGIN:VTIMEZONE -TZID:Europe/Berlin -LAST-MODIFIED:20250723T190331Z -X-LIC-LOCATION:Europe/Berlin -X-PROLEPTIC-TZNAME:LMT -BEGIN:STANDARD -TZNAME:CET -TZOFFSETFROM:+005328 -TZOFFSETTO:+0100 -DTSTART:18930401T000000 -END:STANDARD -BEGIN:DAYLIGHT -TZNAME:CEST -TZOFFSETFROM:+0100 -TZOFFSETTO:+0200 -DTSTART:19160430T230000 -RDATE:19400401T020000 -RDATE:19430329T020000 -RDATE:19460414T020000 -RDATE:19470406T030000 -RDATE:19480418T020000 -RDATE:19490410T020000 -RDATE:19800406T020000 -END:DAYLIGHT -BEGIN:STANDARD -TZNAME:CET -TZOFFSETFROM:+0200 -TZOFFSETTO:+0100 -DTSTART:19161001T010000 -RDATE:19421102T030000 -RDATE:19431004T030000 -RDATE:19441002T030000 -RDATE:19451118T030000 -RDATE:19461007T030000 -END:STANDARD -BEGIN:DAYLIGHT -TZNAME:CEST -TZOFFSETFROM:+0100 -TZOFFSETTO:+0200 -DTSTART:19170416T020000 -RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=3MO;UNTIL=19180415T010000Z -END:DAYLIGHT -BEGIN:STANDARD -TZNAME:CET -TZOFFSETFROM:+0200 -TZOFFSETTO:+0100 -DTSTART:19170917T030000 -RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=3MO;UNTIL=19180916T010000Z -END:STANDARD -BEGIN:DAYLIGHT -TZNAME:CEST -TZOFFSETFROM:+0100 -TZOFFSETTO:+0200 -DTSTART:19440403T020000 -RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1MO;UNTIL=19450402T010000Z -END:DAYLIGHT -BEGIN:DAYLIGHT -TZNAME:CEMT -TZOFFSETFROM:+0200 -TZOFFSETTO:+0300 -DTSTART:19450524T020000 -RDATE:19470511T030000 -END:DAYLIGHT -BEGIN:DAYLIGHT -TZNAME:CEST -TZOFFSETFROM:+0300 -TZOFFSETTO:+0200 -DTSTART:19450924T030000 -RDATE:19470629T030000 -END:DAYLIGHT -BEGIN:STANDARD -TZNAME:CET -TZOFFSETFROM:+0100 -TZOFFSETTO:+0100 -DTSTART:19460101T000000 -RDATE:19800101T000000 -END:STANDARD -BEGIN:STANDARD -TZNAME:CET -TZOFFSETFROM:+0200 -TZOFFSETTO:+0100 -DTSTART:19471005T030000 -RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=1SU;UNTIL=19491002T010000Z -END:STANDARD -BEGIN:STANDARD -TZNAME:CET -TZOFFSETFROM:+0200 -TZOFFSETTO:+0100 -DTSTART:19800928T030000 -RRULE:FREQ=YEARLY;BYMONTH=9;BYDAY=-1SU;UNTIL=19950924T010000Z -END:STANDARD -BEGIN:DAYLIGHT -TZNAME:CEST -TZOFFSETFROM:+0100 -TZOFFSETTO:+0200 -DTSTART:19810329T020000 -RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU -END:DAYLIGHT -BEGIN:STANDARD -TZNAME:CET -TZOFFSETFROM:+0200 -TZOFFSETTO:+0100 -DTSTART:19961027T030000 -RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU -END:STANDARD -END:VTIMEZONE -END:VCALENDAR - - - https://www.iana.org/time-zones - - Europe/Berlin - 0 - - - - - - - - - - i;ascii-casemap - i;octet - - 10000000 - - - - - - - - - - - - - - - - - - -2621430101T000000Z - +2621421231T235959Z - github.com/lennart-k/rustical/ns/0 - github.com/lennart-k/rustical/ns/0 - - - - [PUSH_TOPIC] - - - 1 - - - 1 - - - - - - - Calendar - - /caldav/principal/user/ - - - - - - - - /caldav/principal/user/ - - - HTTP/1.1 200 OK - - diff --git a/src/integration_tests/carddav/mod.rs b/src/integration_tests/carddav/mod.rs index 3e3af8a..d55ae82 100644 --- a/src/integration_tests/carddav/mod.rs +++ b/src/integration_tests/carddav/mod.rs @@ -4,16 +4,17 @@ use axum::extract::Request; use headers::{Authorization, HeaderMapExt}; use http::StatusCode; use rstest::rstest; +use rustical_store_sqlite::tests::{TestStoreContext, test_store_context}; use tower::ServiceExt; #[rstest] #[tokio::test] async fn test_carddav_root( - #[from(get_app)] + #[from(test_store_context)] #[future] - app: axum::Router, + context: TestStoreContext, ) { - let app = app.await; + let app = get_app(context.await); let request_template = || { Request::builder() diff --git a/src/integration_tests/mod.rs b/src/integration_tests/mod.rs index fb0c628..17c0d1f 100644 --- a/src/integration_tests/mod.rs +++ b/src/integration_tests/mod.rs @@ -3,44 +3,24 @@ use axum::extract::Request; use axum::{body::Body, response::Response}; use rstest::rstest; use rustical_frontend::FrontendConfig; -use rustical_store_sqlite::{ - SqliteStore, - addressbook_store::SqliteAddressbookStore, - calendar_store::SqliteCalendarStore, - principal_store::SqlitePrincipalStore, - tests::{ - get_test_addressbook_store, get_test_calendar_store, get_test_principal_store, - get_test_subscription_store, - }, -}; +use rustical_store_sqlite::tests::{TestStoreContext, test_store_context}; use std::sync::Arc; use tower::ServiceExt; -#[rstest::fixture] -pub async fn get_app( - #[from(get_test_calendar_store)] - #[future] - cal_store: SqliteCalendarStore, - #[from(get_test_addressbook_store)] - #[future] - addr_store: SqliteAddressbookStore, - #[from(get_test_principal_store)] - #[future] - principal_store: SqlitePrincipalStore, - #[from(get_test_subscription_store)] - #[future] - sub_store: SqliteStore, -) -> axum::Router { - let addr_store = Arc::new(addr_store.await); - let cal_store = Arc::new(cal_store.await); - let sub_store = Arc::new(sub_store.await); - let principal_store = Arc::new(principal_store.await); - - make_app( +pub fn get_app(context: TestStoreContext) -> axum::Router { + let TestStoreContext { addr_store, cal_store, - sub_store, principal_store, + sub_store, + .. + } = context; + + make_app( + Arc::new(addr_store), + Arc::new(cal_store), + Arc::new(sub_store), + Arc::new(principal_store), FrontendConfig { enabled: true, allow_password_login: true, @@ -70,11 +50,11 @@ impl ResponseExtractString for Response { #[rstest] #[tokio::test] async fn test_ping( - #[from(get_app)] + #[from(test_store_context)] #[future] - app: axum::Router, + context: TestStoreContext, ) { - let app = app.await; + let app = get_app(context.await); let response = app .oneshot(Request::builder().uri("/ping").body(Body::empty()).unwrap())