Skip to content

Commit b8eb8f6

Browse files
committed
Started on the client kafka tests.
1 parent be593af commit b8eb8f6

2 files changed

Lines changed: 223 additions & 8 deletions

File tree

packages/microservices/client/client-kafka.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,16 @@ let kafkaPackage: any = {};
3131

3232
export class ClientKafka extends ClientProxy {
3333
protected readonly logger = new Logger(ClientKafka.name);
34-
private client: Kafka = null;
35-
private consumer: Consumer = null;
36-
private producer: Producer = null;
34+
public client: Kafka = null;
35+
public consumer: Consumer = null;
36+
public producer: Producer = null;
3737
private readonly brokers: string[];
3838
private readonly clientId: string;
3939
private readonly groupId: string;
4040

41-
private consumerAssignments: {[key: string]: number[]} = {};
41+
protected consumerAssignments: {[key: string]: number[]} = {};
4242

43-
private static readonly REPLY_PATTERN_AFFIX: string = '.reply';
43+
protected static readonly REPLY_PATTERN_AFFIX: string = '.reply';
4444

4545
constructor(protected readonly options: KafkaOptions['options']) {
4646
super();
@@ -83,9 +83,7 @@ export class ClientKafka extends ClientProxy {
8383
}));
8484

8585
// set member assignments on join and rebalance
86-
this.consumer.on(this.consumer.events.GROUP_JOIN, (data: ConsumerGroupJoinEvent) => {
87-
this.consumerAssignments = data.payload.memberAssignment;
88-
});
86+
this.consumer.on(this.consumer.events.GROUP_JOIN, this.updateConsumerAssignments);
8987

9088
// connect the producer and consumer
9189
await this.producer.connect();
@@ -97,6 +95,10 @@ export class ClientKafka extends ClientProxy {
9795
return this.producer;
9896
}
9997

98+
public updateConsumerAssignments(data: ConsumerGroupJoinEvent): void {
99+
this.consumerAssignments = data.payload.memberAssignment;
100+
}
101+
100102
public async bindTopics(): Promise<void> {
101103
const requestPatterns = [...this.requestMap.keys()];
102104

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
import { expect } from 'chai';
2+
import { Subject } from 'rxjs';
3+
import * as sinon from 'sinon';
4+
import { ClientKafka } from '../../client/client-kafka';
5+
import { ConsumerEvents, ConsumerGroupJoinEvent } from '../../external/kafka.interface';
6+
import { ERROR_EVENT } from '../../constants';
7+
// tslint:disable:no-string-literal
8+
9+
describe('ClientKafka', () => {
10+
// helpers
11+
const objectToMap = obj =>
12+
new Map(Object.keys(obj).map(key => [key, obj[key]]) as any);
13+
14+
// spys
15+
let client: ClientKafka;
16+
let callback: sinon.SinonSpy;
17+
let connect: sinon.SinonSpy;
18+
let subscribe: sinon.SinonSpy;
19+
let run: sinon.SinonSpy;
20+
let send: sinon.SinonSpy;
21+
let on: sinon.SinonSpy;
22+
23+
// stubs
24+
let consumerStub: sinon.SinonStub;
25+
let producerStub: sinon.SinonStub;
26+
let createClientStub: sinon.SinonStub;
27+
28+
// other
29+
let kafkaClient;
30+
31+
beforeEach(() => {
32+
client = new ClientKafka({});
33+
callback = sinon.spy();
34+
connect = sinon.spy();
35+
subscribe = sinon.spy();
36+
run = sinon.spy();
37+
send = sinon.spy();
38+
on = sinon.spy();
39+
40+
consumerStub = sinon.stub(client, 'consumer')
41+
.callsFake(() => {
42+
return {
43+
connect,
44+
subscribe,
45+
run,
46+
events: {
47+
GROUP_JOIN: 'consumer.group_join'
48+
},
49+
on
50+
};
51+
});
52+
producerStub = sinon.stub(client, 'producer')
53+
.callsFake(() => {
54+
return {
55+
connect,
56+
send
57+
};
58+
});
59+
kafkaClient = {
60+
consumer: consumerStub,
61+
producer: producerStub,
62+
};
63+
64+
createClientStub = sinon.stub(client, 'createClient').callsFake(() => kafkaClient);
65+
});
66+
67+
describe('close', () => {
68+
const consumer = {disconnect: sinon.spy()};
69+
const producer = {disconnect: sinon.spy()};
70+
beforeEach(() => {
71+
(client as any).consumer = consumer;
72+
(client as any).producer = producer;
73+
});
74+
it('should close server', () => {
75+
client.close();
76+
77+
expect(consumer.disconnect.calledOnce).to.be.true;
78+
expect(producer.disconnect.calledOnce).to.be.true;
79+
expect(client.consumer).to.be.null;
80+
expect(client.producer).to.be.null;
81+
expect(client.client).to.be.null;
82+
});
83+
});
84+
85+
describe('connect', () => {
86+
let consumerAssignmentsStub: sinon.SinonStub;
87+
let bindTopicsStub: sinon.SinonStub;
88+
// let handleErrorsSpy: sinon.SinonSpy;
89+
90+
beforeEach(() => {
91+
consumerAssignmentsStub = sinon.stub(client as any, 'consumerAssignments');
92+
bindTopicsStub = sinon.stub(client, 'bindTopics').callsFake(async () => {});
93+
});
94+
95+
it('should expect the connection to be created', async () => {
96+
const connection = await client.connect();
97+
98+
expect(createClientStub.calledOnce).to.be.true;
99+
expect(producerStub.calledOnce).to.be.true;
100+
expect(consumerStub.calledOnce).to.be.true;
101+
102+
expect(on.calledOnce).to.be.true;
103+
expect((client as any).consumerAssignments).to.be.empty;
104+
105+
expect(connect.calledTwice).to.be.true;
106+
107+
expect(bindTopicsStub.calledOnce).to.be.true;
108+
expect(connection).to.deep.equal(producerStub());
109+
});
110+
111+
it('should expect the connection to be reused', async () => {
112+
client.client = kafkaClient;
113+
await client.connect();
114+
115+
expect(createClientStub.calledOnce).to.be.false;
116+
expect(producerStub.calledOnce).to.be.false;
117+
expect(consumerStub.calledOnce).to.be.false;
118+
119+
expect(on.calledOnce).to.be.false;
120+
expect((client as any).consumerAssignments).to.be.empty;
121+
122+
expect(connect.calledTwice).to.be.false;
123+
124+
expect(bindTopicsStub.calledOnce).to.be.false;
125+
});
126+
127+
// beforeEach(() => {
128+
// createClientSpy = sinon.stub(client, 'createClient').callsFake(
129+
// () =>
130+
// ({
131+
// addListener: () => null,
132+
// removeListener: () => null,
133+
// } as any),
134+
// );
135+
// handleErrorsSpy = sinon.spy(client, 'handleError');
136+
137+
// client.connect();
138+
// client['pubClient'] = null;
139+
// });
140+
// afterEach(() => {
141+
// createClientSpy.restore();
142+
// handleErrorsSpy.restore();
143+
// });
144+
// it('should call "createClient" twice', () => {
145+
// expect(createClientSpy.calledTwice).to.be.true;
146+
// });
147+
// it('should call "handleError" twice', () => {
148+
// expect(handleErrorsSpy.calledTwice).to.be.true;
149+
// });
150+
});
151+
152+
describe('updateConsumerAssignments', () => {
153+
it('should update consumer assignments', async () => {
154+
await client.connect();
155+
156+
const consumerAssignments: ConsumerGroupJoinEvent = {
157+
id: 'id',
158+
type: 'type',
159+
timestamp: 1234567890,
160+
payload: {
161+
duration: 20,
162+
groupId: 'group-id',
163+
isLeader: true,
164+
leaderId: 'member-1',
165+
groupProtocol: 'RoundRobin',
166+
memberId: 'member-1',
167+
memberAssignment: {
168+
'topic-a': [0, 1, 2]
169+
}
170+
}
171+
};
172+
173+
client.updateConsumerAssignments(consumerAssignments);
174+
expect((client as any).consumerAssignments).to.deep.eq(consumerAssignments.payload.memberAssignment);
175+
});
176+
});
177+
178+
describe('bindTopics', () => {
179+
it('should bind explicit topics', async () => {
180+
const getReplyPatternSpy = sinon.spy(client as any, 'getReplyPattern');
181+
182+
(client as any).requestMap = objectToMap({
183+
'topic.request': 'topic.request.reply'
184+
});
185+
186+
client.consumer = kafkaClient.consumer();
187+
188+
// await client.connect();
189+
await client.bindTopics();
190+
191+
expect(getReplyPatternSpy.calledOnce).to.be.true;
192+
expect(subscribe.calledOnce).to.be.true;
193+
expect((client as any).getReplyPattern('topic.request', (ClientKafka as any).REPLY_PATTERN_AFFIX)).to.eq('topic.request.reply');
194+
});
195+
196+
it('should bind implicit topics', async () => {
197+
const getReplyPatternSpy = sinon.spy(client as any, 'getReplyPattern');
198+
199+
(client as any).requestMap = objectToMap({
200+
'topic.request.implicit': null
201+
});
202+
203+
client.consumer = kafkaClient.consumer();
204+
205+
// await client.connect();
206+
await client.bindTopics();
207+
208+
expect(getReplyPatternSpy.calledOnce).to.be.true;
209+
expect(subscribe.calledOnce).to.be.true;
210+
expect((client as any).getReplyPattern('topic.request.implicit', (ClientKafka as any).REPLY_PATTERN_AFFIX)).to.eq('topic.request.implicit.reply');
211+
});
212+
});
213+
});

0 commit comments

Comments
 (0)