Skip to content

Commit

Permalink
feat(listener/loopback): add default target listener to config
Browse files Browse the repository at this point in the history
  • Loading branch information
ssube committed Oct 27, 2019
1 parent dfa8f77 commit 145b9c1
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 14 deletions.
30 changes: 27 additions & 3 deletions src/listener/LoopbackListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,39 @@ import { User } from '../entity/auth/User';
import { Message } from '../entity/Message';
import { Session } from '../entity/Session';
import { NotImplementedError } from '../error/NotImplementedError';
import { ServiceMetadata } from '../Service';
import { mustExist } from '../utils';
import { BaseListener } from './BaseListener';

export class LoopbackListener extends BaseListener<ListenerData> implements Listener {
constructor(options: BotServiceOptions<ListenerData>) {
export interface LoopbackListenerData extends ListenerData {
defaultTarget: ServiceMetadata;
}

export class LoopbackListener extends BaseListener<LoopbackListenerData> implements Listener {
protected target?: Listener;

constructor(options: BotServiceOptions<LoopbackListenerData>) {
super(options, 'isolex#/definitions/service-listener-loopback');
}

public async start() {
await super.start();

this.target = this.services.getService<Listener>(this.data.defaultTarget);
}

public async send(msg: Message): Promise<void> {
await this.bot.receive(msg);
const target = mustExist(this.target);
const context = await this.createContext({
...mustExist(msg.context),
source: target,
target,
});
const outMsg = new Message({
...msg,
context,
});
await this.bot.receive(outMsg);
}

public async fetch(options: FetchOptions): Promise<Array<Message>> {
Expand Down
8 changes: 7 additions & 1 deletion src/schema/schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,13 @@ definitions:
type: string

service-listener-loopback:
$ref: "#/definitions/service-listener"
allOf:
- $ref: "#/definitions/service-listener"
- type: object
additionalProperties: true
properties:
defaultTarget:
$ref: "#/definitions/service-metadata"

service-listener-slack:
allOf:
Expand Down
9 changes: 7 additions & 2 deletions test/helpers/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ import { Repository } from 'typeorm';
import { Role } from '../../src/entity/auth/Role';
import { User } from '../../src/entity/auth/User';
import { UserRepository } from '../../src/entity/auth/UserRepository';
import { Context } from '../../src/entity/Context';
import { Storage } from '../../src/storage';

export function createMockStorage(): Storage {
const repository = {
save: (it: unknown) => Promise.resolve(it),
};
const getRepository = stub()
.withArgs(Role).returns(ineeda<Repository<Role>>())
.withArgs(User).returns(ineeda<Repository<User>>());
.withArgs(Context).returns(ineeda<Repository<Context>>(repository))
.withArgs(Role).returns(ineeda<Repository<Role>>(repository))
.withArgs(User).returns(ineeda<Repository<User>>(repository));

return ineeda<Storage>({
getCustomRepository: () => ineeda<UserRepository>(),
Expand Down
115 changes: 107 additions & 8 deletions test/listener/TestLoopbackListener.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,134 @@
import { expect } from 'chai';
import { ineeda } from 'ineeda';
import { spy } from 'sinon';
import { match, spy } from 'sinon';

import { Bot } from '../../src/Bot';
import { INJECT_BOT } from '../../src/BotService';
import { User } from '../../src/entity/auth/User';
import { Context } from '../../src/entity/Context';
import { Message } from '../../src/entity/Message';
import { NotImplementedError } from '../../src/error/NotImplementedError';
import { LoopbackListener } from '../../src/listener/LoopbackListener';
import { Service } from '../../src/Service';
import { TYPE_TEXT } from '../../src/utils/Mime';
import { describeLeaks, itLeaks } from '../helpers/async';
import { createService, createServiceContainer } from '../helpers/container';

const TEST_METADATA = {
kind: 'loopback-listener',
name: 'test-listener',
};

const TEST_TARGET = {
kind: 'test-target',
name: 'test-target',
};

describeLeaks('loopback listener', async () => {
itLeaks('should send messages to the bot', async () => {
const { container, services } = await createServiceContainer();

const svc = ineeda<Service>(TEST_TARGET);
services.addService(svc);

const receive = spy();
const { container } = await createServiceContainer();
const listener = await createService(container, LoopbackListener, {
[INJECT_BOT]: ineeda<Bot>({
receive,
}),
data: {
defaultTarget: TEST_TARGET,
filters: [],
strict: false,
},
metadata: {
kind: 'loopback-listener',
name: 'test-listener',
},
metadata: TEST_METADATA,
});
await listener.start();

const ctxOptions = {
name: 'test-user',
uid: 'test-uid',
};
const msgOptions = {
body: 'test-body',
type: TYPE_TEXT,
};

const msg = ineeda<Message>();
const msg = new Message({
context: new Context({
channel: {
id: '',
thread: '',
},
...ctxOptions,
}),
labels: {},
reactions: [],
...msgOptions,
});
await listener.send(msg);

expect(receive).to.have.callCount(1).and.been.calledWith(msg);
expect(receive).to.have.callCount(1)
.and.been.calledWithMatch(match.has('body', msgOptions.body)
.and(match.has('type', msgOptions.type)));
});

itLeaks('should throw when fetching messages', async () => {
const { container, services } = await createServiceContainer();

const svc = ineeda<Service>(TEST_TARGET);
services.addService(svc);

const listener = await createService(container, LoopbackListener, {
data: {
defaultTarget: TEST_TARGET,
filters: [],
strict: false,
},
metadata: TEST_METADATA,
});
await listener.start();

await expect(listener.fetch({
channel: '',
})).to.eventually.be.rejectedWith(NotImplementedError);
});

itLeaks('should throw when creating sessions', async () => {
const { container, services } = await createServiceContainer();

const svc = ineeda<Service>(TEST_TARGET);
services.addService(svc);

const listener = await createService(container, LoopbackListener, {
data: {
defaultTarget: TEST_TARGET,
filters: [],
strict: false,
},
metadata: TEST_METADATA,
});
await listener.start();

await expect(listener.createSession('test', ineeda<User>())).to.eventually.be.rejectedWith(NotImplementedError);
});

itLeaks('should not provide sessions', async () => {
const { container, services } = await createServiceContainer();

const svc = ineeda<Service>(TEST_TARGET);
services.addService(svc);

const listener = await createService(container, LoopbackListener, {
data: {
defaultTarget: TEST_TARGET,
filters: [],
strict: false,
},
metadata: TEST_METADATA,
});
await listener.start();

await expect(listener.getSession('test')).to.eventually.equal(undefined);
});
});

0 comments on commit 145b9c1

Please sign in to comment.