Skip to content

Commit

Permalink
Add first negotiation tests (#1629)
Browse files Browse the repository at this point in the history
  • Loading branch information
jcague authored Sep 7, 2020
1 parent 196ff1b commit 95fdef6
Show file tree
Hide file tree
Showing 13 changed files with 1,644 additions and 1 deletion.
4 changes: 4 additions & 0 deletions erizo_controller/erizoClient/src/Erizo.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Room from './Room';
import ErizoConnectionManager from './ErizoConnectionManager';
import { LicodeEvent, RoomEvent, StreamEvent, ConnectionEvent } from './Events';
import Stream from './Stream';
import Logger from './utils/Logger';
Expand All @@ -14,6 +15,9 @@ const Erizo = {
ConnectionEvent,
Stream: Stream.bind(null, undefined),
Logger,
_: {
ErizoConnectionManager,
},
};

export default Erizo;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"scripts": {
"buildClient": "cd erizo_controller/erizoClient && ../../node_modules/.bin/gulp",
"test": " ./node_modules/mocha/bin/mocha --exit nuve/nuveAPI/test/* erizo_controller/test/*",
"testNegotiation": " cd test/negotiation && ../../node_modules/mocha/bin/mocha --exit -b ./index.js",
"lintClient": "cd erizo_controller/erizoClient && ../../node_modules/.bin/gulp lint",
"lintErizoController": "./node_modules/.bin/eslint erizo_controller/erizoAgent erizo_controller/erizoController erizo_controller/erizoJS erizo_controller/common erizo_controller/test erizo_controller/ROV",
"lintBasicExample": "./node_modules/.bin/eslint extras/basic_example/basicServer.js extras/basic_example/public",
Expand Down
22 changes: 22 additions & 0 deletions test/negotiation/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const expect = require('chai').expect;
const describeNegotiationTest = require('./utils/NegotiationTest');
const SdpChecker = require('./utils/SdpUtils');

describeNegotiationTest('SDP negotiations started by client', function(ctx) {
ctx.publishToErizoStreamStep();
ctx.subscribeToErizoStreamStep();
ctx.unpublishStreamStep();
ctx.publishToErizoStreamStep();
});

describeNegotiationTest('SDP negotiations started by Erizo', function(ctx) {
ctx.subscribeToErizoStreamStep();
ctx.publishToErizoStreamStep();
ctx.unsubscribeStreamStep();
ctx.subscribeToErizoStreamStep();
});

describeNegotiationTest('Conflicting SDP negotiation started by Erizo and Client', function(ctx) {
ctx.publishAndSubscribeStreamsStep();
ctx.publishAndSubscribeStreamsStep();
});
78 changes: 78 additions & 0 deletions test/negotiation/log4cxx.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Set root logger level to WARN and its only appender to A1.
log4j.rootLogger=WARN, A1

# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
# Print the date in ISO 8601 format
log4j.appender.A1.layout.ConversionPattern=%d - %p [%t] %c - %m%n

log4j.logger.ErizoAPI.OneToManyProcessor=WARN
log4j.logger.ErizoAPI.WebRtcConnection=WARN
log4j.logger.ErizoAPI.MediaStream=WARN

log4j.logger.DtlsTransport=WARN
log4j.logger.LibNiceConnection=WARN
log4j.logger.NicerConnection=WARN
log4j.logger.IceConnection=ERROR
log4j.logger.MediaStream=WARN
log4j.logger.StreamStats=WARN
log4j.logger.OneToManyProcessor=WARN
log4j.logger.TimeoutChecker=WARN
log4j.logger.SdpInfo=WARN
log4j.logger.SrtpChannel=WARN
log4j.logger.Stats=WARN
log4j.logger.WebRtcConnection=WARN

log4j.logger.dtls.DtlsSocket=WARN
log4j.logger.dtls.DtlsFactory=WARN
log4j.logger.dtls.DtlsSocketContext=WARN
log4j.logger.dtls.SSL=WARN

log4j.logger.media.ExternalInput=WARN
log4j.logger.media.ExternalOutput=WARN
log4j.logger.media.InputProcessor=WARN
log4j.logger.media.OneToManyTranscoder=WARN
log4j.logger.media.OutputProcessor=WARN

log4j.logger.media.codecs.VideoEncoder=WARN
log4j.logger.media.codecs.VideoDecoder=WARN
log4j.logger.media.codecs.AudioEncoder=WARN
log4j.logger.media.codecs.AudioDecoder=WARN

log4j.logger.media.mixers.VideoMixer=WARN
log4j.logger.media.mixers.VideoUtils=WARN

log4j.logger.rtp.PacketBufferService=WARN
log4j.logger.rtp.QualityManager=WARN
log4j.logger.rtp.RtcpAggregator=WARN
log4j.logger.rtp.RtcpForwarder=WARN
log4j.logger.rtp.RtpExtensionProcessor=ERROR
log4j.logger.rtp.RtpParser=WARN
log4j.logger.rtp.RtpPacketQueue=WARN
log4j.logger.rtp.RtpRetransmissionHandler=WARN
log4j.logger.rtp.RtpVP8Fragmenter=WARN
log4j.logger.rtp.RtpVP8Parser=ERROR
log4j.logger.rtp.RtpSlideShowHandler=WARN
log4j.logger.rtp.RtpTrackMuteHandler=WARN
log4j.logger.rtp.RtpSink=WARN
log4j.logger.rtp.RtpSource=WARN
log4j.logger.rtp.RtcpFeedbackGenerationHandler=WARN
log4j.logger.rtp.RtpPaddingRemovalHandler=WARN
log4j.logger.rtp.RtcpRrGenerator=WARN
log4j.logger.rtp.RtcpNackGenerator=WARN
log4j.logger.rtp.SRPacketHandler=WARN
log4j.logger.rtp.BandwidthEstimationHandler=WARN
log4j.logger.rtp.SenderBandwidthEstimationHandler=WARN
log4j.logger.rtp.StatsCalculator=WARN
log4j.logger.rtp.LayerDetectorHandler=WARN
log4j.logger.rtp.PeriodicPliHandler=WARN
log4j.logger.rtp.PliPacerHandler=WARN
log4j.logger.rtp.PliPriorityHandler=WARN
log4j.logger.rtp.RtpPaddingGeneratorHandler=WARN
log4j.logger.rtp.RtpPaddingManagerHandler=WARN
log4j.logger.rtp.PacketCodecParser=WARN


32 changes: 32 additions & 0 deletions test/negotiation/log4js_configuration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"appenders": [
{
"type": "console",
"layout": {
"type": "pattern",
"pattern": "%d - %p: %c - %m",
"replaceConsole": true
}
}
],
"levels": {
"AMQPER": "ERROR",
"Client": "ERROR",
"Connection": "ERROR",
"ErizoController": "ERROR",
"ErizoJS": "ERROR",
"ErizoJSController": "ERROR",
"ErizoAgent": "ERROR",
"ErizoAgentReporter": "ERROR",
"EcCloudHandler": "ERROR",
"Publisher": "ERROR",
"Subscriber": "ERROR",
"Room": "ERROR",
"RoomController": "ERROR",
"RovClient":"ERROR",
"RovMetricsServer":"ERROR",
"RovReplManager":"ERROR",
"RPCPublic":"ERROR"
}
}

54 changes: 54 additions & 0 deletions test/negotiation/utils/BrowserInstaller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const puppeteer = require('puppeteer-core');
const cliProgress = require('cli-progress');
const axios = require('axios');

const chromeVersionsUrl = 'http://omahaproxy.appspot.com/all.json';
const platform = 'mac';

let revisionInfo;

const BrowserInstaller = {
installed: false,
revisionInfo: {},
async install(chromeVersion = 'canary') {
const res = await axios( { url: chromeVersionsUrl, method: 'GET', responseType: 'blob' } );
const records = res.data;
let chromeRevision;

records.forEach((record) => {
if (record.os === platform) {
record.versions.forEach((version) => {
if (version.channel === chromeVersion) {
chromeRevision = version.branch_base_position;
}
});
}
});
if (!chromeRevision) {
console.log('Chrome version was not found');
return;
}
const browserFetcher = puppeteer.createBrowserFetcher();
const bar = new cliProgress.SingleBar({
format: `Downloading Chromium r${chromeRevision} [{bar}] {percentage}% | {value}MB/{total}MB`
}, cliProgress.Presets.legacy);
let barStarted = false;
chromeRevision = '801937';
BrowserInstaller.revisionInfo = await browserFetcher.download(chromeRevision, (downloadedBytes, totalBytes) => {
const totalMB = parseInt(totalBytes / 1000000);
const downloadedMB = parseInt(downloadedBytes / 1000000);

if (!barStarted) {
bar.start(totalMB, downloadedMB);
barStarted = true;
}
bar.update(downloadedMB);
});
bar.update(100);
bar.stop();
console.log('');
BrowserInstaller.installed = true;
}
};

module.exports = BrowserInstaller;
113 changes: 113 additions & 0 deletions test/negotiation/utils/ClientConnection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
class ClientConnection {
constructor(page, connectionId) {
this.page = page;
this.options = { p2p: false, simulcast: true, singlePC: false, audio: true, video: true };
this.connectionId = connectionId;
this.erizoId = 'erizoId';
this.sessionId = parseInt(Math.random() * 10000);
this.receivedEndOfCandidates = false;
}

init() {
return this.page.evaluate((connectionId, sessionId, erizoId, options) => {
if (!navigator.connections) {
navigator.connManager = new Erizo._.ErizoConnectionManager();
navigator.connections = {};
navigator.connectionMessages = {};
}
navigator.connectionMessages[connectionId] = [];
navigator.connections[connectionId] = navigator.connManager.getOrBuildErizoConnection({
callback: (message) => {
navigator.connectionMessages[connectionId].push(message);
},
simulcast: options.simulcast,
p2p: options.p2p,
nop2p: !options.p2p,
label: options.label,
video: options.video,
audio: options.audio,
sessionId: sessionId,
connectionId: connectionId
}, erizoId, options.singlePC);
navigator.connections[connectionId].connectionFailed = false;
navigator.connections[connectionId].on('connection-failed', () => {
navigator.connections[connectionId].connectionFailed = true;
});
}, this.connectionId, this.sessionId, this.erizoId, this.options);
}

addStream(stream) {
stream.addedToConnection = true;
return this.page.evaluate((streamId, connectionId) => navigator.connections[connectionId].addStream(navigator.streams[streamId]), stream.id, this.connectionId);
}

removeStream(stream) {
stream.addedToConnection = false;
return this.page.evaluate((streamId, connectionId) => navigator.connections[connectionId].removeStream(navigator.streams[streamId]), stream.id, this.connectionId);
}

async waitForSignalingMessage() {
await this.page.waitForFunction((connectionId) => navigator.connectionMessages[connectionId].length > 0, {}, this.connectionId);
}

async getSignalingMessage() {
await this.waitForSignalingMessage();
return this.page.evaluate((connectionId) => navigator.connectionMessages[connectionId].shift(), this.connectionId);
}

async isConnectionFailed() {
return this.page.evaluate((connectionId) => navigator.connections[connectionId].connectionFailed, this.connectionId);
}

sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

async waitForCandidates() {
let lastCandidateReceived = false;
while(!lastCandidateReceived) {
const signalingMessages = await this.page.evaluate((connectionId) => navigator.connectionMessages[connectionId], this.connectionId);
for (const message of signalingMessages) {
if (message.type === 'candidate' && message.candidate.candidate === 'end') {
lastCandidateReceived = true;
}
}
if (!lastCandidateReceived) {
await this.sleep(100);
}
}
}

async waitForConnected() {
await this.page.waitForFunction((connectionId) => navigator.connections[connectionId].peerConnection.connectionState === 'connected', {}, this.connectionId);
}

async getFSMState() {
const fsmState = await this.page.evaluate((connectionId) => navigator.connections[connectionId].stack.peerConnectionFsm.state, this.connectionId);
return fsmState;
}

processSignalingMessage(message) {
return this.page.evaluate((connectionId, message) => {
navigator.connections[connectionId].processSignalingMessage(message);
}, this.connectionId, message);
}

async getAllCandidates() {
const candidateMessages = [];
let moreCandidates = true;
while(moreCandidates) {
moreCandidates = await this.page.evaluate((connectionId) => navigator.connectionMessages[connectionId].length, this.connectionId) > 0;
if (moreCandidates) {
const clientMessage = await this.page.evaluate((connectionId) => navigator.connectionMessages[connectionId].shift(), this.connectionId);
candidateMessages.push(clientMessage);
}
}
return candidateMessages;
}


}
module.exports = ClientConnection;
47 changes: 47 additions & 0 deletions test/negotiation/utils/ClientStream.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
class ClientStream {
constructor(page) {
this.page = page;
this.id = parseInt(Math.random() * 10000);
this.audio = true;
this.video = true;
this.data = true;
this.label = this.id;
this.addedToConnection = false;
}

init() {
return this.page.evaluate((streamId, audio, video, data) => {
if (!navigator.streamsAccepted) {
navigator.streamsAccepted = {};
navigator.streams = {};
}
const stream = Erizo.Stream({ audio, video, data, attributes: {} });
navigator.streamsAccepted[streamId] = false;
stream.on('access-accepted', () => {
navigator.streamsAccepted[streamId] = true;
});
stream.init();
navigator.streams[streamId] = stream;
}, this.id, this.audio, this.video, this.data);
}

async getLabel() {
const label = await this.page.evaluate((streamId) => {
return navigator.streams[streamId].getLabel();
}, this.id);
this.label = label;
}

waitForAccepted() {
return this.page.waitForFunction((streamId) => navigator.streamsAccepted[streamId], {}, this.id);
}

async remove() {
await this.page.evaluate((streamId) => {
navigator.streams[streamId].close();
delete navigator.streams[streamId];
}, this.id);
}
}

module.exports = ClientStream;
Loading

0 comments on commit 95fdef6

Please sign in to comment.