mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Make stores return modified resources.
This commit is contained in:
committed by
Joachim Van Herwegen
parent
28c0eb7e88
commit
6edc255707
@@ -7,7 +7,7 @@ describe('A DeleteOperationHandler', (): void => {
|
||||
const store = {} as unknown as ResourceStore;
|
||||
const handler = new DeleteOperationHandler(store);
|
||||
beforeEach(async(): Promise<void> => {
|
||||
store.deleteResource = jest.fn(async(): Promise<void> => undefined);
|
||||
store.deleteResource = jest.fn(async(): Promise<any> => undefined);
|
||||
});
|
||||
|
||||
it('only supports DELETE operations.', async(): Promise<void> => {
|
||||
|
||||
@@ -9,7 +9,7 @@ describe('A PatchOperationHandler', (): void => {
|
||||
const store = {} as unknown as ResourceStore;
|
||||
const handler = new PatchOperationHandler(store);
|
||||
beforeEach(async(): Promise<void> => {
|
||||
store.modifyResource = jest.fn(async(): Promise<void> => undefined);
|
||||
store.modifyResource = jest.fn(async(): Promise<any> => undefined);
|
||||
});
|
||||
|
||||
it('only supports PATCH operations.', async(): Promise<void> => {
|
||||
|
||||
@@ -10,7 +10,7 @@ describe('A PutOperationHandler', (): void => {
|
||||
const handler = new PutOperationHandler(store);
|
||||
beforeEach(async(): Promise<void> => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
store.setRepresentation = jest.fn(async(): Promise<void> => {});
|
||||
store.setRepresentation = jest.fn(async(): Promise<any> => {});
|
||||
});
|
||||
|
||||
it('only supports PUT operations.', async(): Promise<void> => {
|
||||
|
||||
@@ -40,11 +40,11 @@ class SimpleDataAccessor implements DataAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
public async deleteResource(identifier: ResourceIdentifier): Promise<void> {
|
||||
public async deleteResource(identifier: ResourceIdentifier): Promise<ResourceIdentifier[]> {
|
||||
this.checkExists(identifier);
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete this.data[identifier.path];
|
||||
return undefined;
|
||||
return [ identifier ];
|
||||
}
|
||||
|
||||
public async getData(identifier: ResourceIdentifier): Promise<Guarded<Readable>> {
|
||||
@@ -353,8 +353,8 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
representation.metadata.contentType = 'text/turtle';
|
||||
representation.data = guardedStreamFrom([ `<${`${root}`}> a <coolContainer>.` ]);
|
||||
|
||||
await expect(store.setRepresentation(resourceID, representation))
|
||||
.resolves.toBeUndefined();
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves
|
||||
.toEqual([{ path: `${root}` }]);
|
||||
expect(mock).toHaveBeenCalledTimes(1);
|
||||
expect(mock).toHaveBeenLastCalledWith(resourceID);
|
||||
|
||||
@@ -383,7 +383,10 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
|
||||
it('can write resources.', async(): Promise<void> => {
|
||||
const resourceID = { path: `${root}resource` };
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves.toBeUndefined();
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves.toEqual([
|
||||
{ path: 'http://test.com/' },
|
||||
{ path: 'http://test.com/resource' },
|
||||
]);
|
||||
await expect(arrayifyStream(accessor.data[resourceID.path].data)).resolves.toEqual([ resourceData ]);
|
||||
});
|
||||
|
||||
@@ -394,7 +397,10 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
representation.metadata.removeAll(RDF.type);
|
||||
representation.metadata.contentType = 'text/turtle';
|
||||
representation.data = guardedStreamFrom([ `<${`${root}resource/`}> a <coolContainer>.` ]);
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves.toBeUndefined();
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves.toEqual([
|
||||
{ path: `${root}` },
|
||||
{ path: `${root}container/` },
|
||||
]);
|
||||
expect(accessor.data[resourceID.path]).toBeTruthy();
|
||||
expect(accessor.data[resourceID.path].metadata.contentType).toBeUndefined();
|
||||
});
|
||||
@@ -403,7 +409,10 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete accessor.data[root];
|
||||
const resourceID = { path: `${root}resource` };
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves.toBeUndefined();
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves.toEqual([
|
||||
{ path: `${root}` },
|
||||
{ path: `${root}resource` },
|
||||
]);
|
||||
await expect(arrayifyStream(accessor.data[resourceID.path].data)).resolves.toEqual([ resourceData ]);
|
||||
});
|
||||
|
||||
@@ -416,7 +425,10 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
representation.data = guardedStreamFrom(
|
||||
[ quad(namedNode(`${root}resource/`), namedNode('a'), namedNode('coolContainer')) ],
|
||||
);
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves.toBeUndefined();
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves.toEqual([
|
||||
{ path: `${root}` },
|
||||
{ path: `${root}container/` },
|
||||
]);
|
||||
expect(accessor.data[resourceID.path]).toBeTruthy();
|
||||
expect(accessor.data[resourceID.path].metadata.contentType).toBeUndefined();
|
||||
});
|
||||
@@ -436,7 +448,11 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
|
||||
it('creates recursive containers when needed.', async(): Promise<void> => {
|
||||
const resourceID = { path: `${root}a/b/resource` };
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves.toBeUndefined();
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves.toEqual([
|
||||
{ path: `${root}a/` },
|
||||
{ path: `${root}a/b/` },
|
||||
{ path: `${root}a/b/resource` },
|
||||
]);
|
||||
await expect(arrayifyStream(accessor.data[resourceID.path].data)).resolves.toEqual([ resourceData ]);
|
||||
expect(accessor.data[`${root}a/`].metadata.getAll(RDF.type).map((type): string => type.value))
|
||||
.toContain(LDP.Container);
|
||||
@@ -461,7 +477,9 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
representation.metadata.removeAll(RDF.type);
|
||||
representation.metadata.contentType = 'text/turtle';
|
||||
representation.data = guardedStreamFrom([]);
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves.toBeUndefined();
|
||||
await expect(store.setRepresentation(resourceID, representation)).resolves.toEqual([
|
||||
{ path: `${root}` },
|
||||
]);
|
||||
expect(accessor.data[resourceID.path]).toBeTruthy();
|
||||
expect(Object.keys(accessor.data)).toHaveLength(1);
|
||||
expect(accessor.data[resourceID.path].metadata.contentType).toBeUndefined();
|
||||
@@ -513,7 +531,9 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
|
||||
it('will delete resources.', async(): Promise<void> => {
|
||||
accessor.data[`${root}resource`] = representation;
|
||||
await expect(store.deleteResource({ path: `${root}resource` })).resolves.toBeUndefined();
|
||||
await expect(store.deleteResource({ path: `${root}resource` })).resolves.toEqual([
|
||||
{ path: `${root}resource` },
|
||||
]);
|
||||
expect(accessor.data[`${root}resource`]).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -522,14 +542,19 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
accessor.data[`${root}container/`] = new BasicRepresentation(representation.data, storageMetadata);
|
||||
accessor.data[`${root}container/.dummy`] = representation;
|
||||
auxStrategy.isRootRequired = jest.fn().mockReturnValue(true);
|
||||
await expect(store.deleteResource({ path: `${root}container/.dummy` })).resolves.toBeUndefined();
|
||||
await expect(store.deleteResource({ path: `${root}container/.dummy` })).resolves.toEqual([
|
||||
{ path: `${root}container/.dummy` },
|
||||
]);
|
||||
expect(accessor.data[`${root}container/.dummy`]).toBeUndefined();
|
||||
});
|
||||
|
||||
it('will delete related auxiliary resources.', async(): Promise<void> => {
|
||||
accessor.data[`${root}container/`] = representation;
|
||||
accessor.data[`${root}container/.dummy`] = representation;
|
||||
await expect(store.deleteResource({ path: `${root}container/` })).resolves.toBeUndefined();
|
||||
await expect(store.deleteResource({ path: `${root}container/` })).resolves.toEqual([
|
||||
{ path: `${root}container/` },
|
||||
{ path: `${root}container/.dummy` },
|
||||
]);
|
||||
expect(accessor.data[`${root}container/`]).toBeUndefined();
|
||||
expect(accessor.data[`${root}container/.dummy`]).toBeUndefined();
|
||||
});
|
||||
@@ -538,15 +563,18 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
accessor.data[`${root}resource`] = representation;
|
||||
accessor.data[`${root}resource.dummy`] = representation;
|
||||
const deleteFn = accessor.deleteResource;
|
||||
accessor.deleteResource = jest.fn(async(identifier: ResourceIdentifier): Promise<void> => {
|
||||
accessor.deleteResource = jest.fn(async(identifier: ResourceIdentifier): Promise<ResourceIdentifier[]> => {
|
||||
if (auxStrategy.isAuxiliaryIdentifier(identifier)) {
|
||||
throw new Error('auxiliary error!');
|
||||
}
|
||||
await deleteFn.call(accessor, identifier);
|
||||
return [ identifier ];
|
||||
});
|
||||
const { logger } = store as any;
|
||||
logger.error = jest.fn();
|
||||
await expect(store.deleteResource({ path: `${root}resource` })).resolves.toBeUndefined();
|
||||
await expect(store.deleteResource({ path: `${root}resource` })).resolves.toEqual([
|
||||
{ path: `${root}resource` },
|
||||
]);
|
||||
expect(accessor.data[`${root}resource`]).toBeUndefined();
|
||||
expect(accessor.data[`${root}resource.dummy`]).not.toBeUndefined();
|
||||
expect(logger.error).toHaveBeenCalledTimes(1);
|
||||
@@ -559,15 +587,18 @@ describe('A DataAccessorBasedStore', (): void => {
|
||||
accessor.data[`${root}resource`] = representation;
|
||||
accessor.data[`${root}resource.dummy`] = representation;
|
||||
const deleteFn = accessor.deleteResource;
|
||||
accessor.deleteResource = jest.fn(async(identifier: ResourceIdentifier): Promise<void> => {
|
||||
accessor.deleteResource = jest.fn(async(identifier: ResourceIdentifier): Promise<ResourceIdentifier[]> => {
|
||||
if (auxStrategy.isAuxiliaryIdentifier(identifier)) {
|
||||
throw 'auxiliary error!';
|
||||
}
|
||||
await deleteFn.call(accessor, identifier);
|
||||
return [ identifier ];
|
||||
});
|
||||
const { logger } = store as any;
|
||||
logger.error = jest.fn();
|
||||
await expect(store.deleteResource({ path: `${root}resource` })).resolves.toBeUndefined();
|
||||
await expect(store.deleteResource({ path: `${root}resource` })).resolves.toEqual([
|
||||
{ path: `${root}resource` },
|
||||
]);
|
||||
expect(accessor.data[`${root}resource`]).toBeUndefined();
|
||||
expect(accessor.data[`${root}resource.dummy`]).not.toBeUndefined();
|
||||
expect(logger.error).toHaveBeenCalledTimes(1);
|
||||
|
||||
@@ -333,7 +333,8 @@ describe('A FileDataAccessor', (): void => {
|
||||
|
||||
it('deletes the corresponding file for document.', async(): Promise<void> => {
|
||||
cache.data = { resource: 'apple' };
|
||||
await expect(accessor.deleteResource({ path: `${base}resource` })).resolves.toBeUndefined();
|
||||
await expect(accessor.deleteResource({ path: `${base}resource` })).resolves
|
||||
.toEqual([{ path: `${base}resource` }]);
|
||||
expect(cache.data.resource).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -344,22 +345,31 @@ describe('A FileDataAccessor', (): void => {
|
||||
|
||||
it('removes the corresponding folder for containers.', async(): Promise<void> => {
|
||||
cache.data = { container: {}};
|
||||
await expect(accessor.deleteResource({ path: `${base}container/` })).resolves.toBeUndefined();
|
||||
await expect(accessor.deleteResource({ path: `${base}container/` })).resolves
|
||||
.toEqual([{ path: `${base}container/` }]);
|
||||
expect(cache.data.container).toBeUndefined();
|
||||
});
|
||||
|
||||
it('removes the corresponding metadata.', async(): Promise<void> => {
|
||||
cache.data = { container: { resource: 'apple', 'resource.meta': 'metaApple', '.meta': 'metadata' }};
|
||||
await expect(accessor.deleteResource({ path: `${base}container/resource` })).resolves.toBeUndefined();
|
||||
await expect(accessor.deleteResource({ path: `${base}container/resource` })).resolves.toEqual([
|
||||
{ path: `${base}container/resource` },
|
||||
{ path: `${base}container/resource.meta` },
|
||||
]);
|
||||
expect(cache.data.container.resource).toBeUndefined();
|
||||
expect(cache.data.container['resource.meta']).toBeUndefined();
|
||||
await expect(accessor.deleteResource({ path: `${base}container/` })).resolves.toBeUndefined();
|
||||
await expect(accessor.deleteResource({ path: `${base}container/` })).resolves.toEqual([
|
||||
{ path: `${base}container/` },
|
||||
{ path: `${base}container/.meta` },
|
||||
]);
|
||||
expect(cache.data.container).toBeUndefined();
|
||||
});
|
||||
|
||||
it('can delete the root container.', async(): Promise<void> => {
|
||||
cache.data = { };
|
||||
await expect(accessor.deleteResource({ path: `${base}` })).resolves.toBeUndefined();
|
||||
await expect(accessor.deleteResource({ path: `${base}` })).resolves.toEqual([
|
||||
{ path: base },
|
||||
]);
|
||||
expect(cache.data).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -170,17 +170,20 @@ describe('An InMemoryDataAccessor', (): void => {
|
||||
it('removes the corresponding resource.', async(): Promise<void> => {
|
||||
await expect(accessor.writeDocument({ path: `${base}resource` }, data, metadata)).resolves.toBeUndefined();
|
||||
await expect(accessor.writeContainer({ path: `${base}container/` }, metadata)).resolves.toBeUndefined();
|
||||
await expect(accessor.deleteResource({ path: `${base}resource` })).resolves.toBeUndefined();
|
||||
await expect(accessor.deleteResource({ path: `${base}container/` })).resolves.toBeUndefined();
|
||||
await expect(accessor.deleteResource({ path: `${base}resource` })).resolves
|
||||
.toEqual([{ path: 'http://test.com/resource' }]);
|
||||
await expect(accessor.deleteResource({ path: `${base}container/` })).resolves
|
||||
.toEqual([{ path: 'http://test.com/container/' }]);
|
||||
await expect(accessor.getMetadata({ path: `${base}resource` })).rejects.toThrow(NotFoundHttpError);
|
||||
await expect(accessor.getMetadata({ path: `${base}container/` })).rejects.toThrow(NotFoundHttpError);
|
||||
});
|
||||
|
||||
it('can delete the root container and write to it again.', async(): Promise<void> => {
|
||||
await expect(accessor.deleteResource({ path: `${base}` })).resolves.toBeUndefined();
|
||||
await expect(accessor.getMetadata({ path: `${base}` })).rejects.toThrow(NotFoundHttpError);
|
||||
await expect(accessor.deleteResource({ path: base })).resolves
|
||||
.toEqual([{ path: base }]);
|
||||
await expect(accessor.getMetadata({ path: base })).rejects.toThrow(NotFoundHttpError);
|
||||
await expect(accessor.getMetadata({ path: `${base}test/` })).rejects.toThrow(NotFoundHttpError);
|
||||
await expect(accessor.writeContainer({ path: `${base}` }, metadata)).resolves.toBeUndefined();
|
||||
await expect(accessor.writeContainer({ path: base }, metadata)).resolves.toBeUndefined();
|
||||
const resultMetadata = await accessor.getMetadata({ path: `${base}` });
|
||||
expect(resultMetadata.quads()).toBeRdfIsomorphic(metadata.quads());
|
||||
});
|
||||
|
||||
@@ -210,7 +210,8 @@ describe('A SparqlDataAccessor', (): void => {
|
||||
it('removes all references when deleting a resource.', async(): Promise<void> => {
|
||||
metadata = new RepresentationMetadata({ path: 'http://test.com/container/' },
|
||||
{ [RDF.type]: [ LDP.terms.Resource, LDP.terms.Container ]});
|
||||
await expect(accessor.deleteResource({ path: 'http://test.com/container/' })).resolves.toBeUndefined();
|
||||
await expect(accessor.deleteResource({ path: 'http://test.com/container/' })).resolves
|
||||
.toEqual([{ path: 'http://test.com/container/' }]);
|
||||
|
||||
expect(fetchUpdate).toHaveBeenCalledTimes(1);
|
||||
expect(fetchUpdate.mock.calls[0][0]).toBe(endpoint);
|
||||
@@ -224,7 +225,8 @@ describe('A SparqlDataAccessor', (): void => {
|
||||
it('does not try to remove containment triples when deleting a root container.', async(): Promise<void> => {
|
||||
metadata = new RepresentationMetadata({ path: 'http://test.com/' },
|
||||
{ [RDF.type]: [ LDP.terms.Resource, LDP.terms.Container ]});
|
||||
await expect(accessor.deleteResource({ path: 'http://test.com/' })).resolves.toBeUndefined();
|
||||
await expect(accessor.deleteResource({ path: 'http://test.com/' })).resolves
|
||||
.toEqual([{ path: 'http://test.com/' }]);
|
||||
|
||||
expect(fetchUpdate).toHaveBeenCalledTimes(1);
|
||||
expect(fetchUpdate.mock.calls[0][0]).toBe(endpoint);
|
||||
|
||||
Reference in New Issue
Block a user