strip session-added comments
This commit is contained in:
@@ -1,6 +1,3 @@
|
||||
//! The purge removes every row a deleted account owns, strips the user row to
|
||||
//! a data-free tombstone, and the cleanup later drops the tombstone itself.
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -69,8 +66,6 @@ struct Seeded {
|
||||
movie_id: String,
|
||||
}
|
||||
|
||||
/// Alice owns a row in every table; bob has a little of everything, including
|
||||
/// a follow of alice and an announce of his own review, which must survive.
|
||||
async fn seed(pool: &SqlitePool, parts: &sqlite::SqliteWireOutput) -> Seeded {
|
||||
let alice = test_user("alice");
|
||||
let bob = test_user("bob");
|
||||
@@ -205,7 +200,6 @@ async fn seed(pool: &SqlitePool, parts: &sqlite::SqliteWireOutput) -> Seeded {
|
||||
follower_actor_url: REMOTE_ACTOR.into(),
|
||||
status: FollowStatus::Accepted,
|
||||
},
|
||||
// bob follows alice, and alice follows bob
|
||||
FollowWrite::AddFollow {
|
||||
follower_id: b.value(),
|
||||
target_actor_url: alice_actor.clone(),
|
||||
@@ -221,7 +215,6 @@ async fn seed(pool: &SqlitePool, parts: &sqlite::SqliteWireOutput) -> Seeded {
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// A remote review attributed to the same account id is not the user's.
|
||||
exec(
|
||||
pool,
|
||||
"INSERT INTO reviews (id, movie_id, user_id, rating, comment, watched_at, created_at, remote_actor_url)
|
||||
@@ -234,7 +227,6 @@ async fn seed(pool: &SqlitePool, parts: &sqlite::SqliteWireOutput) -> Seeded {
|
||||
],
|
||||
)
|
||||
.await;
|
||||
// Announces of alice's review and goal, of bob's review, and one by alice.
|
||||
let alice_review: String =
|
||||
sqlx::query_scalar("SELECT id FROM reviews WHERE user_id = ? AND remote_actor_url IS NULL")
|
||||
.bind(&a_str)
|
||||
@@ -352,7 +344,6 @@ async fn purge_removes_every_user_owned_row() {
|
||||
purger(&pool).purge(&s.user).await.unwrap();
|
||||
|
||||
for (table, column) in PURGED_USER_TABLES {
|
||||
// Reviews: only the remote one, asserted below, is left.
|
||||
let left = if *table == "reviews" { 1 } else { 0 };
|
||||
assert_eq!(
|
||||
count_for(&pool, table, column, &s.user).await,
|
||||
@@ -406,14 +397,12 @@ async fn purge_removes_every_user_owned_row() {
|
||||
"finished rows mentioning the user are gone; pending/processing rows (incl. other users' events about her) and bob's own rows stay"
|
||||
);
|
||||
|
||||
// The other account is untouched.
|
||||
for (table, column) in PURGED_USER_TABLES {
|
||||
assert!(
|
||||
count_for(&pool, table, column, &s.other).await > 0,
|
||||
"{table} of the other user must survive"
|
||||
);
|
||||
}
|
||||
// The keypair stays for queued deliveries.
|
||||
for table in RETAINED_USER_TABLES {
|
||||
assert_eq!(count_for(&pool, table, "user_id", &s.user).await, 1);
|
||||
}
|
||||
@@ -458,8 +447,6 @@ async fn the_purge_table_lists_cover_every_user_referencing_column_in_the_schema
|
||||
"{t} has a foreign key to users but is not in the purge lists"
|
||||
);
|
||||
}
|
||||
// Columns the purge matches by URL or payload must still exist, so a
|
||||
// rename fails here instead of silently leaving rows behind.
|
||||
for (table, column) in URL_KEYED_USER_COLUMNS
|
||||
.iter()
|
||||
.chain(PAYLOAD_KEYED_USER_COLUMNS)
|
||||
@@ -474,9 +461,6 @@ async fn the_purge_table_lists_cover_every_user_referencing_column_in_the_schema
|
||||
}
|
||||
}
|
||||
|
||||
/// `ap_activities` (k-ap's inbound dedup) holds only remote activity ids and a
|
||||
/// timestamp: nothing in it is attributable to a local user. If it ever grows a
|
||||
/// column, the purge must start clearing it.
|
||||
#[tokio::test]
|
||||
async fn ap_activities_holds_nothing_attributable_to_a_local_user() {
|
||||
let pool = migrated_pool().await;
|
||||
@@ -555,7 +539,6 @@ async fn purge_strips_the_user_row_but_keeps_the_username_and_state() {
|
||||
.await
|
||||
.unwrap()
|
||||
);
|
||||
// Images stay referenced until the objects are gone.
|
||||
let mut keys = p.owned_image_keys(&s.user).await.unwrap();
|
||||
keys.sort();
|
||||
assert_eq!(keys, vec!["avatars/a.webp", "banners/a.webp"]);
|
||||
@@ -571,8 +554,6 @@ async fn purging_twice_is_a_no_op() {
|
||||
parts.user.mark_deleted(&s.user, &[]).await.unwrap();
|
||||
let p = purger(&pool);
|
||||
p.purge(&s.user).await.unwrap();
|
||||
// New data cannot appear for a purged account, but a re-run must not
|
||||
// touch anything else or fail.
|
||||
let before: i64 = count(&pool, "SELECT COUNT(*) FROM reviews").await;
|
||||
let stamp: String = sqlx::query_scalar("SELECT purged_at FROM users WHERE id = ?")
|
||||
.bind(s.user.value().to_string())
|
||||
@@ -589,7 +570,6 @@ async fn purging_twice_is_a_no_op() {
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(stamp, again);
|
||||
// And an id that never existed is fine too.
|
||||
p.purge(&UserId::generate()).await.unwrap();
|
||||
}
|
||||
|
||||
@@ -666,7 +646,6 @@ async fn tombstone_cleanup_removes_rows_older_than_retention_and_keeps_younger_o
|
||||
)
|
||||
.await;
|
||||
|
||||
// Younger than the cutoff: kept.
|
||||
let removed = p
|
||||
.purge_expired_tombstones(now - chrono::Duration::days(9))
|
||||
.await
|
||||
@@ -674,9 +653,6 @@ async fn tombstone_cleanup_removes_rows_older_than_retention_and_keeps_younger_o
|
||||
assert_eq!(removed, 0);
|
||||
assert_eq!(count_for(&pool, "users", "id", &s.user).await, 1);
|
||||
|
||||
// Unfinished events still name the user (the pending Delete, bob's
|
||||
// pending FollowRequested, a processing row): the tombstone waits and no
|
||||
// unfinished row is ever deleted.
|
||||
let alice = s.user.value().to_string();
|
||||
let unfinished = || async {
|
||||
sqlx::query_scalar::<_, i64>(
|
||||
@@ -696,7 +672,6 @@ async fn tombstone_cleanup_removes_rows_older_than_retention_and_keeps_younger_o
|
||||
assert_eq!(count_for(&pool, "users", "id", &s.user).await, 1);
|
||||
assert_eq!(unfinished().await, before);
|
||||
|
||||
// A Follow that reached the shared inbox after the purge left a row.
|
||||
exec(
|
||||
&pool,
|
||||
"INSERT INTO ap_followers (local_user_id, remote_actor_url, status, created_at)
|
||||
@@ -704,7 +679,6 @@ async fn tombstone_cleanup_removes_rows_older_than_retention_and_keeps_younger_o
|
||||
&[&alice],
|
||||
)
|
||||
.await;
|
||||
// Once they finish, the cleanup takes the tombstone and the history.
|
||||
exec(&pool, "UPDATE event_queue SET status = 'done'", &[]).await;
|
||||
let removed = p
|
||||
.purge_expired_tombstones(now - chrono::Duration::days(7))
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
//! Real-database counterpart of the `InMemoryStore` cascade tests in the domain
|
||||
//! crate. Both iterate the same table lists (`domain::testing::*_CASCADE_TABLES`),
|
||||
//! so the fake and the schema cannot drift apart unnoticed.
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -28,8 +24,6 @@ use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
||||
|
||||
const REMOTE_ACTOR: &str = "https://remote.example/users/ann";
|
||||
|
||||
/// Private in-memory database with plain `SqliteConnectOptions`; relies on
|
||||
/// sqlx's default `foreign_keys = ON`, which production also depends on.
|
||||
async fn migrated_pool() -> SqlitePool {
|
||||
let opts = SqliteConnectOptions::from_str("sqlite::memory:").unwrap();
|
||||
let pool = SqlitePoolOptions::new()
|
||||
@@ -202,7 +196,6 @@ async fn seed_user_with_dependents(
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// No repository in this crate owns these two tables (federation crate).
|
||||
sqlx::query("INSERT INTO blocked_actors (local_user_id, remote_actor_url, blocked_at) VALUES (?, ?, 'now')")
|
||||
.bind(user_id.value().to_string())
|
||||
.bind(REMOTE_ACTOR)
|
||||
|
||||
@@ -46,8 +46,6 @@ async fn insert_review(pool: &SqlitePool, movie: &MovieId) {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Mirrors what `application::movies::merge_duplicates` builds when the
|
||||
/// canonical row does not exist.
|
||||
fn canonical_from(old: &Movie, canonical_id: MovieId) -> Movie {
|
||||
Movie::from_persistence(
|
||||
canonical_id,
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! Shared helpers for the transactional-outbox repository tests.
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
use sqlx::{
|
||||
@@ -25,8 +23,6 @@ pub async fn count(pool: &SqlitePool, table: &str) -> i64 {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Makes every later `event_queue` insert abort, so a write whose own row
|
||||
/// already landed inside the transaction must be rolled back with it.
|
||||
pub async fn fail_event_inserts(pool: &SqlitePool) {
|
||||
sqlx::query(
|
||||
"CREATE TRIGGER fail_event_insert BEFORE INSERT ON event_queue \
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
//! Goal, watchlist and profile writes commit with their events or not at all.
|
||||
|
||||
use domain::{
|
||||
events::DomainEvent,
|
||||
models::{ProfileField, UserProfile, WatchlistEntry},
|
||||
@@ -796,8 +794,6 @@ async fn a_failing_follow_write_rolls_back_the_rows_already_applied() {
|
||||
use domain::ports::{FollowCommand, FollowWrite};
|
||||
let (pool, user) = pool_with_user().await;
|
||||
let mut writes = follow_writes(user.id());
|
||||
// An unknown local user violates the ap_following foreign key after the
|
||||
// follower row was already written.
|
||||
writes.push(FollowWrite::AddFollow {
|
||||
follower_id: uuid::Uuid::new_v4(),
|
||||
target_actor_url: "https://md.example/users/other".into(),
|
||||
|
||||
@@ -120,7 +120,6 @@ async fn marking_a_user_deleted_hides_them_from_every_lookup() {
|
||||
repo.save(&admin).await.unwrap();
|
||||
let other = test_user("other");
|
||||
repo.save(&other).await.unwrap();
|
||||
// A second admin, so the first is not the last one standing.
|
||||
sqlx::query("UPDATE users SET role = 'admin' WHERE id = ?")
|
||||
.bind(other.id().value().to_string())
|
||||
.execute(&pool)
|
||||
@@ -145,7 +144,6 @@ async fn marking_a_user_deleted_hides_them_from_every_lookup() {
|
||||
assert!(emails.contains(&other.email().value()));
|
||||
assert!(!emails.contains(&admin.email().value()));
|
||||
assert_eq!(repo.count_active_admins().await.unwrap(), 1);
|
||||
// The purge can still read the tombstone; a live user is not one.
|
||||
assert!(
|
||||
repo.find_tombstoned_by_id(admin.id())
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user