fix: real AP id tests, exact poster key check, exists port, list_movies fake
This commit is contained in:
@@ -54,7 +54,6 @@ impl EventHandler for FollowBackfillHandler {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use domain::models::FollowedActorInfo;
|
||||
@@ -63,16 +62,16 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Models the real port: imports are keyed upserts and backfill sends carry
|
||||
/// deterministic activity ids, so a repeat lands on the same key.
|
||||
/// The handler has no state of its own: idempotency lives behind the port
|
||||
/// (remote imports are keyed upserts; backfill Creates use the deterministic
|
||||
/// k-ap id `activities/create/{uuidv5(object id)}`, see activitypub
|
||||
/// `tests/activity_ids.rs`). What this proves is that a redelivery replays
|
||||
/// exactly the same port calls, with no accumulated or derived state.
|
||||
#[derive(Default)]
|
||||
struct KeyedBackfill {
|
||||
imported: Mutex<HashSet<(String, String)>>,
|
||||
sent: Mutex<HashSet<(Uuid, String)>>,
|
||||
}
|
||||
struct CallLog(Mutex<Vec<String>>);
|
||||
|
||||
#[async_trait]
|
||||
impl ApBackfillPort for KeyedBackfill {
|
||||
impl ApBackfillPort for CallLog {
|
||||
async fn get_following(&self, _: Uuid) -> Result<Vec<FollowedActorInfo>, DomainError> {
|
||||
Ok(vec![FollowedActorInfo {
|
||||
url: "https://remote.example/users/a".into(),
|
||||
@@ -80,10 +79,10 @@ mod tests {
|
||||
}])
|
||||
}
|
||||
async fn import_remote_outbox(&self, outbox: &str, actor: &str) -> Result<(), DomainError> {
|
||||
self.imported
|
||||
self.0
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert((outbox.into(), actor.into()));
|
||||
.push(format!("import {outbox} {actor}"));
|
||||
Ok(())
|
||||
}
|
||||
async fn run_backfill_for_follower(
|
||||
@@ -91,35 +90,42 @@ mod tests {
|
||||
owner: Uuid,
|
||||
inbox: String,
|
||||
) -> Result<(), DomainError> {
|
||||
self.sent.lock().unwrap().insert((owner, inbox));
|
||||
self.0
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push(format!("backfill {owner} {inbox}"));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn follow_backfill_is_idempotent_when_run_twice() {
|
||||
let port = Arc::new(KeyedBackfill::default());
|
||||
async fn follow_backfill_replays_identical_port_calls_when_run_twice() {
|
||||
let port = Arc::new(CallLog::default());
|
||||
let handler = FollowBackfillHandler {
|
||||
backfill: port.clone(),
|
||||
};
|
||||
let owner = UserId::from_uuid(Uuid::new_v4());
|
||||
let accepted = DomainEvent::FollowAccepted {
|
||||
owner: owner.clone(),
|
||||
requester: SocialIdentity::Remote {
|
||||
actor_url: "https://remote.example/users/a".into(),
|
||||
let events = [
|
||||
DomainEvent::FollowAccepted {
|
||||
owner: owner.clone(),
|
||||
requester: SocialIdentity::Remote {
|
||||
actor_url: "https://remote.example/users/a".into(),
|
||||
},
|
||||
},
|
||||
};
|
||||
let backfill = DomainEvent::BackfillFollower {
|
||||
owner_user_id: owner,
|
||||
follower_inbox_url: "https://remote.example/inbox".into(),
|
||||
};
|
||||
DomainEvent::BackfillFollower {
|
||||
owner_user_id: owner,
|
||||
follower_inbox_url: "https://remote.example/inbox".into(),
|
||||
},
|
||||
];
|
||||
|
||||
for event in [&accepted, &backfill] {
|
||||
for event in &events {
|
||||
let start = port.0.lock().unwrap().len();
|
||||
handler.handle(event).await.unwrap();
|
||||
let mid = port.0.lock().unwrap().len();
|
||||
handler.handle(event).await.unwrap();
|
||||
let log = port.0.lock().unwrap().clone();
|
||||
assert!(mid > start, "the event reaches the port");
|
||||
assert_eq!(log[start..mid], log[mid..]);
|
||||
}
|
||||
|
||||
assert_eq!(port.imported.lock().unwrap().len(), 1);
|
||||
assert_eq!(port.sent.lock().unwrap().len(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user