You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-31 15:24:23 +03:00
Add unit tests for hangup / reject (#2606)
* Add unit tests for hangup / reject Fixes https://github.com/vector-im/element-call/issues/537 * Fix some bugs where we carried on with the call after it had been ended
This commit is contained in:
@ -109,6 +109,12 @@ export class MockRTCPeerConnection {
|
|||||||
sdp: DUMMY_SDP,
|
sdp: DUMMY_SDP,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
createAnswer() {
|
||||||
|
return Promise.resolve({
|
||||||
|
type: 'answer',
|
||||||
|
sdp: DUMMY_SDP,
|
||||||
|
});
|
||||||
|
}
|
||||||
setRemoteDescription() {
|
setRemoteDescription() {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,9 @@ import {
|
|||||||
installWebRTCMocks,
|
installWebRTCMocks,
|
||||||
} from "../../test-utils/webrtc";
|
} from "../../test-utils/webrtc";
|
||||||
import { CallFeed } from "../../../src/webrtc/callFeed";
|
import { CallFeed } from "../../../src/webrtc/callFeed";
|
||||||
import { EventType } from "../../../src";
|
import { EventType, MatrixEvent } from "../../../src";
|
||||||
|
|
||||||
|
const FAKE_ROOM_ID = "!foo:bar";
|
||||||
|
|
||||||
const startVoiceCall = async (client: TestClient, call: MatrixCall): Promise<void> => {
|
const startVoiceCall = async (client: TestClient, call: MatrixCall): Promise<void> => {
|
||||||
const callPromise = call.placeVoiceCall();
|
const callPromise = call.placeVoiceCall();
|
||||||
@ -43,6 +45,31 @@ const startVideoCall = async (client: TestClient, call: MatrixCall): Promise<voi
|
|||||||
call.getOpponentMember = jest.fn().mockReturnValue({ userId: "@bob:bar.uk" });
|
call.getOpponentMember = jest.fn().mockReturnValue({ userId: "@bob:bar.uk" });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fakeIncomingCall = async (client: TestClient, call: MatrixCall, version: string | number = "1") => {
|
||||||
|
const callPromise = call.initWithInvite({
|
||||||
|
getContent: jest.fn().mockReturnValue({
|
||||||
|
version,
|
||||||
|
call_id: "call_id",
|
||||||
|
party_id: "remote_party_id",
|
||||||
|
offer: {
|
||||||
|
sdp: DUMMY_SDP,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
getSender: () => "@test:foo",
|
||||||
|
getLocalAge: () => null,
|
||||||
|
} as unknown as MatrixEvent);
|
||||||
|
call.getFeeds().push(new CallFeed({
|
||||||
|
client: client.client,
|
||||||
|
userId: "remote_user_id",
|
||||||
|
// @ts-ignore Mock
|
||||||
|
stream: new MockMediaStream("remote_stream_id", [new MockMediaStreamTrack("remote_tack_id")]),
|
||||||
|
id: "remote_feed_id",
|
||||||
|
purpose: SDPStreamMetadataPurpose.Usermedia,
|
||||||
|
}));
|
||||||
|
await client.httpBackend.flush("");
|
||||||
|
await callPromise;
|
||||||
|
};
|
||||||
|
|
||||||
describe('Call', function() {
|
describe('Call', function() {
|
||||||
let client;
|
let client;
|
||||||
let call;
|
let call;
|
||||||
@ -60,7 +87,7 @@ describe('Call', function() {
|
|||||||
client = new TestClient("@alice:foo", "somedevice", "token", undefined, {});
|
client = new TestClient("@alice:foo", "somedevice", "token", undefined, {});
|
||||||
// We just stub out sendEvent: we're not interested in testing the client's
|
// We just stub out sendEvent: we're not interested in testing the client's
|
||||||
// event sending code here
|
// event sending code here
|
||||||
client.client.sendEvent = () => {};
|
client.client.sendEvent = jest.fn();
|
||||||
client.client.mediaHandler = new MockMediaHandler;
|
client.client.mediaHandler = new MockMediaHandler;
|
||||||
client.client.getMediaHandler = () => client.client.mediaHandler;
|
client.client.getMediaHandler = () => client.client.mediaHandler;
|
||||||
client.httpBackend.when("GET", "/voip/turnServer").respond(200, {});
|
client.httpBackend.when("GET", "/voip/turnServer").respond(200, {});
|
||||||
@ -74,7 +101,7 @@ describe('Call', function() {
|
|||||||
|
|
||||||
call = new MatrixCall({
|
call = new MatrixCall({
|
||||||
client: client.client,
|
client: client.client,
|
||||||
roomId: '!foo:bar',
|
roomId: FAKE_ROOM_ID,
|
||||||
});
|
});
|
||||||
// call checks one of these is wired up
|
// call checks one of these is wired up
|
||||||
call.on('error', () => {});
|
call.on('error', () => {});
|
||||||
@ -594,28 +621,7 @@ describe('Call', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should end call after receiving a select event with a different party id", async () => {
|
it("should end call after receiving a select event with a different party id", async () => {
|
||||||
const callPromise = call.initWithInvite({
|
await fakeIncomingCall(client, call);
|
||||||
getContent: () => ({
|
|
||||||
version: 1,
|
|
||||||
call_id: "call_id",
|
|
||||||
party_id: "remote_party_id",
|
|
||||||
offer: {
|
|
||||||
sdp: DUMMY_SDP,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
getSender: () => "@test:foo",
|
|
||||||
getLocalAge: () => null,
|
|
||||||
});
|
|
||||||
call.feeds.push(new CallFeed({
|
|
||||||
client,
|
|
||||||
userId: "remote_user_id",
|
|
||||||
// @ts-ignore Mock
|
|
||||||
stream: new MockMediaStream("remote_stream_id", [new MockMediaStreamTrack("remote_tack_id")]),
|
|
||||||
id: "remote_feed_id",
|
|
||||||
purpose: SDPStreamMetadataPurpose.Usermedia,
|
|
||||||
}));
|
|
||||||
await client.httpBackend.flush();
|
|
||||||
await callPromise;
|
|
||||||
|
|
||||||
const callHangupCallback = jest.fn();
|
const callHangupCallback = jest.fn();
|
||||||
call.on(CallEvent.Hangup, callHangupCallback);
|
call.on(CallEvent.Hangup, callHangupCallback);
|
||||||
@ -845,4 +851,72 @@ describe('Call', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("rejecting calls", () => {
|
||||||
|
it("sends hangup event when rejecting v0 calls", async () => {
|
||||||
|
await fakeIncomingCall(client, call, 0);
|
||||||
|
|
||||||
|
call.reject();
|
||||||
|
|
||||||
|
expect(client.client.sendEvent).toHaveBeenCalledWith(
|
||||||
|
FAKE_ROOM_ID,
|
||||||
|
EventType.CallHangup,
|
||||||
|
expect.objectContaining({
|
||||||
|
call_id: call.callId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sends reject event when rejecting v1 calls", async () => {
|
||||||
|
await fakeIncomingCall(client, call, "1");
|
||||||
|
|
||||||
|
call.reject();
|
||||||
|
|
||||||
|
expect(client.client.sendEvent).toHaveBeenCalledWith(
|
||||||
|
FAKE_ROOM_ID,
|
||||||
|
EventType.CallReject,
|
||||||
|
expect.objectContaining({
|
||||||
|
call_id: call.callId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not reject a call that has already been answered", async () => {
|
||||||
|
await fakeIncomingCall(client, call, "1");
|
||||||
|
|
||||||
|
await call.answer();
|
||||||
|
|
||||||
|
client.client.sendEvent.mockReset();
|
||||||
|
|
||||||
|
let caught = false;
|
||||||
|
try {
|
||||||
|
call.reject();
|
||||||
|
} catch (e) {
|
||||||
|
caught = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(caught).toEqual(true);
|
||||||
|
expect(client.client.sendEvent).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
call.hangup();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("hangs up a call", async () => {
|
||||||
|
await fakeIncomingCall(client, call, "1");
|
||||||
|
|
||||||
|
await call.answer();
|
||||||
|
|
||||||
|
client.client.sendEvent.mockReset();
|
||||||
|
|
||||||
|
call.hangup();
|
||||||
|
|
||||||
|
expect(client.client.sendEvent).toHaveBeenCalledWith(
|
||||||
|
FAKE_ROOM_ID,
|
||||||
|
EventType.CallHangup,
|
||||||
|
expect.objectContaining({
|
||||||
|
call_id: call.callId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1569,6 +1569,10 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await this.peerConn.setLocalDescription(answer);
|
await this.peerConn.setLocalDescription(answer);
|
||||||
|
|
||||||
|
// make sure we're still going
|
||||||
|
if (this.callHasEnded()) return;
|
||||||
|
|
||||||
this.setState(CallState.Connecting);
|
this.setState(CallState.Connecting);
|
||||||
|
|
||||||
// Allow a short time for initial candidates to be gathered
|
// Allow a short time for initial candidates to be gathered
|
||||||
@ -1576,6 +1580,9 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
|
|||||||
setTimeout(resolve, 200);
|
setTimeout(resolve, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// make sure the call hasn't ended before we continue
|
||||||
|
if (this.callHasEnded()) return;
|
||||||
|
|
||||||
this.sendAnswer();
|
this.sendAnswer();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.debug(`Call ${this.callId} Error setting local description!`, err);
|
logger.debug(`Call ${this.callId} Error setting local description!`, err);
|
||||||
|
Reference in New Issue
Block a user