Server overhaul: one test harness in tests/common for every test binary

core_api/common.rs becomes tests/common/mod.rs and sync_api/m4.rs tests/common/sync_fixtures.rs; each binary
includes them through #[path] (the binaries of SPEC §14.7 stay as they are). TempDir's Default moves into the
harness instead of three copies; the skeleton helpers take ids, tokens and TempDir from it. Milestone wording in
test docs and the server README replaced by what the code does; README seams and test layout updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
2026-10-18 22:31:04 +02:00
parent 6c405e142d
commit 8cb42f85a9
19 changed files with 118 additions and 146 deletions
@@ -3,7 +3,7 @@
use serde_json::json;
use crate::common::*;
use crate::m4::*;
use crate::sync_fixtures::*;
const T0: &str = "2026-10-17T10:00:00.000Z";
@@ -24,7 +24,7 @@ fn delete(id: &str, at: &str) -> serde_json::Value {
#[tokio::test]
async fn both_users_edit_offline_the_later_updated_at_wins_in_either_arrival_order() {
for later_arrives_first in [true, false] {
let app = crate::m4::app().await;
let app = crate::sync_fixtures::app().await;
let id = new_id();
push_one(&app, &admin_token(), exp(expense(&id, T0))).await;
let anna = exp(edit(&id, "2026-10-17T11:00:00.000Z", "Anna's"));
@@ -50,7 +50,7 @@ async fn both_users_edit_offline_the_later_updated_at_wins_in_either_arrival_ord
#[tokio::test]
async fn one_deletes_the_other_edits_delete_wins_regardless_of_order_and_timestamps() {
// Delete first, then a newer edit: rejected deleted.
let app = crate::m4::app().await;
let app = crate::sync_fixtures::app().await;
let id = new_id();
push_one(&app, &admin_token(), exp(expense(&id, T0))).await;
accepted(
@@ -69,7 +69,7 @@ async fn one_deletes_the_other_edits_delete_wins_regardless_of_order_and_timesta
.await;
rejected(&r, "deleted");
// Edit first, then an older delete: applied.
let app = crate::m4::app().await;
let app = crate::sync_fixtures::app().await;
let id = new_id();
push_one(&app, &admin_token(), exp(expense(&id, T0))).await;
accepted(
@@ -94,7 +94,7 @@ async fn one_deletes_the_other_edits_delete_wins_regardless_of_order_and_timesta
#[tokio::test]
async fn same_user_on_two_devices_is_lww_per_row() {
let app = crate::m4::app().await;
let app = crate::sync_fixtures::app().await;
// A second, non-revoked device of the admin.
let second = token('S');
app.insert_device(
@@ -129,7 +129,7 @@ async fn same_user_on_two_devices_is_lww_per_row() {
#[tokio::test]
async fn an_expense_in_an_account_deleted_meanwhile_is_reference_not_found_archived_category_accepted()
{
let app = crate::m4::app().await;
let app = crate::sync_fixtures::app().await;
tombstone(&app, "accounts", ACCOUNT_1).await;
rejected(
&push_one(&app, &admin_token(), exp(expense(&new_id(), T0))).await,
@@ -150,7 +150,7 @@ async fn an_expense_in_an_account_deleted_meanwhile_is_reference_not_found_archi
async fn epoch_recovery_re_push_of_identical_rows_comes_back_stale_with_equal_content() {
// §14.4.8: after a restore the phone re-pushes everything; identical rows are stale with current equal to the
// pushed client-writable fields (the phone treats that as accepted), missing rows are inserted.
let app = crate::m4::app().await;
let app = crate::sync_fixtures::app().await;
let kept = new_id();
let entity = expense(&kept, T0);
push_one(&app, &admin_token(), exp(entity.clone())).await;