Skip to content

Commit 145b9c1

Browse files
committed
feat(listener/loopback): add default target listener to config
1 parent dfa8f77 commit 145b9c1

File tree

4 files changed

+148
-14
lines changed

4 files changed

+148
-14
lines changed

src/listener/LoopbackListener.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,39 @@ import { User } from '../entity/auth/User';
44
import { Message } from '../entity/Message';
55
import { Session } from '../entity/Session';
66
import { NotImplementedError } from '../error/NotImplementedError';
7+
import { ServiceMetadata } from '../Service';
8+
import { mustExist } from '../utils';
79
import { BaseListener } from './BaseListener';
810

9-
export class LoopbackListener extends BaseListener<ListenerData> implements Listener {
10-
constructor(options: BotServiceOptions<ListenerData>) {
11+
export interface LoopbackListenerData extends ListenerData {
12+
defaultTarget: ServiceMetadata;
13+
}
14+
15+
export class LoopbackListener extends BaseListener<LoopbackListenerData> implements Listener {
16+
protected target?: Listener;
17+
18+
constructor(options: BotServiceOptions<LoopbackListenerData>) {
1119
super(options, 'isolex#/definitions/service-listener-loopback');
1220
}
1321

22+
public async start() {
23+
await super.start();
24+
25+
this.target = this.services.getService<Listener>(this.data.defaultTarget);
26+
}
27+
1428
public async send(msg: Message): Promise<void> {
15-
await this.bot.receive(msg);
29+
const target = mustExist(this.target);
30+
const context = await this.createContext({
31+
...mustExist(msg.context),
32+
source: target,
33+
target,
34+
});
35+
const outMsg = new Message({
36+
...msg,
37+
context,
38+
});
39+
await this.bot.receive(outMsg);
1640
}
1741

1842
public async fetch(options: FetchOptions): Promise<Array<Message>> {

src/schema/schema.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,13 @@ definitions:
840840
type: string
841841

842842
service-listener-loopback:
843-
$ref: "#/definitions/service-listener"
843+
allOf:
844+
- $ref: "#/definitions/service-listener"
845+
- type: object
846+
additionalProperties: true
847+
properties:
848+
defaultTarget:
849+
$ref: "#/definitions/service-metadata"
844850

845851
service-listener-slack:
846852
allOf:

test/helpers/storage.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@ import { Repository } from 'typeorm';
55
import { Role } from '../../src/entity/auth/Role';
66
import { User } from '../../src/entity/auth/User';
77
import { UserRepository } from '../../src/entity/auth/UserRepository';
8+
import { Context } from '../../src/entity/Context';
89
import { Storage } from '../../src/storage';
910

1011
export function createMockStorage(): Storage {
12+
const repository = {
13+
save: (it: unknown) => Promise.resolve(it),
14+
};
1115
const getRepository = stub()
12-
.withArgs(Role).returns(ineeda<Repository<Role>>())
13-
.withArgs(User).returns(ineeda<Repository<User>>());
16+
.withArgs(Context).returns(ineeda<Repository<Context>>(repository))
17+
.withArgs(Role).returns(ineeda<Repository<Role>>(repository))
18+
.withArgs(User).returns(ineeda<Repository<User>>(repository));
1419

1520
return ineeda<Storage>({
1621
getCustomRepository: () => ineeda<UserRepository>(),

test/listener/TestLoopbackListener.ts

Lines changed: 107 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,134 @@
11
import { expect } from 'chai';
22
import { ineeda } from 'ineeda';
3-
import { spy } from 'sinon';
3+
import { match, spy } from 'sinon';
44

55
import { Bot } from '../../src/Bot';
66
import { INJECT_BOT } from '../../src/BotService';
7+
import { User } from '../../src/entity/auth/User';
8+
import { Context } from '../../src/entity/Context';
79
import { Message } from '../../src/entity/Message';
10+
import { NotImplementedError } from '../../src/error/NotImplementedError';
811
import { LoopbackListener } from '../../src/listener/LoopbackListener';
12+
import { Service } from '../../src/Service';
13+
import { TYPE_TEXT } from '../../src/utils/Mime';
914
import { describeLeaks, itLeaks } from '../helpers/async';
1015
import { createService, createServiceContainer } from '../helpers/container';
1116

17+
const TEST_METADATA = {
18+
kind: 'loopback-listener',
19+
name: 'test-listener',
20+
};
21+
22+
const TEST_TARGET = {
23+
kind: 'test-target',
24+
name: 'test-target',
25+
};
26+
1227
describeLeaks('loopback listener', async () => {
1328
itLeaks('should send messages to the bot', async () => {
29+
const { container, services } = await createServiceContainer();
30+
31+
const svc = ineeda<Service>(TEST_TARGET);
32+
services.addService(svc);
33+
1434
const receive = spy();
15-
const { container } = await createServiceContainer();
1635
const listener = await createService(container, LoopbackListener, {
1736
[INJECT_BOT]: ineeda<Bot>({
1837
receive,
1938
}),
2039
data: {
40+
defaultTarget: TEST_TARGET,
2141
filters: [],
2242
strict: false,
2343
},
24-
metadata: {
25-
kind: 'loopback-listener',
26-
name: 'test-listener',
27-
},
44+
metadata: TEST_METADATA,
2845
});
46+
await listener.start();
47+
48+
const ctxOptions = {
49+
name: 'test-user',
50+
uid: 'test-uid',
51+
};
52+
const msgOptions = {
53+
body: 'test-body',
54+
type: TYPE_TEXT,
55+
};
2956

30-
const msg = ineeda<Message>();
57+
const msg = new Message({
58+
context: new Context({
59+
channel: {
60+
id: '',
61+
thread: '',
62+
},
63+
...ctxOptions,
64+
}),
65+
labels: {},
66+
reactions: [],
67+
...msgOptions,
68+
});
3169
await listener.send(msg);
3270

33-
expect(receive).to.have.callCount(1).and.been.calledWith(msg);
71+
expect(receive).to.have.callCount(1)
72+
.and.been.calledWithMatch(match.has('body', msgOptions.body)
73+
.and(match.has('type', msgOptions.type)));
74+
});
75+
76+
itLeaks('should throw when fetching messages', async () => {
77+
const { container, services } = await createServiceContainer();
78+
79+
const svc = ineeda<Service>(TEST_TARGET);
80+
services.addService(svc);
81+
82+
const listener = await createService(container, LoopbackListener, {
83+
data: {
84+
defaultTarget: TEST_TARGET,
85+
filters: [],
86+
strict: false,
87+
},
88+
metadata: TEST_METADATA,
89+
});
90+
await listener.start();
91+
92+
await expect(listener.fetch({
93+
channel: '',
94+
})).to.eventually.be.rejectedWith(NotImplementedError);
95+
});
96+
97+
itLeaks('should throw when creating sessions', async () => {
98+
const { container, services } = await createServiceContainer();
99+
100+
const svc = ineeda<Service>(TEST_TARGET);
101+
services.addService(svc);
102+
103+
const listener = await createService(container, LoopbackListener, {
104+
data: {
105+
defaultTarget: TEST_TARGET,
106+
filters: [],
107+
strict: false,
108+
},
109+
metadata: TEST_METADATA,
110+
});
111+
await listener.start();
112+
113+
await expect(listener.createSession('test', ineeda<User>())).to.eventually.be.rejectedWith(NotImplementedError);
114+
});
115+
116+
itLeaks('should not provide sessions', async () => {
117+
const { container, services } = await createServiceContainer();
118+
119+
const svc = ineeda<Service>(TEST_TARGET);
120+
services.addService(svc);
121+
122+
const listener = await createService(container, LoopbackListener, {
123+
data: {
124+
defaultTarget: TEST_TARGET,
125+
filters: [],
126+
strict: false,
127+
},
128+
metadata: TEST_METADATA,
129+
});
130+
await listener.start();
131+
132+
await expect(listener.getSession('test')).to.eventually.equal(undefined);
34133
});
35134
});

0 commit comments

Comments
 (0)