Skip to content

Commit

Permalink
Test handleCollection()
Browse files Browse the repository at this point in the history
  • Loading branch information
dahlia committed Mar 6, 2024
1 parent 296eb9c commit c79c9d9
Show file tree
Hide file tree
Showing 2 changed files with 257 additions and 5 deletions.
256 changes: 253 additions & 3 deletions federation/handler.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { assert, assertEquals, assertFalse } from "jsr:@std/assert@^0.218.2";
import { createRequestContext } from "../testing/context.ts";
import { Person } from "../vocab/vocab.ts";
import { ActorDispatcher } from "./callback.ts";
import { acceptsJsonLd, handleActor } from "./handler.ts";
import { Activity, Create, Person } from "../vocab/vocab.ts";
import {
ActorDispatcher,
CollectionCounter,
CollectionCursor,
CollectionDispatcher,
} from "./callback.ts";
import { acceptsJsonLd, handleActor, handleCollection } from "./handler.ts";

Deno.test("acceptsJsonLd()", () => {
assert(acceptsJsonLd(
Expand Down Expand Up @@ -107,6 +112,10 @@ Deno.test("handleActor()", async () => {
},
);
assertEquals(response.status, 200);
assertEquals(
response.headers.get("Content-Type"),
"application/activity+json",
);
assertEquals(await response.json(), {
"@context": [
"https://www.w3.org/ns/activitystreams",
Expand Down Expand Up @@ -140,3 +149,244 @@ Deno.test("handleActor()", async () => {
assertEquals(onNotFoundCalled, context.request);
assertEquals(onNotAcceptableCalled, null);
});

Deno.test("handleCollection()", async () => {
let context = createRequestContext<void>({
data: undefined,
url: new URL("https://example.com/"),
getActorUri(handle) {
return new URL(`https://example.com/users/${handle}`);
},
});
const dispatcher: CollectionDispatcher<Activity, void> = (
_ctx,
handle,
cursor,
) => {
if (handle !== "someone") return null;
const items = [
new Create({ id: new URL("https://example.com/activities/1") }),
new Create({ id: new URL("https://example.com/activities/2") }),
new Create({ id: new URL("https://example.com/activities/3") }),
];
if (cursor != null) {
const idx = parseInt(cursor);
return {
items: [items[idx]],
nextCursor: idx < items.length - 1 ? (idx + 1).toString() : null,
prevCursor: idx > 0 ? (idx - 1).toString() : null,
};
}
return { items };
};
const counter: CollectionCounter<void> = (_ctx, handle) =>
handle === "someone" ? 3 : null;
const firstCursor: CollectionCursor<void> = (_ctx, handle) =>
handle === "someone" ? "0" : null;
const lastCursor: CollectionCursor<void> = (_ctx, handle) =>
handle === "someone" ? "2" : null;
let onNotFoundCalled: Request | null = null;
const onNotFound = (request: Request) => {
onNotFoundCalled = request;
return new Response("Not found", { status: 404 });
};
let onNotAcceptableCalled: Request | null = null;
const onNotAcceptable = (request: Request) => {
onNotAcceptableCalled = request;
return new Response("Not acceptable", { status: 406 });
};
let response = await handleCollection(
context.request,
{
context,
handle: "someone",
onNotFound,
onNotAcceptable,
},
);
assertEquals(response.status, 404);
assertEquals(onNotFoundCalled, context.request);
assertEquals(onNotAcceptableCalled, null);

onNotFoundCalled = null;
response = await handleCollection(
context.request,
{
context,
handle: "someone",
collectionCallbacks: { dispatcher },
onNotFound,
onNotAcceptable,
},
);
assertEquals(response.status, 406);
assertEquals(onNotFoundCalled, null);
assertEquals(onNotAcceptableCalled, context.request);

onNotAcceptableCalled = null;
context = createRequestContext<void>({
...context,
request: new Request(context.url, {
headers: {
Accept: "application/activity+json",
},
}),
});
response = await handleCollection(
context.request,
{
context,
handle: "no-one",
collectionCallbacks: { dispatcher },
onNotFound,
onNotAcceptable,
},
);
assertEquals(response.status, 404);
assertEquals(onNotFoundCalled, context.request);
assertEquals(onNotAcceptableCalled, null);

onNotFoundCalled = null;
response = await handleCollection(
context.request,
{
context,
handle: "someone",
collectionCallbacks: { dispatcher },
onNotFound,
onNotAcceptable,
},
);
assertEquals(response.status, 200);
assertEquals(
response.headers.get("Content-Type"),
"application/activity+json",
);
assertEquals(await response.json(), {
"@context": "https://www.w3.org/ns/activitystreams",
type: "OrderedCollection",
items: [
{ type: "Create", id: "https://example.com/activities/1" },
{ type: "Create", id: "https://example.com/activities/2" },
{ type: "Create", id: "https://example.com/activities/3" },
],
});
assertEquals(onNotFoundCalled, null);
assertEquals(onNotAcceptableCalled, null);

response = await handleCollection(
context.request,
{
context,
handle: "someone",
collectionCallbacks: {
dispatcher,
counter,
firstCursor,
lastCursor,
},
onNotFound,
onNotAcceptable,
},
);
assertEquals(response.status, 200);
assertEquals(
response.headers.get("Content-Type"),
"application/activity+json",
);
assertEquals(await response.json(), {
"@context": "https://www.w3.org/ns/activitystreams",
type: "OrderedCollection",
totalItems: 3,
first: "https://example.com/?cursor=0",
last: "https://example.com/?cursor=2",
});
assertEquals(onNotFoundCalled, null);
assertEquals(onNotAcceptableCalled, null);

let url = new URL("https://example.com/?cursor=0");
context = createRequestContext({
...context,
url,
request: new Request(url, {
headers: {
Accept: "application/activity+json",
},
}),
});
response = await handleCollection(
context.request,
{
context,
handle: "someone",
collectionCallbacks: {
dispatcher,
counter,
firstCursor,
lastCursor,
},
onNotFound,
onNotAcceptable,
},
);
assertEquals(response.status, 200);
assertEquals(
response.headers.get("Content-Type"),
"application/activity+json",
);
assertEquals(await response.json(), {
"@context": "https://www.w3.org/ns/activitystreams",
type: "OrderedCollectionPage",
partOf: "https://example.com/",
next: "https://example.com/?cursor=1",
items: {
id: "https://example.com/activities/1",
type: "Create",
},
});
assertEquals(onNotFoundCalled, null);
assertEquals(onNotAcceptableCalled, null);

url = new URL("https://example.com/?cursor=2");
context = createRequestContext({
...context,
url,
request: new Request(url, {
headers: {
Accept: "application/activity+json",
},
}),
});
response = await handleCollection(
context.request,
{
context,
handle: "someone",
collectionCallbacks: {
dispatcher,
counter,
firstCursor,
lastCursor,
},
onNotFound,
onNotAcceptable,
},
);
assertEquals(response.status, 200);
assertEquals(
response.headers.get("Content-Type"),
"application/activity+json",
);
assertEquals(await response.json(), {
"@context": "https://www.w3.org/ns/activitystreams",
type: "OrderedCollectionPage",
partOf: "https://example.com/",
prev: "https://example.com/?cursor=1",
items: {
id: "https://example.com/activities/3",
type: "Create",
},
});
assertEquals(onNotFoundCalled, null);
assertEquals(onNotAcceptableCalled, null);
});
6 changes: 4 additions & 2 deletions federation/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export async function handleCollection<
}
const { items } = page;
collection = new OrderedCollection({
totalItems: Number(totalItems),
totalItems: totalItems == null ? null : Number(totalItems),
items,
});
} else {
Expand Down Expand Up @@ -192,7 +192,9 @@ export async function handleCollection<
next = new URL(context.url);
next.searchParams.set("cursor", nextCursor);
}
collection = new OrderedCollectionPage({ prev, next, items });
const partOf = new URL(context.url);
partOf.searchParams.delete("cursor");
collection = new OrderedCollectionPage({ prev, next, items, partOf });
}
const jsonLd = await collection.toJsonLd(context);
return new Response(JSON.stringify(jsonLd), {
Expand Down

0 comments on commit c79c9d9

Please sign in to comment.