Skip to content

Commit 74cab84

Browse files
committed
Verify Accept delivery in relay approval tests
Record deliveries to Alice's inbox and assert that approved follows produce exactly one Accept POST from the relay for the expected Follow. Cover subscription approval, public follows, and malformed follower rows. Use unique Follow IDs to isolate concurrent tests and loop iterations. #1046 Validated with mise run test-each relay, including code checks and Deno, Node.js, and Bun tests. Changelog: none Assisted-by: Codex:gpt-6-astra
1 parent c83fe40 commit 74cab84

2 files changed

Lines changed: 63 additions & 5 deletions

File tree

‎packages/relay/src/litepub.test.ts‎

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,25 @@ function recordInbox(inbox: string): DeliveredRequest[] {
142142
return recorded;
143143
}
144144

145+
const aliceDeliveries = recordInbox(aliceInbox);
146+
147+
function assertAcceptDelivered(
148+
follow: Follow,
149+
deliveries: readonly DeliveredRequest[] = aliceDeliveries,
150+
): void {
151+
const accepts = deliveries.filter(({ body }) =>
152+
body.type === "Accept" && body.object?.id === follow.id?.href
153+
);
154+
strictEqual(accepts.length, 1, "Expected exactly one Accept for this Follow");
155+
strictEqual(accepts[0].method, "POST");
156+
strictEqual(accepts[0].body.actor, "https://relay.example.com/users/relay");
157+
strictEqual(accepts[0].body.object.type, "Follow");
158+
strictEqual(
159+
accepts[0].body.object.actor?.id ?? accepts[0].body.object.actor,
160+
follow.actorId?.href,
161+
);
162+
}
163+
145164
const nextFetch = globalThis.fetch;
146165
globalThis.fetch = (async (input: URL | RequestInfo, init?: RequestInit) => {
147166
const request = input instanceof Request ? input : new Request(input, init);
@@ -361,7 +380,10 @@ describe("LitePubRelay", () => {
361380
});
362381

363382
const followActivity = new Follow({
364-
id: new URL("https://remote.example.com/activities/follow/1"),
383+
// Isolate delivery assertions from other tests and loop iterations.
384+
id: new URL(
385+
`https://remote.example.com/activities/follow/${crypto.randomUUID()}`,
386+
),
365387
actor: follower.id,
366388
object: new URL("https://relay.example.com/users/relay"),
367389
});
@@ -385,6 +407,7 @@ describe("LitePubRelay", () => {
385407
const deliveredActivities = recordInbox(daveInbox);
386408
const response = await relay.fetch(request);
387409
strictEqual(response.status, 202);
410+
assertAcceptDelivered(followActivity, deliveredActivities);
388411

389412
// Verify handler was called
390413
strictEqual(handlerCalled, true);
@@ -487,7 +510,10 @@ describe("LitePubRelay", () => {
487510

488511
// Public follow activity
489512
const followActivity = new Follow({
490-
id: new URL("https://remote.example.com/activities/follow/1"),
513+
// Isolate delivery assertions from other tests and loop iterations.
514+
id: new URL(
515+
`https://remote.example.com/activities/follow/${crypto.randomUUID()}`,
516+
),
491517
actor: follower.id,
492518
object: new URL("https://www.w3.org/ns/activitystreams#Public"),
493519
});
@@ -510,6 +536,7 @@ describe("LitePubRelay", () => {
510536

511537
const response = await relay.fetch(request);
512538
strictEqual(response.status, 202);
539+
assertAcceptDelivered(followActivity);
513540

514541
// Verify follower was stored with "pending" state
515542
const followerData = await kv.get([
@@ -594,7 +621,10 @@ describe("LitePubRelay", () => {
594621
strictEqual(await relay.getFollower(followerId), null);
595622

596623
const followActivity = new Follow({
597-
id: new URL("https://remote.example.com/activities/follow/1"),
624+
// Isolate delivery assertions from other tests and loop iterations.
625+
id: new URL(
626+
`https://remote.example.com/activities/follow/${crypto.randomUUID()}`,
627+
),
598628
actor: new URL(followerId),
599629
object: new URL("https://relay.example.com/users/relay"),
600630
});
@@ -613,6 +643,7 @@ describe("LitePubRelay", () => {
613643

614644
const response = await relay.fetch(request);
615645
strictEqual(response.status, 202);
646+
assertAcceptDelivered(followActivity);
616647

617648
strictEqual(handlerCallCount, 1);
618649
const follower = await relay.getFollower(followerId);

‎packages/relay/src/mastodon.test.ts‎

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,25 @@ function recordInbox(inbox: string): DeliveredRequest[] {
108108
return recorded;
109109
}
110110

111+
const aliceDeliveries = recordInbox(aliceInbox);
112+
113+
function assertAcceptDelivered(
114+
follow: Follow,
115+
deliveries: readonly DeliveredRequest[] = aliceDeliveries,
116+
): void {
117+
const accepts = deliveries.filter(({ body }) =>
118+
body.type === "Accept" && body.object?.id === follow.id?.href
119+
);
120+
strictEqual(accepts.length, 1, "Expected exactly one Accept for this Follow");
121+
strictEqual(accepts[0].method, "POST");
122+
strictEqual(accepts[0].body.actor, "https://relay.example.com/users/relay");
123+
strictEqual(accepts[0].body.object.type, "Follow");
124+
strictEqual(
125+
accepts[0].body.object.actor?.id ?? accepts[0].body.object.actor,
126+
follow.actorId?.href,
127+
);
128+
}
129+
111130
const nextFetch = globalThis.fetch;
112131
globalThis.fetch = (async (input: URL | RequestInfo, init?: RequestInit) => {
113132
const request = input instanceof Request ? input : new Request(input, init);
@@ -406,7 +425,10 @@ describe("MastodonRelay", () => {
406425
});
407426

408427
const followActivity = new Follow({
409-
id: new URL("https://remote.example.com/activities/follow/1"),
428+
// Isolate delivery assertions from other tests and loop iterations.
429+
id: new URL(
430+
`https://remote.example.com/activities/follow/${crypto.randomUUID()}`,
431+
),
410432
actor: follower.id,
411433
object: new URL("https://relay.example.com/users/relay"),
412434
});
@@ -429,6 +451,7 @@ describe("MastodonRelay", () => {
429451

430452
const response = await relay.fetch(request);
431453
strictEqual(response.status, 202);
454+
assertAcceptDelivered(followActivity);
432455

433456
// Verify handler was called
434457
strictEqual(handlerCalled, true);
@@ -858,7 +881,10 @@ describe("MastodonRelay", () => {
858881

859882
// Public follow activity
860883
const followActivity = new Follow({
861-
id: new URL("https://remote.example.com/activities/follow/1"),
884+
// Isolate delivery assertions from other tests and loop iterations.
885+
id: new URL(
886+
`https://remote.example.com/activities/follow/${crypto.randomUUID()}`,
887+
),
862888
actor: follower.id,
863889
object: new URL("https://www.w3.org/ns/activitystreams#Public"),
864890
});
@@ -881,6 +907,7 @@ describe("MastodonRelay", () => {
881907

882908
const response = await relay.fetch(request);
883909
strictEqual(response.status, 202);
910+
assertAcceptDelivered(followActivity);
884911

885912
// Verify follower was stored
886913
const followerData = await kv.get([

0 commit comments

Comments
 (0)