Skip to content

Commit 0c8e8fb

Browse files
committed
chore(@nestjs/microservices) add tests to grpc clients disconnection
1 parent f337206 commit 0c8e8fb

1 file changed

Lines changed: 72 additions & 3 deletions

File tree

packages/microservices/test/client/client-grpc.spec.ts

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ describe('ClientGrpcProxy', () => {
5555
const cln = { [methodName]: { responseStream: false } };
5656
const spy = sinon.spy(client, 'createUnaryServiceMethod');
5757
client.createServiceMethod(cln, methodName);
58-
58+
5959
expect(spy.called).to.be.true;
6060
});
6161
});
@@ -71,7 +71,7 @@ describe('ClientGrpcProxy', () => {
7171
const obj = { [methodName]: () => ({ on: (type, fn) => fn() }) };
7272

7373
let stream$: Observable<any>;
74-
74+
7575
beforeEach(() => {
7676
stream$ = client.createStreamServiceMethod(obj, methodName)();
7777
});
@@ -83,6 +83,75 @@ describe('ClientGrpcProxy', () => {
8383
expect(spy.called).to.be.true;
8484
});
8585
});
86+
87+
describe('flow-control', () => {
88+
const methodName = 'm';
89+
type EvtCallback = (...args: any[]) => void;
90+
let callMock: {
91+
on: (type: string, fn: EvtCallback) => void,
92+
cancel: sinon.SinonSpy,
93+
finished: boolean,
94+
destroy: sinon.SinonSpy,
95+
removeAllListeners: sinon.SinonSpy,
96+
};
97+
let eventCallbacks: { [type: string]: EvtCallback };
98+
let obj;
99+
const dataSpy = sinon.spy();
100+
const errorSpy = sinon.spy();
101+
const completeSpy = sinon.spy();
102+
103+
let stream$: Observable<any>;
104+
105+
beforeEach(() => {
106+
dataSpy.reset();
107+
errorSpy.reset();
108+
completeSpy.reset();
109+
eventCallbacks = {};
110+
callMock = {
111+
on: (type, fn) => eventCallbacks[type] = fn,
112+
cancel: sinon.spy(),
113+
finished: false,
114+
destroy: sinon.spy(),
115+
removeAllListeners: sinon.spy(),
116+
};
117+
obj = { [methodName]: () => callMock };
118+
stream$ = client.createStreamServiceMethod(obj, methodName)();
119+
});
120+
121+
it('propagates server errors', () => {
122+
const err = new Error('something happened');
123+
stream$.subscribe(dataSpy, errorSpy, completeSpy);
124+
eventCallbacks.data('a');
125+
eventCallbacks.data('b');
126+
callMock.finished = true;
127+
eventCallbacks.error(err);
128+
eventCallbacks.data('c');
129+
130+
expect(Object.keys(eventCallbacks).length).to.eq(3);
131+
expect(dataSpy.args).to.eql([['a'], ['b']]);
132+
expect(errorSpy.args[0][0]).to.eql(err);
133+
expect(completeSpy.called).to.be.false;
134+
expect(callMock.cancel.called).to.be.false;
135+
});
136+
137+
it('handles client side cancel', () => {
138+
const grpcServerCancelErrMock = {
139+
details: 'Cancelled',
140+
};
141+
const subscription = stream$.subscribe(dataSpy, errorSpy);
142+
eventCallbacks.data('a');
143+
eventCallbacks.data('b');
144+
subscription.unsubscribe();
145+
eventCallbacks.error(grpcServerCancelErrMock);
146+
eventCallbacks.end();
147+
eventCallbacks.data('c');
148+
149+
expect(callMock.cancel.called, 'should call call.cancel()').to.be.true;
150+
expect(callMock.destroy.called, 'should call call.destroy()').to.be.true;
151+
expect(dataSpy.args).to.eql([['a'], ['b']]);
152+
expect(errorSpy.called, 'should not error if client canceled').to.be.false;
153+
});
154+
});
86155
});
87156

88157
describe('createUnaryServiceMethod', () => {
@@ -95,7 +164,7 @@ describe('ClientGrpcProxy', () => {
95164
const obj = { [methodName]: (callback) => callback(null, {}) };
96165

97166
let stream$: Observable<any>;
98-
167+
99168
beforeEach(() => {
100169
stream$ = client.createUnaryServiceMethod(obj, methodName)();
101170
});

0 commit comments

Comments
 (0)