diff --git a/packages/solid/src/requester/results/error/HttpErrorResult.ts b/packages/solid/src/requester/results/error/HttpErrorResult.ts index 8475899..b4db237 100644 --- a/packages/solid/src/requester/results/error/HttpErrorResult.ts +++ b/packages/solid/src/requester/results/error/HttpErrorResult.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 ); diff --git a/packages/solid/src/util/RequestBatcher.ts b/packages/solid/src/util/RequestBatcher.ts index 33c6b1f..b9711d1 100644 --- a/packages/solid/src/util/RequestBatcher.ts +++ b/packages/solid/src/util/RequestBatcher.ts @@ -35,16 +35,13 @@ export class RequestBatcher { private currentlyProcessing: WaitingProcess | undefined = undefined; private processQueue: WaitingProcess[] = []; - 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]) { diff --git a/packages/solid/src/util/rdfUtils.ts b/packages/solid/src/util/rdfUtils.ts index 4a05276..f7f8d30 100644 --- a/packages/solid/src/util/rdfUtils.ts +++ b/packages/solid/src/util/rdfUtils.ts @@ -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}`, ); } diff --git a/packages/solid/test/ContainerRequester.test.ts b/packages/solid/test/ContainerRequester.test.ts index 54fc55b..7ee4c06 100644 --- a/packages/solid/test/ContainerRequester.test.ts +++ b/packages/solid/test/ContainerRequester.test.ts @@ -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 . - @prefix rdf: . - @prefix rdfs: . - @prefix foaf: . - @prefix rel: . - - <#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 . +// @prefix rdf: . +// @prefix rdfs: . +// @prefix foaf: . +// @prefix rel: . - 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); +// }); +// }); diff --git a/packages/solid/test/LeafRequester.test.ts b/packages/solid/test/LeafRequester.test.ts index 3f2a97c..4504cf8 100644 --- a/packages/solid/test/LeafRequester.test.ts +++ b/packages/solid/test/LeafRequester.test.ts @@ -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 . - @prefix rdf: . - @prefix rdfs: . - @prefix foaf: . - @prefix rel: . - - <#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 . +// @prefix rdf: . +// @prefix rdfs: . +// @prefix foaf: . +// @prefix rel: . - 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); +// }); +// }); diff --git a/packages/solid/test/RequestBatcher.test.ts b/packages/solid/test/RequestBatcher.test.ts index f05f2eb..38ff5a2 100644 --- a/packages/solid/test/RequestBatcher.test.ts +++ b/packages/solid/test/RequestBatcher.test.ts @@ -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 => `Hello ${input}`; + const requestBatcher = new RequestBatcher({ batchMillis: 500 }); + const perform = async (input: string): Promise => { + 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 => { + 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 => { + 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 { + return new Promise((resolve) => setTimeout(resolve, millis)); +} diff --git a/packages/solid/test/SolidLdoDataset.test.ts b/packages/solid/test/SolidLdoDataset.test.ts new file mode 100644 index 0000000..955adf3 --- /dev/null +++ b/packages/solid/test/SolidLdoDataset.test.ts @@ -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 . +@prefix rdf: . +@prefix rdfs: . +@prefix foaf: . +@prefix rel: . + +<#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, + [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: '; 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.", + ); + }); + }); +}); diff --git a/packages/solid/test/configs/solid-css-seed.json b/packages/solid/test/configs/solid-css-seed.json new file mode 100644 index 0000000..1b10b4c --- /dev/null +++ b/packages/solid/test/configs/solid-css-seed.json @@ -0,0 +1,7 @@ +[ + { + "podName": "example", + "email": "hello@example.com", + "password": "abc123" + } +] \ No newline at end of file diff --git a/packages/solid/test/solidServer.helper.ts b/packages/solid/test/solidServer.helper.ts index 5a71c3e..01ec04d 100644 --- a/packages/solid/test/solidServer.helper.ts +++ b/packages/solid/test/solidServer.helper.ts @@ -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 { + 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,