Full code coverage on read

main
jaxoncreed 2 years ago
parent e4af4f641a
commit 0c0f037786
  1. 2
      packages/solid/src/requester/results/error/HttpErrorResult.ts
  2. 7
      packages/solid/src/util/RequestBatcher.ts
  3. 2
      packages/solid/src/util/rdfUtils.ts
  4. 162
      packages/solid/test/ContainerRequester.test.ts
  5. 476
      packages/solid/test/LeafRequester.test.ts
  6. 39
      packages/solid/test/RequestBatcher.test.ts
  7. 217
      packages/solid/test/SolidLdoDataset.test.ts
  8. 7
      packages/solid/test/configs/solid-css-seed.json
  9. 27
      packages/solid/test/solidServer.helper.ts

@ -30,7 +30,7 @@ export abstract class HttpErrorResult extends ResourceError {
static isnt(response: Response) {
return (
!(response.status >= 200 || response.status < 300) &&
!(response.status >= 200 && response.status < 300) &&
response.status !== 404 &&
response.status !== 304
);

@ -35,16 +35,13 @@ export class RequestBatcher {
private currentlyProcessing: WaitingProcess<any[], any> | undefined =
undefined;
private processQueue: WaitingProcess<any[], any>[] = [];
public shouldBatchAllRequests: boolean;
public batchMillis: number;
constructor(
options?: Partial<{
shouldBatchAllRequests: boolean;
batchMillis: number;
}>,
) {
this.shouldBatchAllRequests = options?.shouldBatchAllRequests || false;
this.batchMillis = options?.batchMillis || 1000;
}
@ -56,9 +53,7 @@ export class RequestBatcher {
if (!this.processQueue[0]) {
return;
}
const processName = this.shouldBatchAllRequests
? ANY_KEY
: this.processQueue[0].name;
const processName = this.processQueue[0].name;
// Set last request timestamp if not available
if (!this.lastRequestTimestampMap[processName]) {

@ -88,7 +88,7 @@ export async function addRawTurtleToDataset(
const error = UnexpectedResourceError.fromThrown(baseUri, err);
return new NoncompliantPodError(
baseUri,
`Request at ${baseUri} returned noncompliant turtle: ${error.message}`,
`Request returned noncompliant turtle: ${error.message}`,
);
}

@ -1,88 +1,88 @@
import type { App } from "@solid/community-server";
import { getAuthenticatedFetch, ROOT_COONTAINER } from "./solidServer.helper";
import type { SolidLdoDataset } from "../src/SolidLdoDataset";
import { createSolidLdoDataset } from "../src/createSolidLdoDataset";
import { ContainerRequester } from "../src/requester/ContainerRequester";
import type { ContainerUri } from "../src/util/uriTypes";
// import type { App } from "@solid/community-server";
// import { getAuthenticatedFetch, ROOT_CONTAINER } from "./solidServer.helper";
// import type { SolidLdoDataset } from "../src/SolidLdoDataset";
// import { createSolidLdoDataset } from "../src/createSolidLdoDataset";
// import { ContainerRequester } from "../src/requester/ContainerRequester";
// import type { ContainerUri } from "../src/util/uriTypes";
describe.skip("Container Requester", () => {
let _app: App;
let authFetch: typeof fetch;
let fetchMock: typeof fetch;
let solidLdoDataset: SolidLdoDataset;
// describe.skip("Container Requester", () => {
// let _app: App;
// let authFetch: typeof fetch;
// let fetchMock: typeof fetch;
// let solidLdoDataset: SolidLdoDataset;
beforeAll(async () => {
// Start up the server
// app = await createApp();
// await app.start();
// beforeAll(async () => {
// // Start up the server
// // app = await createApp();
// // await app.start();
authFetch = await getAuthenticatedFetch();
});
// authFetch = await getAuthenticatedFetch();
// });
beforeEach(async () => {
fetchMock = jest.fn(authFetch);
solidLdoDataset = createSolidLdoDataset({ fetch: fetchMock });
// Create a new document called sample.ttl
await Promise.all([
authFetch(`${ROOT_COONTAINER}test_leaf/`, {
method: "POST",
headers: { "content-type": "text/turtle", slug: "sample.ttl" },
body: `@base <http://example.org/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix rel: <http://www.perceive.net/schemas/relationship/> .
<#green-goblin>
rel:enemyOf <#spiderman> ;
a foaf:Person ; # in the context of the Marvel universe
foaf:name "Green Goblin" .
<#spiderman>
rel:enemyOf <#green-goblin> ;
a foaf:Person ;
foaf:name "Spiderman", "Человек-паук"@ru .`,
}),
authFetch(`${ROOT_COONTAINER}test_leaf/`, {
method: "PUT",
headers: { "content-type": "text/plain", slug: "sample.txt" },
body: `some text.`,
}),
]);
});
// beforeEach(async () => {
// fetchMock = jest.fn(authFetch);
// solidLdoDataset = createSolidLdoDataset({ fetch: fetchMock });
// // Create a new document called sample.ttl
// await Promise.all([
// authFetch(`${ROOT_CONTAINER}test_leaf/`, {
// method: "POST",
// headers: { "content-type": "text/turtle", slug: "sample.ttl" },
// body: `@base <http://example.org/> .
// @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
// @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
// @prefix foaf: <http://xmlns.com/foaf/0.1/> .
// @prefix rel: <http://www.perceive.net/schemas/relationship/> .
afterEach(async () => {
await Promise.all([
authFetch(`${ROOT_COONTAINER}test_leaf/sample.ttl`, {
method: "DELETE",
}),
authFetch(`${ROOT_COONTAINER}test_leaf/sample2.ttl`, {
method: "DELETE",
}),
authFetch(`${ROOT_COONTAINER}test_leaf/sample.txt`, {
method: "DELETE",
}),
authFetch(`${ROOT_COONTAINER}test_leaf/sample2.txt`, {
method: "DELETE",
}),
]);
});
// <#green-goblin>
// rel:enemyOf <#spiderman> ;
// a foaf:Person ; # in the context of the Marvel universe
// foaf:name "Green Goblin" .
it("Checks if a root container is a root container", async () => {
const leafRequester = new ContainerRequester(
`${ROOT_COONTAINER}` as ContainerUri,
solidLdoDataset.context,
);
const result = await leafRequester.isRootContainer();
expect(result).toBe(true);
});
// <#spiderman>
// rel:enemyOf <#green-goblin> ;
// a foaf:Person ;
// foaf:name "Spiderman", "Человек-паук"@ru .`,
// }),
// authFetch(`${ROOT_COONTAINER}test_leaf/`, {
// method: "PUT",
// headers: { "content-type": "text/plain", slug: "sample.txt" },
// body: `some text.`,
// }),
// ]);
// });
it("Checks if a non root container is a root container", async () => {
const leafRequester = new ContainerRequester(
`${ROOT_COONTAINER}/test_leaf/`,
solidLdoDataset.context,
);
const result = await leafRequester.isRootContainer();
expect(result).toBe(false);
});
});
// afterEach(async () => {
// await Promise.all([
// authFetch(`${ROOT_COONTAINER}test_leaf/sample.ttl`, {
// method: "DELETE",
// }),
// authFetch(`${ROOT_COONTAINER}test_leaf/sample2.ttl`, {
// method: "DELETE",
// }),
// authFetch(`${ROOT_COONTAINER}test_leaf/sample.txt`, {
// method: "DELETE",
// }),
// authFetch(`${ROOT_COONTAINER}test_leaf/sample2.txt`, {
// method: "DELETE",
// }),
// ]);
// });
// it("Checks if a root container is a root container", async () => {
// const leafRequester = new ContainerRequester(
// `${ROOT_COONTAINER}` as ContainerUri,
// solidLdoDataset.context,
// );
// const result = await leafRequester.isRootContainer();
// expect(result).toBe(true);
// });
// it("Checks if a non root container is a root container", async () => {
// const leafRequester = new ContainerRequester(
// `${ROOT_COONTAINER}/test_leaf/`,
// solidLdoDataset.context,
// );
// const result = await leafRequester.isRootContainer();
// expect(result).toBe(false);
// });
// });

@ -1,250 +1,250 @@
import type { App } from "@solid/community-server";
import { getAuthenticatedFetch, ROOT_COONTAINER } from "./solidServer.helper";
import type { SolidLdoDataset } from "../src/SolidLdoDataset";
import { createSolidLdoDataset } from "../src/createSolidLdoDataset";
import { LeafRequester } from "../src/requester/LeafRequester";
import { namedNode, quad as createQuad } from "@rdfjs/data-model";
// import type { App } from "@solid/community-server";
// import { getAuthenticatedFetch, ROOT_COONTAINER } from "./solidServer.helper";
// import type { SolidLdoDataset } from "../src/SolidLdoDataset";
// import { createSolidLdoDataset } from "../src/createSolidLdoDataset";
// import { LeafRequester } from "../src/requester/LeafRequester";
// import { namedNode, quad as createQuad } from "@rdfjs/data-model";
describe.skip("Leaf Requester", () => {
let _app: App;
let authFetch: typeof fetch;
let fetchMock: typeof fetch;
let solidLdoDataset: SolidLdoDataset;
// describe.skip("Leaf Requester", () => {
// let _app: App;
// let authFetch: typeof fetch;
// let fetchMock: typeof fetch;
// let solidLdoDataset: SolidLdoDataset;
beforeAll(async () => {
// Start up the server
// app = await createApp();
// await app.start();
// beforeAll(async () => {
// // Start up the server
// // app = await createApp();
// // await app.start();
authFetch = await getAuthenticatedFetch();
});
// authFetch = await getAuthenticatedFetch();
// });
beforeEach(async () => {
fetchMock = jest.fn(authFetch);
solidLdoDataset = createSolidLdoDataset({ fetch: fetchMock });
// Create a new document called sample.ttl
await Promise.all([
authFetch(`${ROOT_COONTAINER}test_leaf/`, {
method: "POST",
headers: { "content-type": "text/turtle", slug: "sample.ttl" },
body: `@base <http://example.org/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix rel: <http://www.perceive.net/schemas/relationship/> .
<#green-goblin>
rel:enemyOf <#spiderman> ;
a foaf:Person ; # in the context of the Marvel universe
foaf:name "Green Goblin" .
<#spiderman>
rel:enemyOf <#green-goblin> ;
a foaf:Person ;
foaf:name "Spiderman", "Человек-паук"@ru .`,
}),
authFetch(`${ROOT_COONTAINER}test_leaf/`, {
method: "PUT",
headers: { "content-type": "text/plain", slug: "sample.txt" },
body: `some text.`,
}),
]);
});
// beforeEach(async () => {
// fetchMock = jest.fn(authFetch);
// solidLdoDataset = createSolidLdoDataset({ fetch: fetchMock });
// // Create a new document called sample.ttl
// await Promise.all([
// authFetch(`${ROOT_COONTAINER}test_leaf/`, {
// method: "POST",
// headers: { "content-type": "text/turtle", slug: "sample.ttl" },
// body: `@base <http://example.org/> .
// @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
// @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
// @prefix foaf: <http://xmlns.com/foaf/0.1/> .
// @prefix rel: <http://www.perceive.net/schemas/relationship/> .
afterEach(async () => {
await Promise.all([
authFetch(`${ROOT_COONTAINER}test_leaf/sample.ttl`, {
method: "DELETE",
}),
authFetch(`${ROOT_COONTAINER}test_leaf/sample2.ttl`, {
method: "DELETE",
}),
authFetch(`${ROOT_COONTAINER}test_leaf/sample.txt`, {
method: "DELETE",
}),
authFetch(`${ROOT_COONTAINER}test_leaf/sample2.txt`, {
method: "DELETE",
}),
]);
});
// <#green-goblin>
// rel:enemyOf <#spiderman> ;
// a foaf:Person ; # in the context of the Marvel universe
// foaf:name "Green Goblin" .
/**
* ===========================================================================
* Read
* ===========================================================================
*/
it("reads data", async () => {
const leafRequester = new LeafRequester(
`${ROOT_COONTAINER}test_leaf/sample.ttl`,
solidLdoDataset.context,
);
const result = await leafRequester.read();
expect(result.type).toBe("data");
expect(
solidLdoDataset.match(
null,
null,
null,
namedNode(`${ROOT_COONTAINER}test_leaf/sample.ttl`),
).size,
).toBe(7);
});
// <#spiderman>
// rel:enemyOf <#green-goblin> ;
// a foaf:Person ;
// foaf:name "Spiderman", "Человек-паук"@ru .`,
// }),
// authFetch(`${ROOT_COONTAINER}test_leaf/`, {
// method: "PUT",
// headers: { "content-type": "text/plain", slug: "sample.txt" },
// body: `some text.`,
// }),
// ]);
// });
it("reads data that doesn't exist", async () => {
const leafRequester = new LeafRequester(
`${ROOT_COONTAINER}test_leaf/doesnotexist.ttl`,
solidLdoDataset.context,
);
const result = await leafRequester.read();
expect(result.type).toBe("absent");
});
// afterEach(async () => {
// await Promise.all([
// authFetch(`${ROOT_COONTAINER}test_leaf/sample.ttl`, {
// method: "DELETE",
// }),
// authFetch(`${ROOT_COONTAINER}test_leaf/sample2.ttl`, {
// method: "DELETE",
// }),
// authFetch(`${ROOT_COONTAINER}test_leaf/sample.txt`, {
// method: "DELETE",
// }),
// authFetch(`${ROOT_COONTAINER}test_leaf/sample2.txt`, {
// method: "DELETE",
// }),
// ]);
// });
/**
* ===========================================================================
* Create
* ===========================================================================
*/
it("creates a data resource that doesn't exist while not overwriting", async () => {
const leafRequester = new LeafRequester(
`${ROOT_COONTAINER}test_leaf/sample2.ttl`,
solidLdoDataset.context,
);
const result = await leafRequester.createDataResource();
expect(result.type).toBe("data");
expect(
solidLdoDataset.has(
createQuad(
namedNode(`${ROOT_COONTAINER}test_leaf/`),
namedNode("http://www.w3.org/ns/ldp#contains"),
namedNode(`${ROOT_COONTAINER}test_leaf/sample2.ttl`),
namedNode(`${ROOT_COONTAINER}test_leaf/`),
),
),
).toBe(true);
});
// /**
// * ===========================================================================
// * Read
// * ===========================================================================
// */
// it("reads data", async () => {
// const leafRequester = new LeafRequester(
// `${ROOT_COONTAINER}test_leaf/sample.ttl`,
// solidLdoDataset.context,
// );
// const result = await leafRequester.read();
// expect(result.type).toBe("data");
// expect(
// solidLdoDataset.match(
// null,
// null,
// null,
// namedNode(`${ROOT_COONTAINER}test_leaf/sample.ttl`),
// ).size,
// ).toBe(7);
// });
it("creates a data resource that doesn't exist while overwriting", async () => {
const leafRequester = new LeafRequester(
`${ROOT_COONTAINER}test_leaf/sample2.ttl`,
solidLdoDataset.context,
);
const result = await leafRequester.createDataResource(true);
expect(result.type).toBe("data");
expect(
solidLdoDataset.has(
createQuad(
namedNode(`${ROOT_COONTAINER}test_leaf/`),
namedNode("http://www.w3.org/ns/ldp#contains"),
namedNode(`${ROOT_COONTAINER}test_leaf/sample2.ttl`),
namedNode(`${ROOT_COONTAINER}test_leaf/`),
),
),
).toBe(true);
});
// it("reads data that doesn't exist", async () => {
// const leafRequester = new LeafRequester(
// `${ROOT_COONTAINER}test_leaf/doesnotexist.ttl`,
// solidLdoDataset.context,
// );
// const result = await leafRequester.read();
// expect(result.type).toBe("absent");
// });
it("creates a data resource that does exist while not overwriting", async () => {
const leafRequester = new LeafRequester(
`${ROOT_COONTAINER}test_leaf/sample.ttl`,
solidLdoDataset.context,
);
const result = await leafRequester.createDataResource();
expect(result.type).toBe("data");
expect(
solidLdoDataset.has(
createQuad(
namedNode("http://example.org/#spiderman"),
namedNode("http://www.perceive.net/schemas/relationship/enemyOf"),
namedNode("http://example.org/#green-goblin"),
namedNode(`${ROOT_COONTAINER}test_leaf/sample.ttl`),
),
),
).toBe(true);
expect(
solidLdoDataset.has(
createQuad(
namedNode(`${ROOT_COONTAINER}test_leaf/`),
namedNode("http://www.w3.org/ns/ldp#contains"),
namedNode(`${ROOT_COONTAINER}test_leaf/sample.ttl`),
namedNode(`${ROOT_COONTAINER}test_leaf/`),
),
),
).toBe(true);
});
// /**
// * ===========================================================================
// * Create
// * ===========================================================================
// */
// it("creates a data resource that doesn't exist while not overwriting", async () => {
// const leafRequester = new LeafRequester(
// `${ROOT_COONTAINER}test_leaf/sample2.ttl`,
// solidLdoDataset.context,
// );
// const result = await leafRequester.createDataResource();
// expect(result.type).toBe("data");
// expect(
// solidLdoDataset.has(
// createQuad(
// namedNode(`${ROOT_COONTAINER}test_leaf/`),
// namedNode("http://www.w3.org/ns/ldp#contains"),
// namedNode(`${ROOT_COONTAINER}test_leaf/sample2.ttl`),
// namedNode(`${ROOT_COONTAINER}test_leaf/`),
// ),
// ),
// ).toBe(true);
// });
it("creates a data resource that does exist while overwriting", async () => {
const leafRequester = new LeafRequester(
`${ROOT_COONTAINER}test_leaf/sample.ttl`,
solidLdoDataset.context,
);
const result = await leafRequester.createDataResource(true);
expect(result.type).toBe("data");
expect(
solidLdoDataset.has(
createQuad(
namedNode("http://example.org/#spiderman"),
namedNode("http://www.perceive.net/schemas/relationship/enemyOf"),
namedNode("http://example.org/#green-goblin"),
namedNode(`${ROOT_COONTAINER}test_leaf/sample.ttl`),
),
),
).toBe(false);
expect(
solidLdoDataset.has(
createQuad(
namedNode(`${ROOT_COONTAINER}test_leaf/`),
namedNode("http://www.w3.org/ns/ldp#contains"),
namedNode(`${ROOT_COONTAINER}test_leaf/sample.ttl`),
namedNode(`${ROOT_COONTAINER}test_leaf/`),
),
),
).toBe(true);
});
// it("creates a data resource that doesn't exist while overwriting", async () => {
// const leafRequester = new LeafRequester(
// `${ROOT_COONTAINER}test_leaf/sample2.ttl`,
// solidLdoDataset.context,
// );
// const result = await leafRequester.createDataResource(true);
// expect(result.type).toBe("data");
// expect(
// solidLdoDataset.has(
// createQuad(
// namedNode(`${ROOT_COONTAINER}test_leaf/`),
// namedNode("http://www.w3.org/ns/ldp#contains"),
// namedNode(`${ROOT_COONTAINER}test_leaf/sample2.ttl`),
// namedNode(`${ROOT_COONTAINER}test_leaf/`),
// ),
// ),
// ).toBe(true);
// });
/**
* ===========================================================================
* Delete
* ===========================================================================
*/
it("deletes data", async () => {
solidLdoDataset.add(
createQuad(
namedNode("a"),
namedNode("b"),
namedNode("c"),
namedNode(`${ROOT_COONTAINER}/test_leaf/sample.ttl`),
),
);
solidLdoDataset.add(
createQuad(
namedNode(`${ROOT_COONTAINER}/test_leaf/`),
namedNode("http://www.w3.org/ns/ldp#contains"),
namedNode(`${ROOT_COONTAINER}/test_leaf/sample.ttl`),
namedNode(`${ROOT_COONTAINER}/test_leaf/`),
),
);
const leafRequester = new LeafRequester(
`${ROOT_COONTAINER}/test_leaf/sample.ttl`,
solidLdoDataset.context,
);
const result = await leafRequester.delete();
expect(result.type).toBe("absent");
expect(
solidLdoDataset.match(
null,
null,
null,
namedNode(`${ROOT_COONTAINER}/test_leaf/sample.ttl`),
).size,
).toBe(0);
expect(
solidLdoDataset.has(
createQuad(
namedNode(`${ROOT_COONTAINER}/test_leaf/`),
namedNode("http://www.w3.org/ns/ldp#contains"),
namedNode(`${ROOT_COONTAINER}/test_leaf/sample.ttl`),
namedNode(`${ROOT_COONTAINER}/test_leaf/`),
),
),
).toBe(false);
});
});
// it("creates a data resource that does exist while not overwriting", async () => {
// const leafRequester = new LeafRequester(
// `${ROOT_COONTAINER}test_leaf/sample.ttl`,
// solidLdoDataset.context,
// );
// const result = await leafRequester.createDataResource();
// expect(result.type).toBe("data");
// expect(
// solidLdoDataset.has(
// createQuad(
// namedNode("http://example.org/#spiderman"),
// namedNode("http://www.perceive.net/schemas/relationship/enemyOf"),
// namedNode("http://example.org/#green-goblin"),
// namedNode(`${ROOT_COONTAINER}test_leaf/sample.ttl`),
// ),
// ),
// ).toBe(true);
// expect(
// solidLdoDataset.has(
// createQuad(
// namedNode(`${ROOT_COONTAINER}test_leaf/`),
// namedNode("http://www.w3.org/ns/ldp#contains"),
// namedNode(`${ROOT_COONTAINER}test_leaf/sample.ttl`),
// namedNode(`${ROOT_COONTAINER}test_leaf/`),
// ),
// ),
// ).toBe(true);
// });
// it("creates a data resource that does exist while overwriting", async () => {
// const leafRequester = new LeafRequester(
// `${ROOT_COONTAINER}test_leaf/sample.ttl`,
// solidLdoDataset.context,
// );
// const result = await leafRequester.createDataResource(true);
// expect(result.type).toBe("data");
// expect(
// solidLdoDataset.has(
// createQuad(
// namedNode("http://example.org/#spiderman"),
// namedNode("http://www.perceive.net/schemas/relationship/enemyOf"),
// namedNode("http://example.org/#green-goblin"),
// namedNode(`${ROOT_COONTAINER}test_leaf/sample.ttl`),
// ),
// ),
// ).toBe(false);
// expect(
// solidLdoDataset.has(
// createQuad(
// namedNode(`${ROOT_COONTAINER}test_leaf/`),
// namedNode("http://www.w3.org/ns/ldp#contains"),
// namedNode(`${ROOT_COONTAINER}test_leaf/sample.ttl`),
// namedNode(`${ROOT_COONTAINER}test_leaf/`),
// ),
// ),
// ).toBe(true);
// });
// /**
// * ===========================================================================
// * Delete
// * ===========================================================================
// */
// it("deletes data", async () => {
// solidLdoDataset.add(
// createQuad(
// namedNode("a"),
// namedNode("b"),
// namedNode("c"),
// namedNode(`${ROOT_COONTAINER}/test_leaf/sample.ttl`),
// ),
// );
// solidLdoDataset.add(
// createQuad(
// namedNode(`${ROOT_COONTAINER}/test_leaf/`),
// namedNode("http://www.w3.org/ns/ldp#contains"),
// namedNode(`${ROOT_COONTAINER}/test_leaf/sample.ttl`),
// namedNode(`${ROOT_COONTAINER}/test_leaf/`),
// ),
// );
// const leafRequester = new LeafRequester(
// `${ROOT_COONTAINER}/test_leaf/sample.ttl`,
// solidLdoDataset.context,
// );
// const result = await leafRequester.delete();
// expect(result.type).toBe("absent");
// expect(
// solidLdoDataset.match(
// null,
// null,
// null,
// namedNode(`${ROOT_COONTAINER}/test_leaf/sample.ttl`),
// ).size,
// ).toBe(0);
// expect(
// solidLdoDataset.has(
// createQuad(
// namedNode(`${ROOT_COONTAINER}/test_leaf/`),
// namedNode("http://www.w3.org/ns/ldp#contains"),
// namedNode(`${ROOT_COONTAINER}/test_leaf/sample.ttl`),
// namedNode(`${ROOT_COONTAINER}/test_leaf/`),
// ),
// ),
// ).toBe(false);
// });
// });

@ -5,11 +5,17 @@ describe("RequestBatcher", () => {
type ReadWaitingProcess = WaitingProcess<[string], string>;
it("Batches a request", async () => {
const requestBatcher = new RequestBatcher({ batchMillis: 1000 });
const perform = async (input: string): Promise<string> => `Hello ${input}`;
const requestBatcher = new RequestBatcher({ batchMillis: 500 });
const perform = async (input: string): Promise<string> => {
await wait(100);
return `Hello ${input}`;
};
const perform1 = jest.fn(perform);
const perform2 = jest.fn(perform);
const perform3 = jest.fn(perform);
const perform3 = jest.fn((input: string): Promise<string> => {
expect(requestBatcher.isLoading("read")).toBe(true);
return perform(input);
});
const perform4 = jest.fn(perform);
const modifyQueue = (queue, currentlyProcessing, input: [string]) => {
@ -26,6 +32,8 @@ describe("RequestBatcher", () => {
let return3: string = "";
let return4: string = "";
expect(requestBatcher.isLoading("read")).toBe(false);
await Promise.all([
requestBatcher
.queueProcess<[string], string>({
@ -76,4 +84,29 @@ describe("RequestBatcher", () => {
expect(perform3).toHaveBeenCalledTimes(0);
expect(perform4).toHaveBeenCalledTimes(0);
});
it("sets a default batch millis", () => {
const requestBatcher = new RequestBatcher();
expect(requestBatcher.batchMillis).toBe(1000);
});
it("handles an error being thrown in the process", () => {
const requestBatcher = new RequestBatcher({ batchMillis: 500 });
const perform = async (_input: string): Promise<string> => {
throw new Error("Test Error");
};
const perform1 = jest.fn(perform);
expect(() =>
requestBatcher.queueProcess<[string], string>({
name: "read",
args: ["a"],
perform: perform1,
modifyQueue: () => undefined,
}),
).rejects.toThrowError("Test Error");
});
});
function wait(millis: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, millis));
}

@ -0,0 +1,217 @@
import type { App } from "@solid/community-server";
import type { ContainerUri, LeafUri, SolidLdoDataset } from "../src";
import { createSolidLdoDataset } from "../src";
import {
ROOT_CONTAINER,
createApp,
getAuthenticatedFetch,
} from "./solidServer.helper";
import { namedNode } from "@rdfjs/data-model";
const TEST_CONTAINER_SLUG = "test_ldo/";
const TEST_CONTAINER_URI =
`${ROOT_CONTAINER}${TEST_CONTAINER_SLUG}` as ContainerUri;
const SAMPLE_DATA_URI = `${TEST_CONTAINER_URI}sample.ttl` as LeafUri;
const SAMPLE2_DATA_URI = `${TEST_CONTAINER_URI}sample2.ttl` as LeafUri;
const SAMPLE_BINARY_URI = `${TEST_CONTAINER_URI}sample.txt` as LeafUri;
const SAMPLE2_BINARY_URI = `${TEST_CONTAINER_URI}sample2.txt` as LeafUri;
const SPIDER_MAN_TTL = `@base <http://example.org/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix rel: <http://www.perceive.net/schemas/relationship/> .
<#green-goblin>
rel:enemyOf <#spiderman> ;
a foaf:Person ; # in the context of the Marvel universe
foaf:name "Green Goblin" .
<#spiderman>
rel:enemyOf <#green-goblin> ;
a foaf:Person ;
foaf:name "Spiderman", "Человек-паук"@ru .`;
describe("SolidLdoDataset", () => {
let app: App;
let authFetch: typeof fetch;
let fetchMock: jest.Mock<
Promise<Response>,
[input: RequestInfo | URL, init?: RequestInit | undefined]
>;
let solidLdoDataset: SolidLdoDataset;
beforeAll(async () => {
// Start up the server
app = await createApp();
await app.start();
authFetch = await getAuthenticatedFetch();
await authFetch(ROOT_CONTAINER, {
method: "POST",
headers: {
link: '<http://www.w3.org/ns/ldp#Container>; rel="type"',
slug: TEST_CONTAINER_SLUG,
},
});
});
afterAll(async () => {
app.stop();
});
beforeEach(async () => {
fetchMock = jest.fn(authFetch);
solidLdoDataset = createSolidLdoDataset({ fetch: fetchMock });
// Create a new document called sample.ttl
await Promise.all([
authFetch(TEST_CONTAINER_URI, {
method: "POST",
headers: { "content-type": "text/turtle", slug: "sample.ttl" },
body: SPIDER_MAN_TTL,
}),
authFetch(TEST_CONTAINER_URI, {
method: "POST",
headers: { "content-type": "text/plain", slug: "sample.txt" },
body: "some text.",
}),
]);
});
afterEach(async () => {
await Promise.all([
authFetch(SAMPLE_DATA_URI, {
method: "DELETE",
}),
authFetch(SAMPLE2_DATA_URI, {
method: "DELETE",
}),
authFetch(SAMPLE_BINARY_URI, {
method: "DELETE",
}),
authFetch(SAMPLE2_BINARY_URI, {
method: "DELETE",
}),
]);
});
describe("read", () => {
it("Reads a data leaf", async () => {
const resource = solidLdoDataset.getResource(SAMPLE_DATA_URI);
const result = await resource.read();
expect(result.type).toBe("dataReadSuccess");
expect(
solidLdoDataset.match(
namedNode("http://example.org/#spiderman"),
namedNode("http://www.perceive.net/schemas/relationship/enemyOf"),
namedNode("http://example.org/#green-goblin"),
).size,
).toBe(1);
});
it("Reads a container", async () => {
const resource = solidLdoDataset.getResource(TEST_CONTAINER_URI);
const result = await resource.read();
expect(result.type).toBe("containerReadSuccess");
expect(resource.children().length).toBe(2);
});
it("Reads a binary leaf", async () => {
const resource = solidLdoDataset.getResource(SAMPLE_BINARY_URI);
const result = await resource.read();
expect(result.type).toBe("binaryReadSuccess");
expect(resource.isBinary()).toBe(true);
expect(await resource.getBlob()?.text()).toBe("some text.");
});
it("Returns an absent result if the document doesn't exist", async () => {
const resource = solidLdoDataset.getResource(SAMPLE2_DATA_URI);
const result = await resource.read();
expect(result.type).toBe("absentReadSuccess");
if (result.type !== "absentReadSuccess") return;
expect(result.resource.isAbsent()).toBe(true);
});
it("Returns an ServerError when an 500 error is returned", async () => {
fetchMock.mockResolvedValueOnce(new Response("Error", { status: 500 }));
const resource = solidLdoDataset.getResource(SAMPLE2_DATA_URI);
const result = await resource.read();
expect(result.isError).toBe(true);
expect(result.type).toBe("serverError");
});
it("Returns an UnauthenticatedError on an 401 error is returned", async () => {
fetchMock.mockResolvedValueOnce(new Response("Error", { status: 401 }));
const resource = solidLdoDataset.getResource(SAMPLE2_DATA_URI);
const result = await resource.read();
expect(result.isError).toBe(true);
expect(result.type).toBe("unauthenticatedError");
});
it("Returns an UnexpectedHttpError on a strange number error is returned", async () => {
fetchMock.mockResolvedValueOnce(new Response("Error", { status: 3942 }));
const resource = solidLdoDataset.getResource(SAMPLE2_DATA_URI);
const result = await resource.read();
expect(result.isError).toBe(true);
expect(result.type).toBe("unexpectedHttpError");
});
it("Returns a NoncompliantPod error when no content type is returned", async () => {
fetchMock.mockResolvedValueOnce(
new Response(undefined, { status: 200, headers: {} }),
);
const resource = solidLdoDataset.getResource(SAMPLE2_DATA_URI);
const result = await resource.read();
expect(result.isError).toBe(true);
if (!result.isError) return;
expect(result.type).toBe("noncompliantPodError");
expect(result.message).toBe(
"Response from https://solidweb.me/jackson3/test_ldo/sample2.ttl is not compliant with the Solid Specification: Resource requests must return a content-type header.",
);
});
it("Returns a NoncompliantPod error if invalid turtle is provided", async () => {
fetchMock.mockResolvedValueOnce(
new Response("Error", {
status: 200,
headers: new Headers({ "content-type": "text/turtle" }),
}),
);
const resource = solidLdoDataset.getResource(SAMPLE2_DATA_URI);
const result = await resource.read();
expect(result.isError).toBe(true);
if (!result.isError) return;
expect(result.type).toBe("noncompliantPodError");
expect(result.message).toBe(
'Response from https://solidweb.me/jackson3/test_ldo/sample2.ttl is not compliant with the Solid Specification: Request returned noncompliant turtle: Unexpected "Error" on line 1.',
);
});
it("Returns an UnexpectedResourceError if an unknown error is triggered", async () => {
fetchMock.mockRejectedValueOnce(new Error("Something happened."));
const resource = solidLdoDataset.getResource(SAMPLE2_DATA_URI);
const result = await resource.read();
expect(result.isError).toBe(true);
if (!result.isError) return;
expect(result.type).toBe("unexpectedResourceError");
expect(result.message).toBe("Something happened.");
});
it("Returns an error if there is no link header for a container request", async () => {
fetchMock.mockResolvedValueOnce(
new Response(SPIDER_MAN_TTL, {
status: 200,
headers: new Headers({ "content-type": "text/turtle" }),
}),
);
const resource = solidLdoDataset.getResource(TEST_CONTAINER_URI);
const result = await resource.read();
expect(result.isError).toBe(true);
if (!result.isError) return;
expect(result.type).toBe("noncompliantPodError");
expect(result.message).toBe(
"Response from https://solidweb.me/jackson3/test_ldo/ is not compliant with the Solid Specification: No link header present in request.",
);
});
});
});

@ -0,0 +1,7 @@
[
{
"podName": "example",
"email": "hello@example.com",
"password": "abc123"
}
]

@ -7,26 +7,35 @@ import {
createDpopHeader,
generateDpopKeyPair,
} from "@inrupt/solid-client-authn-core";
import type { App } from "@solid/community-server";
import { AppRunner, resolveModulePath } from "@solid/community-server";
import "jest-rdf";
import fetch from "cross-fetch";
const config = [
{
podName: process.env.USER_NAME,
email: process.env.EMAIL,
password: process.env.PASSWORD,
podName: process.env.USER_NAME || "example",
email: process.env.EMAIL || "hello@example.com",
password: process.env.PASSWORD || "abc123",
},
];
export const SERVER_DOMAIN = process.env.SERVER;
export const ROOT_COONTAINER = `${process.env.SERVER}${process.env.ROOT_CONTAINER}`;
export const SERVER_DOMAIN = process.env.SERVER || "http://localhost:3001/";
export const ROOT_ROUTE = process.env.ROOT_CONTAINER || "example/";
export const ROOT_CONTAINER = `${SERVER_DOMAIN}${ROOT_ROUTE}`;
// Use an increased timeout, since the CSS server takes too much setup time.
jest.setTimeout(40_000);
export function createApp() {
return new AppRunner().create(
export async function createApp(): Promise<App> {
if (process.env.SERVER) {
return {
start: () => {},
stop: () => {},
} as App;
}
const appRunner = new AppRunner();
return appRunner.create(
{
mainModulePath: resolveModulePath(""),
typeChecking: false,
@ -98,9 +107,13 @@ export async function getAuthenticatedFetch() {
// Generate secret
const secret = await getSecret();
if (!secret) throw new Error("No Secret");
// Get token
const token = await refreshToken(secret);
if (!token) throw new Error("No Token");
// Build authenticated fetch
const authFetch = await buildAuthenticatedFetch(fetch, token.accessToken, {
dpopKey: token.dpopKey,

Loading…
Cancel
Save