Merge server integration tests into one binary

Each test binary links the whole server statically. CI linked 17 of
them in parallel, and ld was OOM-killed at the 6g container limit.
The tests now build into one `api` binary. api_spa.rs stays separate
because it sets the process-wide DOVENEST_DIST variable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AuthorKonata <konata@posteo.jp>
Date
Commit62d98a9f6c8703a0ab9e0ddf72da564130bb7417
Parent0d15a4d
21 files changed, 43 insertions(+), 52 deletions(-)
▾MREADME.md
@@ -565,7 +565,7 @@ Tests live in `server/tests` and run against an in-process server with a
temporary root. CI runs on Hearthforge, see `.hearthforge-ci.toml`.
No test drives a real authenticator, so nothing here verifies a WebAuthn
signature — that is `webauthn-rs`' own job. `server/tests/api_passkeys.rs`
signature — that is `webauthn-rs`' own job. `server/tests/api/passkeys.rs`
covers everything around it: which credential combinations the server
accepts, which it refuses, and that a half-finished sign-in never becomes a
session.
▾Mpimdav/README.md
@@ -660,7 +660,7 @@ cargo test -p pimdav
| `tests/itip.rs` | Scheduling messages and copies |
| `tests/principal.rs` | Principal search, system address book cards |
The server's end-to-end tests are `server/tests/api_pim*.rs`.
The server's end-to-end tests are `server/tests/api/pim*.rs`.
### The corpus test
▾Rserver/tests/api/admin.rs← server/tests/api_admin.rs
@@ -1,9 +1,7 @@
//! Admin API: user management, lockout guards, server settings.
mod common;
use crate::common::*;
use axum::http::StatusCode;
use common::*;
use serde_json::json;
#[tokio::test]
▾Rserver/tests/api/app_passwords.rs← server/tests/api_app_passwords.rs
@@ -1,10 +1,8 @@
//! App passwords: the self-service routes, and what they do at the WebDAV
//! mount.
mod common;
use crate::common::*;
use axum::http::{Method, StatusCode};
use common::*;
use serde_json::json;
const ROUTE: &str = "/api/auth/app-passwords";
▾Rserver/tests/api/auth.rs← server/tests/api_auth.rs
@@ -1,11 +1,9 @@
//! Authentication: first-boot setup, login, session, logout, disabling.
mod common;
use std::sync::Arc;
use crate::common::*;
use axum::http::StatusCode;
use common::*;
use serde_json::json;
#[tokio::test]
▾Rserver/tests/api/dav.rs← server/tests/api_dav.rs
@@ -1,10 +1,8 @@
//! The WebDAV mounts: Basic auth, root scoping, the synthetic top level,
//! reads and writes, and the share mount.
mod common;
use crate::common::*;
use axum::http::{Method, StatusCode};
use common::*;
use serde_json::json;
fn method(name: &str) -> Method {
▾Rserver/tests/api/embedded.rs← server/tests/api_embedded.rs
@@ -7,10 +7,8 @@
//! the full server suite against the embedded assets.
#![cfg(feature = "embedded")]
mod common;
use crate::common::*;
use axum::http::StatusCode;
use common::*;
/// Absolute (`/...`) `src`/`href` asset references in the built index.html.
fn asset_refs(html: &str) -> Vec<String> {
▾Rserver/tests/api/files.rs← server/tests/api_files.rs
@@ -1,10 +1,8 @@
//! File API: listing, download/preview/content, editor save, mutations,
//! upload, access control and path-safety.
mod common;
use crate::common::*;
use axum::http::StatusCode;
use common::*;
use serde_json::json;
/// Root id for the whole-root (".") user root is 1 (first row inserted).
▾Aserver/tests/api/main.rs
@@ -0,0 +1,23 @@
//! Server integration tests. One binary on purpose: each test binary links
//! the whole server statically, and parallel links ran CI out of memory.
//! `api_spa.rs` stays separate because it sets a process-wide env var.
#[path = "../common/mod.rs"]
mod common;
mod admin;
mod app_passwords;
mod auth;
mod dav;
mod embedded;
mod files;
mod passkeys;
mod pim;
mod pim_clients;
mod pim_derived;
mod pim_io;
mod pim_schedule;
mod pim_ui;
mod search;
mod shares;
mod thumbs;
▾Rserver/tests/api/passkeys.rs← server/tests/api_passkeys.rs
@@ -6,10 +6,8 @@
//! everything around it: which combinations the server accepts, what it
//! refuses, and that a half-finished sign-in never becomes a session.
mod common;
use crate::common::*;
use axum::http::{Method, StatusCode};
use common::*;
use serde_json::json;
/// A syntactically valid stored passkey.
▾Rserver/tests/api/pim.rs← server/tests/api_pim.rs
@@ -1,9 +1,7 @@
//! CalDAV and CardDAV: discovery, collections, properties and objects.
mod common;
use crate::common::*;
use axum::http::{Method, StatusCode};
use common::*;
use pimdav::xml::{self, APPLE, CALDAV, CALSERVER, CARDDAV, DAV, Name};
use serde_json::json;
use xmltree::Element;
▾Rserver/tests/api/pim_clients.rs← server/tests/api_pim_clients.rs
@@ -2,10 +2,8 @@
//! the server root, client properties, vCard 3.0 for Apple, and addresses
//! and logins for unusual account names.
mod common;
use crate::common::*;
use axum::http::{Method, StatusCode};
use common::*;
use pimdav::xml::{self, CALDAV, CALSERVER, CARDDAV, DAV, Name};
use serde_json::json;
use xmltree::Element;
▾Rserver/tests/api/pim_derived.rs← server/tests/api_pim_derived.rs
@@ -2,11 +2,9 @@
//! calendar, the cleanup after a deleted principal, and the admin view of
//! public feeds.
mod common;
use crate::common::*;
use axum::http::{Method, StatusCode};
use base64::Engine;
use common::*;
use pimdav::xml::{self, DAV};
use serde_json::json;
use xmltree::Element;
▾Rserver/tests/api/pim_io.rs← server/tests/api_pim_io.rs
@@ -1,9 +1,7 @@
//! Public feeds, import and export of calendars and address books.
mod common;
use crate::common::*;
use axum::http::{Method, StatusCode};
use common::*;
use serde_json::{Value, json};
const PW: &str = "secret12345";
▾Rserver/tests/api/pim_schedule.rs← server/tests/api_pim_schedule.rs
@@ -1,10 +1,8 @@
//! Implicit scheduling (RFC 6638) between the accounts and rooms of one
//! server.
mod common;
use crate::common::*;
use axum::http::{Method, StatusCode};
use common::*;
use pimdav::xml::{self, CALDAV, DAV, Name};
use serde_json::json;
use xmltree::Element;
▾Rserver/tests/api/pim_ui.rs← server/tests/api_pim_ui.rs
@@ -1,9 +1,7 @@
//! The JSON endpoints behind the calendar and contacts web UI.
mod common;
use crate::common::*;
use axum::http::{Method, StatusCode};
use common::*;
use serde_json::{Value, json};
const PW: &str = "secret12345";
▾Rserver/tests/api/search.rs← server/tests/api_search.rs
@@ -1,9 +1,7 @@
//! Search API: one walk serves both scopes, streamed as SSE.
mod common;
use crate::common::*;
use axum::http::StatusCode;
use common::*;
/// Root id for the whole-root (".") user root is 1 (first row inserted).
const ROOT: i64 = 1;
▾Rserver/tests/api/shares.rs← server/tests/api_shares.rs
@@ -1,10 +1,8 @@
//! Token-based shares: creation (incl. writable gating), public resolve,
//! anonymous access via `?share=`, expiry, scoping, deletion.
mod common;
use crate::common::*;
use axum::http::StatusCode;
use common::*;
use serde_json::json;
/// Create a share via the admin (who has the whole root).
▾Rserver/tests/api/thumbs.rs← server/tests/api_thumbs.rs
@@ -1,9 +1,7 @@
//! Thumbnail endpoint: what gets one, what does not, and the cache.
mod common;
use crate::common::*;
use axum::http::StatusCode;
use common::*;
const ROOT: i64 = 1;
▾Mserver/tests/api_spa.rs
@@ -3,7 +3,7 @@
//! tempdir so the test is independent of any built frontend.
//!
//! Disabled under `--features embedded` (assets come from rust-embed, not
//! $DOVENEST_DIST) — see `api_embedded.rs` for the production variant.
//! $DOVENEST_DIST) — see `api/embedded.rs` for the production variant.
#![cfg(not(feature = "embedded"))]
mod common;
▾Mserver/tests/common/mod.rs
@@ -1,7 +1,7 @@
//! Shared integration-test harness: drives the real router with
//! `tower::ServiceExt::oneshot` — no ports, no network, fully parallel.
//
// Every test binary compiles this module privately, so helpers unused by a
// Each test binary compiles this module privately, so helpers unused by a
// particular binary would warn as dead code.
#![allow(dead_code)]