mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Add support for StreamingHTTPChannel2023 notifications
* feat: initial StremingHTTPChannel2023 notifications Co-authored-by: Maciej Samoraj <maciej.samoraj@gmail.com> * test: unit for StremingHTTPChannel2023 notifications Co-authored-by: Maciej Samoraj <maciej.samoraj@gmail.com> * test: integration for StremingHTTPChannel2023 notifications Co-authored-by: Maciej Samoraj <maciej.samoraj@gmail.com> * emit initial notification on streaming http channel * fix linting erros * ensure canceling fetch body in integration tests * extract defaultChannel for topic into util * add documentation * Apply suggestions from code review Co-authored-by: Ted Thibodeau Jr <tthibodeau@openlinksw.com> * only generate notifications when needed Co-authored-by: Maciej Samoraj <maciej.samoraj@gmail.com> * test: set body timeout to pass on node >21 Co-authored-by: Maciej Samoraj <maciej.samoraj@gmail.com> * address review feedback * remove node 21 workaround * add architecture documentation * Apply suggestions from code review Co-authored-by: Joachim Van Herwegen <joachimvh@gmail.com> --------- Co-authored-by: Maciej Samoraj <maciej.samoraj@gmail.com> Co-authored-by: Ted Thibodeau Jr <tthibodeau@openlinksw.com> Co-authored-by: Joachim Van Herwegen <joachimvh@gmail.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import { PassThrough } from 'node:stream';
|
||||
import { BasicRepresentation } from '../../../../../src/http/representation/BasicRepresentation';
|
||||
import type { NotificationChannel } from '../../../../../src/server/notifications/NotificationChannel';
|
||||
import {
|
||||
StreamingHttp2023Emitter,
|
||||
} from '../../../../../src/server/notifications/StreamingHttpChannel2023/StreamingHttp2023Emitter';
|
||||
import { WrappedSetMultiMap } from '../../../../../src/util/map/WrappedSetMultiMap';
|
||||
import type { StreamingHttpMap } from '../../../../../src';
|
||||
|
||||
describe('A StreamingHttp2023Emitter', (): void => {
|
||||
const channel: NotificationChannel = {
|
||||
id: 'id',
|
||||
topic: 'http://example.com/foo',
|
||||
type: 'type',
|
||||
};
|
||||
|
||||
let stream: jest.Mocked<PassThrough>;
|
||||
let streamMap: StreamingHttpMap;
|
||||
let emitter: StreamingHttp2023Emitter;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
stream = jest.mocked(new PassThrough());
|
||||
|
||||
streamMap = new WrappedSetMultiMap();
|
||||
|
||||
emitter = new StreamingHttp2023Emitter(streamMap);
|
||||
});
|
||||
|
||||
it('emits notifications to the stored Streams.', async(): Promise<void> => {
|
||||
streamMap.add(channel.topic, stream);
|
||||
|
||||
const representation = new BasicRepresentation('notification', 'text/plain');
|
||||
const spy = jest.spyOn(representation.data, 'pipe');
|
||||
await expect(emitter.handle({ channel, representation })).resolves.toBeUndefined();
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
expect(spy).toHaveBeenLastCalledWith(stream, { end: false });
|
||||
});
|
||||
|
||||
it('destroys the representation if there is no matching Stream.', async(): Promise<void> => {
|
||||
const representation = new BasicRepresentation('notification', 'text/plain');
|
||||
const spy = jest.spyOn(representation.data, 'pipe');
|
||||
await expect(emitter.handle({ channel, representation })).resolves.toBeUndefined();
|
||||
expect(spy).toHaveBeenCalledTimes(0);
|
||||
expect(representation.data.destroyed).toBe(true);
|
||||
});
|
||||
|
||||
it('can write to multiple matching Streams.', async(): Promise<void> => {
|
||||
const stream2 = jest.mocked(new PassThrough());
|
||||
|
||||
streamMap.add(channel.topic, stream);
|
||||
streamMap.add(channel.topic, stream2);
|
||||
|
||||
const representation = new BasicRepresentation('notification', 'text/plain');
|
||||
const spy = jest.spyOn(representation.data, 'pipe');
|
||||
await expect(emitter.handle({ channel, representation })).resolves.toBeUndefined();
|
||||
expect(spy).toHaveBeenCalledTimes(2);
|
||||
expect(spy).toHaveBeenCalledWith(stream, { end: false });
|
||||
expect(spy).toHaveBeenLastCalledWith(stream2, { end: false });
|
||||
});
|
||||
|
||||
it('only writes to the matching topic Streams.', async(): Promise<void> => {
|
||||
const stream2 = jest.mocked(new PassThrough());
|
||||
const channel2: NotificationChannel = {
|
||||
...channel,
|
||||
id: 'other id',
|
||||
topic: 'other topic',
|
||||
};
|
||||
|
||||
streamMap.add(channel.topic, stream);
|
||||
streamMap.add(channel2.topic, stream2);
|
||||
|
||||
const representation = new BasicRepresentation('notification', 'text/plain');
|
||||
const spy = jest.spyOn(representation.data, 'pipe');
|
||||
await expect(emitter.handle({ channel, representation })).resolves.toBeUndefined();
|
||||
expect(spy).toHaveBeenCalledTimes(1);
|
||||
expect(spy).toHaveBeenLastCalledWith(stream, { end: false });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user