mirror of
https://github.com/jambonz/sbc-inbound.git
synced 2026-01-24 22:37:51 +00:00
revamp to mysql for gateway configuration and major code refactor
This commit is contained in:
@@ -4,6 +4,6 @@ node_js:
|
||||
- "lts/*"
|
||||
services:
|
||||
- docker
|
||||
- mysql
|
||||
script:
|
||||
- npm test
|
||||
|
||||
111
README.md
111
README.md
@@ -32,84 +32,77 @@ the `rtpengine` object specifies the location of the rtpengine, which will typic
|
||||
"level": "info"
|
||||
}
|
||||
```
|
||||
##### authentication web callback
|
||||
##### application server location
|
||||
The sip trunk routing to internal application servers are specified as an array of IP addresses.
|
||||
```
|
||||
"authCallback": {
|
||||
"uri": "http://example.com/auth",
|
||||
"auth": {
|
||||
"username": "foo",
|
||||
"password": "bar"
|
||||
}
|
||||
"trunks": {
|
||||
"appserver": ["sip:10.10.120.1"]
|
||||
}
|
||||
```
|
||||
##### transcoding options
|
||||
The transcoding options for rtpengine are found in the configuration file, however these should not need to be modified.
|
||||
```
|
||||
"transcoding": {
|
||||
"rtpCharacteristics" : {
|
||||
"transport protocol": "RTP/AVP",
|
||||
"DTLS": "off",
|
||||
"SDES": "off",
|
||||
"ICE": "remove",
|
||||
"rtcp-mux": ["demux"]
|
||||
},
|
||||
"srtpCharacteristics": {
|
||||
"transport-protocol": "UDP/TLS/RTP/SAVPF",
|
||||
"ICE": "force",
|
||||
"SDES": "off",
|
||||
"flags": ["generate mid", "SDES-no"],
|
||||
"rtcp-mux": ["require"]
|
||||
}
|
||||
}
|
||||
```
|
||||
the `authCallback` object specifies the http(s) url that a POST request will be sent to for each incoming REGISTER request. The body of the POST will be a json payload including the following information:
|
||||
## Authentication
|
||||
Authenticating users is the responsibility of the client by exposing an http callback. A POST request will be sent to the configured callback (i.e. the value in the `accounts.registration_hook` column in the associated sip realm value in the REGISTER request). The body of the POST will be a json payload including the following information:
|
||||
```
|
||||
{
|
||||
"method": "REGISTER",
|
||||
"username": "daveh",
|
||||
"realm": "drachtio.org",
|
||||
"nonce": "2q4gct3g3ghbfj34h3",
|
||||
"uri": "sip:dhorton@drachtio.org",
|
||||
"response": "djaduys9g9d",
|
||||
}
|
||||
{
|
||||
"method": "REGISTER",
|
||||
"expires": 3600,
|
||||
"scheme": "digest",
|
||||
"username": "john",
|
||||
"realm": "jambonz.org",
|
||||
"nonce": "157590482938000",
|
||||
"uri": "sip:172.37.0.10:5060",
|
||||
"response": "be641cf7951ff23ab04c57907d59f37d",
|
||||
"qop": "auth",
|
||||
"nc": "00000001",
|
||||
"cnonce": "6b8b4567",
|
||||
"algorithm": "MD5"
|
||||
}
|
||||
```
|
||||
It is the responsibility of the customer-side logic to retrieve the associated password for the given username and authenticate the request by calculating a response token (per the algorithm described in [RFC 2617](https://tools.ietf.org/html/rfc2617#section-3.2.2)) and comparing it to that provided in the request.
|
||||
It is the responsibility of the customer-side logic to retrieve the associated password for the given username and to then authenticate the request by calculating a response hash value (per the algorithm described in [RFC 2617](https://tools.ietf.org/html/rfc2617#section-3.2.2)) and comparing it to the response property in the http body.
|
||||
|
||||
The `auth` property in the `authCallback` object is optional. It should be provided if the customer callback is using HTTP Basic Authentication to protect the endpoint.
|
||||
For example code showing how to calculate the response hash given the above inputs, [see here](https://github.com/jambonz/customer-auth-server/blob/master/lib/utils.js).
|
||||
|
||||
If the request is successfully authenticated, the callback should return a 200 OK response with a JSON body including:
|
||||
For a simple, full-fledged example server doing the same, [see here](https://github.com/jambonz/customer-auth-server).
|
||||
|
||||
The customer server SHOULD return a 200 OK response to the http request in all cases with a json body indicating whether the request was successfully authenticated.
|
||||
|
||||
The body MUST include a `status` field with a value of either `ok` or `fail`, indicating whether the request was authenticated or not.
|
||||
```
|
||||
{"status": "ok"}
|
||||
```
|
||||
This will signal the application to accept the registration request, respond accordingly to the client, and update the redis database with the active registration.
|
||||
|
||||
In the case of failure, the customer-side application *should* return a 'msg' property indicating the reason, e.g.
|
||||
Additionally, in the case of failure, the body MAY include a `msg` field with a human-readable description of why the authentication failed.
|
||||
```
|
||||
{"status": "fail", "msg": "invalid username"}
|
||||
```
|
||||
##### sip trunks
|
||||
Inbound sip trunks are configured by specifing name and associated ip addresses. Additionally, the sip trunk for internal jambonz application servers is specified as an array of IP addresses.
|
||||
```
|
||||
"trunks": {
|
||||
"inbound": [
|
||||
{
|
||||
"name": "carrier1",
|
||||
"host": ["10.123.22.3"]
|
||||
}
|
||||
],
|
||||
"appserver": ["sip:10.10.120.1"]
|
||||
}
|
||||
```
|
||||
##### transcoding options
|
||||
The transcoding options for rtpengine are found in the configuration file, however these should not need to be modified.
|
||||
```
|
||||
"transcoding": {
|
||||
"rtpCharacteristics" : {
|
||||
"transport protocol": "RTP/AVP",
|
||||
"DTLS": "off",
|
||||
"SDES": "off",
|
||||
"ICE": "remove",
|
||||
"rtcp-mux": ["demux"]
|
||||
},
|
||||
"srtpCharacteristics": {
|
||||
"transport-protocol": "UDP/TLS/RTP/SAVPF",
|
||||
"ICE": "force",
|
||||
"SDES": "off",
|
||||
"flags": ["generate mid", "SDES-no"],
|
||||
"rtcp-mux": ["require"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Forwarding behavior
|
||||
This application acts as a back-to-back user agent and media proxy. When sending INVITEs on to the jambonz application servers, it adds the following headers onto the INVITE:
|
||||
|
||||
- `X-Forwarded-For`: the IP address of the client that sent the INVITE
|
||||
- `X-Forwarded-Proto`: the transport protocol used by the client
|
||||
- `X-Forwarded-Carrier`: the name of the inbound carrier, if applicable
|
||||
|
||||
## Tests
|
||||
The automated test suite requires a docker installation.
|
||||
|
||||
#### Running the test suite
|
||||
To run the included test suite, you will need to have a mysql server installed on your laptop/server. You will need to set the MYSQL_ROOT_PASSWORD env variable to the mysql root password before running the tests. The test suite creates a database named 'jambones_test' in your mysql server to run the tests against, and removes it when done.
|
||||
```
|
||||
npm test
|
||||
MYSQL_ROOT_PASSWORD=foobar npm test
|
||||
```
|
||||
|
||||
25
app.js
25
app.js
@@ -2,7 +2,16 @@ const Srf = require('drachtio-srf');
|
||||
const srf = new Srf();
|
||||
const config = require('config');
|
||||
const logger = require('pino')(config.get('logging'));
|
||||
const {auth} = require('./lib/middleware');
|
||||
const {
|
||||
lookupAuthHook,
|
||||
lookupSipGatewayBySignalingAddress
|
||||
} = require('jambonz-db-helpers')(config.get('mysql'), logger);
|
||||
srf.locals.dbHelpers = {
|
||||
lookupAuthHook,
|
||||
lookupSipGatewayBySignalingAddress
|
||||
};
|
||||
const {challengeDeviceCalls} = require('./lib/middleware')(srf, logger);
|
||||
const CallSession = require('./lib/call-session');
|
||||
|
||||
// disable logging in test mode
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
@@ -21,8 +30,18 @@ if (config.has('drachtio.host')) {
|
||||
else {
|
||||
srf.listen(config.get('drachtio'));
|
||||
}
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
srf.on('error', (err) => {
|
||||
logger.info(err, 'Error connecting to drachtio');
|
||||
});
|
||||
}
|
||||
|
||||
srf.use('invite', auth);
|
||||
srf.invite(require('./lib/invite')({log: logger}));
|
||||
// challenge calls from devices, let calls from sip gateways through
|
||||
srf.use('invite', [challengeDeviceCalls]);
|
||||
|
||||
srf.invite((req, res) => {
|
||||
const session = new CallSession(logger, req, res);
|
||||
session.connect();
|
||||
});
|
||||
|
||||
module.exports = {srf};
|
||||
|
||||
@@ -10,21 +10,14 @@
|
||||
"logging": {
|
||||
"level": "info"
|
||||
},
|
||||
"authCallback": {
|
||||
"uri": "http://example.com/auth",
|
||||
"auth": {
|
||||
"user": "foo",
|
||||
"pass": "bar"
|
||||
}
|
||||
"mysql": {
|
||||
"host": "localhost",
|
||||
"user": "jambones",
|
||||
"password": "jambones",
|
||||
"database": "jambones"
|
||||
},
|
||||
"trunks": {
|
||||
"inbound": [
|
||||
{
|
||||
"name": "carrier1",
|
||||
"host": ["10.123.22.3"]
|
||||
}
|
||||
],
|
||||
"appserver": ["sip:10.10.120.1"]
|
||||
"appserver": ["sip:172.38.0.11"]
|
||||
},
|
||||
"transcoding": {
|
||||
"rtpCharacteristics" : {
|
||||
@@ -11,21 +11,14 @@
|
||||
"logging": {
|
||||
"level": "debug"
|
||||
},
|
||||
"authCallback": {
|
||||
"uri": "http://127.0.0.1:4000/auth",
|
||||
"auth": {
|
||||
"user": "foo",
|
||||
"pass ": "bar"
|
||||
}
|
||||
"mysql": {
|
||||
"host": "localhost",
|
||||
"user": "jambones_test",
|
||||
"password": "jambones_test",
|
||||
"database": "jambones_test"
|
||||
},
|
||||
"trunks": {
|
||||
"inbound": [
|
||||
{
|
||||
"name": "carrier1",
|
||||
"host": ["172.38.0.20"]
|
||||
}
|
||||
],
|
||||
"appserver": ["sip:172.38.0.11"]
|
||||
"appserver": ["172.38.0.11"]
|
||||
},
|
||||
"transcoding": {
|
||||
"rtpCharacteristics" : {
|
||||
|
||||
131
lib/call-session.js
Normal file
131
lib/call-session.js
Normal file
@@ -0,0 +1,131 @@
|
||||
const Emitter = require('events');
|
||||
const config = require('config');
|
||||
const Client = require('rtpengine-client').Client ;
|
||||
const rtpengine = new Client();
|
||||
const offer = rtpengine.offer.bind(rtpengine, config.get('rtpengine'));
|
||||
const answer = rtpengine.answer.bind(rtpengine, config.get('rtpengine'));
|
||||
const del = rtpengine.delete.bind(rtpengine, config.get('rtpengine'));
|
||||
const {getAppserver, isWSS, makeRtpEngineOpts} = require('./utils');
|
||||
const {forwardInDialogRequests} = require('drachtio-fn-b2b-sugar');
|
||||
const {parseUri, SipError} = require('drachtio-srf');
|
||||
const debug = require('debug')('jambonz:sbc-inbound');
|
||||
|
||||
class CallSession extends Emitter {
|
||||
constructor(logger, req, res) {
|
||||
super();
|
||||
this.req = req;
|
||||
this.res = res;
|
||||
this.srf = req.srf;
|
||||
this.logger = logger.child({callId: req.get('Call-ID')});
|
||||
}
|
||||
|
||||
async connect() {
|
||||
this.rtpEngineOpts = makeRtpEngineOpts(this.req, isWSS(this.req), false);
|
||||
this.rtpEngineResource = {destroy: del.bind(rtpengine, this.rtpEngineOpts.common)};
|
||||
const obj = parseUri(this.req.uri);
|
||||
const appServer = getAppserver();
|
||||
let proxy, host, uri;
|
||||
|
||||
// replace host part of uri if its an ipv4 address, leave it otherwise
|
||||
if (/\d{1-3}\.\d{1-3}\.\d{1-3}\.\d{1-3}/.test(obj.host)) {
|
||||
host = obj.host;
|
||||
proxy = appServer;
|
||||
}
|
||||
else {
|
||||
host = appServer;
|
||||
}
|
||||
if (obj.user) uri = `${obj.scheme}:${obj.user}@${host}`;
|
||||
else uri = `${obj.scheme}:${host}`;
|
||||
debug(`uri will be: ${uri}, proxy ${proxy}`);
|
||||
|
||||
try {
|
||||
// rtpengine 'offer'
|
||||
debug('sending offer command to rtpengine');
|
||||
const response = await offer(this.rtpEngineOpts.offer);
|
||||
debug(`response from rtpengine to offer ${JSON.stringify(response)}`);
|
||||
if ('ok' !== response.result) {
|
||||
this.logger.error(`rtpengine offer failed with ${JSON.stringify(response)}`);
|
||||
throw new Error('rtpengine failed: answer');
|
||||
}
|
||||
|
||||
// now send the INVITE in towards the feature servers
|
||||
const headers = {'X-Forwarded-For': this.req.source_address};
|
||||
if (this.req.locals.carrier) Object.assign(headers, {'X-Originating-Carrier': this.req.locals.carrier});
|
||||
|
||||
debug(`sending INVITE to ${proxy} with ${uri}`);
|
||||
const {uas, uac} = await this.srf.createB2BUA(this.req, this.res, uri, {
|
||||
proxy,
|
||||
headers,
|
||||
proxyRequestHeaders: ['all'],
|
||||
proxyResponseHeaders: ['all'],
|
||||
localSdpB: response.sdp,
|
||||
localSdpA: async(sdp, res) => {
|
||||
const opts = Object.assign({sdp, 'to-tag': res.getParsedHeader('To').params.tag},
|
||||
this.rtpEngineOpts.answer);
|
||||
const response = await answer(opts);
|
||||
if ('ok' !== response.result) {
|
||||
this.logger.error(`rtpengine answer failed with ${JSON.stringify(response)}`);
|
||||
throw new Error('rtpengine failed: answer');
|
||||
}
|
||||
return response.sdp;
|
||||
}
|
||||
});
|
||||
|
||||
// successfully connected
|
||||
this.logger.info('call connected');
|
||||
debug('call connected');
|
||||
this.emit('connected');
|
||||
|
||||
this._setHandlers({uas, uac});
|
||||
return;
|
||||
} catch (err) {
|
||||
if (err instanceof SipError) {
|
||||
this.logger.info(`call failed with ${err.status}`);
|
||||
this.emit('failed');
|
||||
this.rtpEngineResource.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_setHandlers({uas, uac}) {
|
||||
this.uas = uas;
|
||||
this.uac = uac;
|
||||
[uas, uac].forEach((dlg) => {
|
||||
//hangup
|
||||
dlg.on('destroy', () => {
|
||||
this.logger.info('call ended');
|
||||
this.rtpEngineResource.destroy();
|
||||
});
|
||||
|
||||
//re-invite
|
||||
dlg.on('modify', this._onReinvite.bind(this, dlg));
|
||||
});
|
||||
|
||||
// default forwarding of other request types
|
||||
forwardInDialogRequests(uas);
|
||||
}
|
||||
|
||||
async _onReinvite(dlg, req, res) {
|
||||
try {
|
||||
let response = await offer(Object.assign({sdp: req.body}, this.rtpEngineOpts.offer));
|
||||
if ('ok' !== response.result) {
|
||||
res.send(488);
|
||||
throw new Error(`_onReinvite: rtpengine failed: offer: ${JSON.stringify(response)}`);
|
||||
}
|
||||
const sdp = await dlg.other.modify(response.sdp);
|
||||
const opts = Object.assign({sdp, 'to-tag': res.getParsedHeader('To').params.tag},
|
||||
this.rtpEngineOpts.answer);
|
||||
response = await answer(opts);
|
||||
if ('ok' !== response.result) {
|
||||
res.send(488);
|
||||
throw new Error(`_onReinvite: rtpengine failed: ${JSON.stringify(response)}`);
|
||||
}
|
||||
res.send(200, {body: response.sdp});
|
||||
} catch (err) {
|
||||
this.logger.error(err, 'Error handling reinvite');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = CallSession;
|
||||
@@ -1,62 +0,0 @@
|
||||
const config = require('config');
|
||||
const Client = require('rtpengine-client').Client ;
|
||||
const rtpengine = new Client();
|
||||
const offer = rtpengine.offer.bind(rtpengine, config.get('rtpengine'));
|
||||
const answer = rtpengine.answer.bind(rtpengine, config.get('rtpengine'));
|
||||
const del = rtpengine.delete.bind(rtpengine, config.get('rtpengine'));
|
||||
const {getAppserver, isWSS, makeRtpEngineOpts} = require('./utils');
|
||||
|
||||
module.exports = handler;
|
||||
|
||||
function handler({log}) {
|
||||
return async(req, res) => {
|
||||
const logger = log.child({callId: req.get('Call-ID')});
|
||||
const srf = req.srf;
|
||||
const rtpEngineOpts = makeRtpEngineOpts(req, isWSS(req), false);
|
||||
const rtpEngineResource = {destroy: del.bind(rtpengine, rtpEngineOpts.common)};
|
||||
const uri = getAppserver();
|
||||
logger.info(`received inbound INVITE from ${req.protocol}/${req.source_address}:${req.source_port}`);
|
||||
try {
|
||||
const response = await offer(rtpEngineOpts.offer);
|
||||
if ('ok' !== response.result) {
|
||||
res.send(480);
|
||||
throw new Error(`failed allocating rtpengine endpoint: ${JSON.stringify(response)}`);
|
||||
}
|
||||
|
||||
const {uas, uac} = await srf.createB2BUA(req, res, uri, {
|
||||
headers: {
|
||||
'X-Forwarded-For': req.source_address,
|
||||
'X-Forwarded-Proto': req.getParsedHeader('Via')[0].protocol.toLowerCase(),
|
||||
'X-Forwarded-Carrier': req.carrier_name
|
||||
},
|
||||
proxyRequestHeaders: ['User-Agent', 'Subject'],
|
||||
localSdpB: response.sdp,
|
||||
localSdpA: (sdp, res) => {
|
||||
const opts = Object.assign({sdp, 'to-tag': res.getParsedHeader('To').params.tag},
|
||||
rtpEngineOpts.answer);
|
||||
return answer(opts)
|
||||
.then((response) => {
|
||||
if ('ok' !== response.result) throw new Error('error allocating rtpengine');
|
||||
return response.sdp;
|
||||
});
|
||||
}
|
||||
});
|
||||
logger.info('call connected');
|
||||
setHandlers(logger, uas, uac, rtpEngineResource);
|
||||
|
||||
} catch (err) {
|
||||
logger.error(err, 'Error connecting call');
|
||||
rtpEngineResource.destroy();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function setHandlers(logger, uas, uac, rtpEngineResource) {
|
||||
[uas, uac].forEach((dlg) => dlg.on('destroy', () => {
|
||||
logger.info('call ended');
|
||||
dlg.other.destroy();
|
||||
rtpEngineResource.destroy();
|
||||
}));
|
||||
|
||||
//TODO: handle re-INVITEs, REFER, INFO
|
||||
}
|
||||
@@ -1,12 +1,28 @@
|
||||
const {fromInboundTrunk} = require('./utils');
|
||||
const config = require('config');
|
||||
const authenticator = require('drachtio-http-authenticator')(config.get('authCallback'));
|
||||
const debug = require('debug')('jambonz:sbc-inbound');
|
||||
|
||||
function auth(req, res, next) {
|
||||
if (fromInboundTrunk(req)) {
|
||||
return next();
|
||||
module.exports = function(srf, logger) {
|
||||
const {lookupSipGatewayBySignalingAddress, lookupAuthHook} = srf.locals.dbHelpers;
|
||||
const authenticator = require('drachtio-http-authenticator')(lookupAuthHook, logger);
|
||||
|
||||
async function challengeDeviceCalls(req, res, next) {
|
||||
req.locals = req.locals || {};
|
||||
try {
|
||||
const gateway = await lookupSipGatewayBySignalingAddress(req.source_address, req.source_port);
|
||||
if (!gateway) {
|
||||
req.locals.originator = 'device';
|
||||
return authenticator(req, res, next);
|
||||
}
|
||||
debug(`challengeDeviceCalls: call came from gateway: ${JSON.stringify(gateway)}`);
|
||||
req.locals.originator = 'trunk';
|
||||
req.locals.carrier = gateway.name;
|
||||
next();
|
||||
} catch (err) {
|
||||
logger.error(err, `${req.get('Call-ID')} Error looking up related info for inbound call`);
|
||||
res.send(500);
|
||||
}
|
||||
}
|
||||
authenticator(req, res, next);
|
||||
}
|
||||
|
||||
module.exports = { auth };
|
||||
return {
|
||||
challengeDeviceCalls
|
||||
};
|
||||
};
|
||||
|
||||
11
lib/utils.js
11
lib/utils.js
@@ -1,16 +1,6 @@
|
||||
const config = require('config');
|
||||
let idx = 0;
|
||||
|
||||
function fromInboundTrunk(req) {
|
||||
const trunks = config.has('trunks.inbound') ?
|
||||
config.get('trunks.inbound') : [];
|
||||
if (isWSS(req)) return false;
|
||||
const trunk = trunks.find((t) => t.host.includes(req.source_address));
|
||||
if (!trunk) return false;
|
||||
req.carrier_name = trunk.name;
|
||||
return true;
|
||||
}
|
||||
|
||||
function isWSS(req) {
|
||||
return req.getParsedHeader('Via')[0].protocol.toLowerCase().startsWith('ws');
|
||||
}
|
||||
@@ -34,7 +24,6 @@ function makeRtpEngineOpts(req, srcIsUsingSrtp, dstIsUsingSrtp) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fromInboundTrunk,
|
||||
isWSS,
|
||||
getAppserver,
|
||||
makeRtpEngineOpts
|
||||
|
||||
20
package.json
20
package.json
@@ -18,20 +18,24 @@
|
||||
"jslint": "eslint app.js lib"
|
||||
},
|
||||
"dependencies": {
|
||||
"config": "^3.2.2",
|
||||
"drachtio-http-authenticator": "0.0.5",
|
||||
"drachtio-srf": "^4.4.14",
|
||||
"pino": "^5.13.2",
|
||||
"rtpengine-client": "0.0.8"
|
||||
"config": "^3.2.4",
|
||||
"debug": "^4.1.1",
|
||||
"drachtio-fn-b2b-sugar": "0.0.12",
|
||||
"drachtio-http-authenticator": "^0.1.7",
|
||||
"drachtio-srf": "^4.4.25",
|
||||
"jambonz-db-helpers": "^0.1.2",
|
||||
"pino": "^5.14.0",
|
||||
"rtpengine-client": "^0.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"blue-tape": "^1.0.0",
|
||||
"clear-module": "^4.0.0",
|
||||
"eslint": "^6.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"nyc": "^14.1.1",
|
||||
"tap": "^14.6.1",
|
||||
"tap": "^14.10.2",
|
||||
"tap-dot": "^2.0.0",
|
||||
"tap-spec": "^5.0.0"
|
||||
"tap-spec": "^5.0.0",
|
||||
"tape": "^4.11.0"
|
||||
}
|
||||
}
|
||||
|
||||
27
test/create-test-db.js
Normal file
27
test/create-test-db.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const test = require('tape').test ;
|
||||
const exec = require('child_process').exec ;
|
||||
const pwd = process.env.TRAVIS ? '' : '-p$MYSQL_ROOT_PASSWORD';
|
||||
|
||||
test('creating jambones_test database', (t) => {
|
||||
exec(`mysql -h localhost -u root ${pwd} < ${__dirname}/db/create_test_db.sql`, (err, stdout, stderr) => {
|
||||
if (err) return t.end(err);
|
||||
t.pass('database successfully created');
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test('creating schema', (t) => {
|
||||
exec(`mysql -h localhost -u root ${pwd} -D jambones_test < ${__dirname}/db/jambones-sql.sql`, (err, stdout, stderr) => {
|
||||
if (err) return t.end(err);
|
||||
t.pass('schema successfully created');
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test('populating test case data', (t) => {
|
||||
exec(`mysql -h localhost -u root ${pwd} -D jambones_test < ${__dirname}/db/populate-test-data.sql`, (err, stdout, stderr) => {
|
||||
if (err) return t.end(err);
|
||||
t.pass('test data set created');
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
3
test/db/create_test_db.sql
Normal file
3
test/db/create_test_db.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
create database jambones_test;
|
||||
create user jambones_test@localhost IDENTIFIED WITH mysql_native_password by 'jambones_test';
|
||||
grant all on jambones_test.* to jambones_test@localhost;
|
||||
272
test/db/jambones-sql.sql
Normal file
272
test/db/jambones-sql.sql
Normal file
@@ -0,0 +1,272 @@
|
||||
/* SQLEditor (MySQL (2))*/
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `call_routes`;
|
||||
|
||||
DROP TABLE IF EXISTS `conference_participants`;
|
||||
|
||||
DROP TABLE IF EXISTS `queue_members`;
|
||||
|
||||
DROP TABLE IF EXISTS `calls`;
|
||||
|
||||
DROP TABLE IF EXISTS `phone_numbers`;
|
||||
|
||||
DROP TABLE IF EXISTS `applications`;
|
||||
|
||||
DROP TABLE IF EXISTS `conferences`;
|
||||
|
||||
DROP TABLE IF EXISTS `queues`;
|
||||
|
||||
DROP TABLE IF EXISTS `subscriptions`;
|
||||
|
||||
DROP TABLE IF EXISTS `registrations`;
|
||||
|
||||
DROP TABLE IF EXISTS `api_keys`;
|
||||
|
||||
DROP TABLE IF EXISTS `accounts`;
|
||||
|
||||
DROP TABLE IF EXISTS `service_providers`;
|
||||
|
||||
DROP TABLE IF EXISTS `sip_gateways`;
|
||||
|
||||
DROP TABLE IF EXISTS `voip_carriers`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `applications`
|
||||
(
|
||||
`application_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`account_sid` CHAR(36) NOT NULL,
|
||||
`call_hook` VARCHAR(255) NOT NULL,
|
||||
`call_status_hook` VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY (`application_sid`)
|
||||
) ENGINE=InnoDB COMMENT='A defined set of behaviors to be applied to phone calls with';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `call_routes`
|
||||
(
|
||||
`call_route_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`order` INTEGER NOT NULL,
|
||||
`account_sid` CHAR(36) NOT NULL,
|
||||
`regex` VARCHAR(255) NOT NULL,
|
||||
`application_sid` CHAR(36) NOT NULL,
|
||||
PRIMARY KEY (`call_route_sid`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `conferences`
|
||||
(
|
||||
`id` INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE ,
|
||||
`conference_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`name` VARCHAR(255),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB COMMENT='An audio conference';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `conference_participants`
|
||||
(
|
||||
`conference_participant_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`call_sid` CHAR(36),
|
||||
`conference_sid` CHAR(36) NOT NULL,
|
||||
PRIMARY KEY (`conference_participant_sid`)
|
||||
) ENGINE=InnoDB COMMENT='A relationship between a call and a conference that it is co';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `queues`
|
||||
(
|
||||
`id` INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE ,
|
||||
`queue_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`name` VARCHAR(255),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB COMMENT='A set of behaviors to be applied to parked calls';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `registrations`
|
||||
(
|
||||
`registration_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`username` VARCHAR(255) NOT NULL,
|
||||
`domain` VARCHAR(255) NOT NULL,
|
||||
`sip_contact` VARCHAR(255) NOT NULL,
|
||||
`sip_user_agent` VARCHAR(255),
|
||||
PRIMARY KEY (`registration_sid`)
|
||||
) ENGINE=InnoDB COMMENT='An active sip registration';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `queue_members`
|
||||
(
|
||||
`queue_member_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`call_sid` CHAR(36),
|
||||
`queue_sid` CHAR(36) NOT NULL,
|
||||
`position` INTEGER,
|
||||
PRIMARY KEY (`queue_member_sid`)
|
||||
) ENGINE=InnoDB COMMENT='A relationship between a call and a queue that it is waiting';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `calls`
|
||||
(
|
||||
`call_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`parent_call_sid` CHAR(36),
|
||||
`application_sid` CHAR(36),
|
||||
`status_url` VARCHAR(255),
|
||||
`time_start` DATETIME NOT NULL,
|
||||
`time_alerting` DATETIME,
|
||||
`time_answered` DATETIME,
|
||||
`time_ended` DATETIME,
|
||||
`direction` ENUM('inbound','outbound'),
|
||||
`phone_number_sid` CHAR(36),
|
||||
`inbound_user_sid` CHAR(36),
|
||||
`outbound_user_sid` CHAR(36),
|
||||
`calling_number` VARCHAR(255),
|
||||
`called_number` VARCHAR(255),
|
||||
`caller_name` VARCHAR(255),
|
||||
`status` VARCHAR(255) NOT NULL COMMENT 'Possible values are queued, ringing, in-progress, completed, failed, busy and no-answer',
|
||||
`sip_uri` VARCHAR(255) NOT NULL,
|
||||
`sip_call_id` VARCHAR(255) NOT NULL,
|
||||
`sip_cseq` INTEGER NOT NULL,
|
||||
`sip_from_tag` VARCHAR(255) NOT NULL,
|
||||
`sip_via_branch` VARCHAR(255) NOT NULL,
|
||||
`sip_contact` VARCHAR(255),
|
||||
`sip_final_status` INTEGER UNSIGNED,
|
||||
`sdp_offer` VARCHAR(4096),
|
||||
`sdp_answer` VARCHAR(4096),
|
||||
`source_address` VARCHAR(255) NOT NULL,
|
||||
`source_port` INTEGER UNSIGNED NOT NULL,
|
||||
`dest_address` VARCHAR(255),
|
||||
`dest_port` INTEGER UNSIGNED,
|
||||
`url` VARCHAR(255),
|
||||
PRIMARY KEY (`call_sid`)
|
||||
) ENGINE=InnoDB COMMENT='A phone call';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `service_providers`
|
||||
(
|
||||
`service_provider_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`name` VARCHAR(255) NOT NULL UNIQUE ,
|
||||
`description` VARCHAR(255),
|
||||
`root_domain` VARCHAR(255) UNIQUE ,
|
||||
`registration_hook` VARCHAR(255),
|
||||
`hook_basic_auth_user` VARCHAR(255),
|
||||
`hook_basic_auth_password` VARCHAR(255),
|
||||
PRIMARY KEY (`service_provider_sid`)
|
||||
) ENGINE=InnoDB COMMENT='An organization that provides communication services to its ';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `api_keys`
|
||||
(
|
||||
`api_key_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`token` CHAR(36) NOT NULL UNIQUE ,
|
||||
`account_sid` CHAR(36),
|
||||
`service_provider_sid` CHAR(36),
|
||||
PRIMARY KEY (`api_key_sid`)
|
||||
) ENGINE=InnoDB COMMENT='An authorization token that is used to access the REST api';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `accounts`
|
||||
(
|
||||
`account_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`sip_realm` VARCHAR(255) UNIQUE ,
|
||||
`service_provider_sid` CHAR(36) NOT NULL,
|
||||
`registration_hook` VARCHAR(255),
|
||||
`hook_basic_auth_user` VARCHAR(255),
|
||||
`hook_basic_auth_password` VARCHAR(255),
|
||||
`is_active` BOOLEAN NOT NULL DEFAULT true,
|
||||
PRIMARY KEY (`account_sid`)
|
||||
) ENGINE=InnoDB COMMENT='A single end-user of the platform';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `subscriptions`
|
||||
(
|
||||
`id` INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE ,
|
||||
`subscription_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`registration_sid` CHAR(36) NOT NULL,
|
||||
`event` VARCHAR(255),
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB COMMENT='An active sip subscription';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `voip_carriers`
|
||||
(
|
||||
`voip_carrier_sid` CHAR(36) NOT NULL UNIQUE ,
|
||||
`name` VARCHAR(255) NOT NULL UNIQUE ,
|
||||
`description` VARCHAR(255),
|
||||
PRIMARY KEY (`voip_carrier_sid`)
|
||||
) ENGINE=InnoDB COMMENT='An external organization that can provide sip trunking and D';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `phone_numbers`
|
||||
(
|
||||
`phone_number_sid` CHAR(36) UNIQUE ,
|
||||
`number` VARCHAR(255) NOT NULL UNIQUE ,
|
||||
`voip_carrier_sid` CHAR(36) NOT NULL,
|
||||
`account_sid` CHAR(36),
|
||||
`application_sid` CHAR(36),
|
||||
PRIMARY KEY (`phone_number_sid`)
|
||||
) ENGINE=InnoDB COMMENT='A phone number that has been assigned to an account';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sip_gateways`
|
||||
(
|
||||
`sip_gateway_sid` CHAR(36),
|
||||
`ipv4` VARCHAR(32) NOT NULL,
|
||||
`port` INTEGER NOT NULL DEFAULT 5060,
|
||||
`inbound` BOOLEAN NOT NULL,
|
||||
`outbound` BOOLEAN NOT NULL,
|
||||
`voip_carrier_sid` CHAR(36) NOT NULL,
|
||||
`is_active` BOOLEAN NOT NULL DEFAULT true,
|
||||
PRIMARY KEY (`sip_gateway_sid`)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX `applications_idx_name` ON `applications` (`account_sid`,`name`);
|
||||
|
||||
CREATE INDEX `applications_application_sid_idx` ON `applications` (`application_sid`);
|
||||
CREATE INDEX `applications_name_idx` ON `applications` (`name`);
|
||||
CREATE INDEX `applications_account_sid_idx` ON `applications` (`account_sid`);
|
||||
ALTER TABLE `applications` ADD FOREIGN KEY account_sid_idxfk (`account_sid`) REFERENCES `accounts` (`account_sid`);
|
||||
|
||||
CREATE INDEX `call_routes_call_route_sid_idx` ON `call_routes` (`call_route_sid`);
|
||||
ALTER TABLE `call_routes` ADD FOREIGN KEY account_sid_idxfk_1 (`account_sid`) REFERENCES `accounts` (`account_sid`);
|
||||
|
||||
ALTER TABLE `call_routes` ADD FOREIGN KEY application_sid_idxfk (`application_sid`) REFERENCES `applications` (`application_sid`);
|
||||
|
||||
CREATE INDEX `conferences_conference_sid_idx` ON `conferences` (`conference_sid`);
|
||||
CREATE INDEX `conference_participants_conference_participant_sid_idx` ON `conference_participants` (`conference_participant_sid`);
|
||||
ALTER TABLE `conference_participants` ADD FOREIGN KEY call_sid_idxfk (`call_sid`) REFERENCES `calls` (`call_sid`);
|
||||
|
||||
ALTER TABLE `conference_participants` ADD FOREIGN KEY conference_sid_idxfk (`conference_sid`) REFERENCES `conferences` (`conference_sid`);
|
||||
|
||||
CREATE INDEX `queues_queue_sid_idx` ON `queues` (`queue_sid`);
|
||||
CREATE INDEX `registrations_registration_sid_idx` ON `registrations` (`registration_sid`);
|
||||
CREATE INDEX `queue_members_queue_member_sid_idx` ON `queue_members` (`queue_member_sid`);
|
||||
ALTER TABLE `queue_members` ADD FOREIGN KEY call_sid_idxfk_1 (`call_sid`) REFERENCES `calls` (`call_sid`);
|
||||
|
||||
ALTER TABLE `queue_members` ADD FOREIGN KEY queue_sid_idxfk (`queue_sid`) REFERENCES `queues` (`queue_sid`);
|
||||
|
||||
CREATE INDEX `calls_call_sid_idx` ON `calls` (`call_sid`);
|
||||
ALTER TABLE `calls` ADD FOREIGN KEY parent_call_sid_idxfk (`parent_call_sid`) REFERENCES `calls` (`call_sid`);
|
||||
|
||||
ALTER TABLE `calls` ADD FOREIGN KEY application_sid_idxfk_1 (`application_sid`) REFERENCES `applications` (`application_sid`);
|
||||
|
||||
CREATE INDEX `calls_phone_number_sid_idx` ON `calls` (`phone_number_sid`);
|
||||
ALTER TABLE `calls` ADD FOREIGN KEY phone_number_sid_idxfk (`phone_number_sid`) REFERENCES `phone_numbers` (`phone_number_sid`);
|
||||
|
||||
ALTER TABLE `calls` ADD FOREIGN KEY inbound_user_sid_idxfk (`inbound_user_sid`) REFERENCES `registrations` (`registration_sid`);
|
||||
|
||||
ALTER TABLE `calls` ADD FOREIGN KEY outbound_user_sid_idxfk (`outbound_user_sid`) REFERENCES `registrations` (`registration_sid`);
|
||||
|
||||
CREATE INDEX `service_providers_service_provider_sid_idx` ON `service_providers` (`service_provider_sid`);
|
||||
CREATE INDEX `service_providers_name_idx` ON `service_providers` (`name`);
|
||||
CREATE INDEX `service_providers_root_domain_idx` ON `service_providers` (`root_domain`);
|
||||
CREATE INDEX `api_keys_api_key_sid_idx` ON `api_keys` (`api_key_sid`);
|
||||
CREATE INDEX `api_keys_account_sid_idx` ON `api_keys` (`account_sid`);
|
||||
ALTER TABLE `api_keys` ADD FOREIGN KEY account_sid_idxfk_2 (`account_sid`) REFERENCES `accounts` (`account_sid`);
|
||||
|
||||
CREATE INDEX `api_keys_service_provider_sid_idx` ON `api_keys` (`service_provider_sid`);
|
||||
ALTER TABLE `api_keys` ADD FOREIGN KEY service_provider_sid_idxfk (`service_provider_sid`) REFERENCES `service_providers` (`service_provider_sid`);
|
||||
|
||||
CREATE INDEX `accounts_account_sid_idx` ON `accounts` (`account_sid`);
|
||||
CREATE INDEX `accounts_name_idx` ON `accounts` (`name`);
|
||||
CREATE INDEX `accounts_sip_realm_idx` ON `accounts` (`sip_realm`);
|
||||
CREATE INDEX `accounts_service_provider_sid_idx` ON `accounts` (`service_provider_sid`);
|
||||
ALTER TABLE `accounts` ADD FOREIGN KEY service_provider_sid_idxfk_1 (`service_provider_sid`) REFERENCES `service_providers` (`service_provider_sid`);
|
||||
|
||||
ALTER TABLE `subscriptions` ADD FOREIGN KEY registration_sid_idxfk (`registration_sid`) REFERENCES `registrations` (`registration_sid`);
|
||||
|
||||
CREATE INDEX `voip_carriers_voip_carrier_sid_idx` ON `voip_carriers` (`voip_carrier_sid`);
|
||||
CREATE INDEX `voip_carriers_name_idx` ON `voip_carriers` (`name`);
|
||||
CREATE INDEX `phone_numbers_phone_number_sid_idx` ON `phone_numbers` (`phone_number_sid`);
|
||||
CREATE INDEX `phone_numbers_voip_carrier_sid_idx` ON `phone_numbers` (`voip_carrier_sid`);
|
||||
ALTER TABLE `phone_numbers` ADD FOREIGN KEY voip_carrier_sid_idxfk (`voip_carrier_sid`) REFERENCES `voip_carriers` (`voip_carrier_sid`);
|
||||
|
||||
ALTER TABLE `phone_numbers` ADD FOREIGN KEY account_sid_idxfk_3 (`account_sid`) REFERENCES `accounts` (`account_sid`);
|
||||
|
||||
ALTER TABLE `phone_numbers` ADD FOREIGN KEY application_sid_idxfk_2 (`application_sid`) REFERENCES `applications` (`application_sid`);
|
||||
|
||||
CREATE UNIQUE INDEX `sip_gateways_sip_gateway_idx_hostport` ON `sip_gateways` (`ipv4`,`port`);
|
||||
|
||||
ALTER TABLE `sip_gateways` ADD FOREIGN KEY voip_carrier_sid_idxfk_1 (`voip_carrier_sid`) REFERENCES `voip_carriers` (`voip_carrier_sid`);
|
||||
10
test/db/populate-test-data.sql
Normal file
10
test/db/populate-test-data.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
insert into service_providers (service_provider_sid, name, root_domain, registration_hook, hook_basic_auth_user, hook_basic_auth_password)
|
||||
values ('3f35518f-5a0d-4c2e-90a5-2407bb3b36f0', 'SP A', 'jambonz.org', 'http://127.0.0.1:4000/auth', 'foo', 'bar');
|
||||
insert into accounts(account_sid, service_provider_sid, name, sip_realm, registration_hook, hook_basic_auth_user, hook_basic_auth_password)
|
||||
values ('ed649e33-e771-403a-8c99-1780eabbc803', '3f35518f-5a0d-4c2e-90a5-2407bb3b36f0', 'test account', 'sip.example.com', 'http://127.0.0.1:4000/auth', 'foo', 'bar');
|
||||
|
||||
insert into voip_carriers (voip_carrier_sid, name) values ('287c1452-620d-4195-9f19-c9814ef90d78', 'westco');
|
||||
insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, inbound, outbound)
|
||||
values ('124a5339-c62c-4075-9e19-f4de70a96597', '287c1452-620d-4195-9f19-c9814ef90d78', '172.38.0.20', true, true);
|
||||
insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, port, inbound, outbound)
|
||||
values ('efbc4830-57cd-4c78-a56f-d64fdf210fe8', '287c1452-620d-4195-9f19-c9814ef90d78', '3.3.3.3', 5062, false, true);
|
||||
3
test/db/remove_test_db.sql
Normal file
3
test/db/remove_test_db.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
DROP DATABASE jambones_test;
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'jambones_test'@'localhost';
|
||||
DROP USER 'jambones_test'@'localhost';
|
||||
@@ -1,3 +1,5 @@
|
||||
require('./docker_start');
|
||||
require('./create-test-db');
|
||||
require('./sip-tests');
|
||||
require('./remove-test-db');
|
||||
require('./docker_stop');
|
||||
|
||||
11
test/remove-test-db.js
Normal file
11
test/remove-test-db.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const test = require('tape').test ;
|
||||
const exec = require('child_process').exec ;
|
||||
const pwd = process.env.TRAVIS ? '' : '-p$MYSQL_ROOT_PASSWORD';
|
||||
|
||||
test('dropping jambones_test database', (t) => {
|
||||
exec(`mysql -h localhost -u root ${pwd} < ${__dirname}/db/remove_test_db.sql`, (err, stdout, stderr) => {
|
||||
if (err) return t.end(err);
|
||||
t.pass('database successfully dropped');
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
132
test/scenarios/uac-device-invalid-password.xml
Normal file
132
test/scenarios/uac-device-invalid-password.xml
Normal file
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp 'uac' scenario with pcap (rtp) play -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="UAC with media">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:[service]@jambonz.org SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 INVITE
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
Max-Forwards: 70
|
||||
Subject: uac-device-unknown-user
|
||||
Content-Type: application/sdp
|
||||
Content-Length: [len]
|
||||
|
||||
v=0
|
||||
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||
s=-
|
||||
c=IN IP[local_ip_type] [local_ip]
|
||||
t=0 0
|
||||
m=audio [auto_media_port] RTP/AVP 8 101
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:101 telephone-event/8000
|
||||
a=fmtp:101 0-11,16
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="401" auth="true">
|
||||
</recv>
|
||||
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
ACK sip:[service]@jambonz.org SIP/2.0
|
||||
[last_Via]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 ACK
|
||||
Subject: uac-device-unknown-user
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:[service]@jambonz.org SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 2 INVITE
|
||||
[authentication username=john password=2222]
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
Max-Forwards: 70
|
||||
Subject: uac-device-unknown-user
|
||||
Content-Type: application/sdp
|
||||
Content-Length: [len]
|
||||
|
||||
v=0
|
||||
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||
s=-
|
||||
c=IN IP[local_ip_type] [local_ip]
|
||||
t=0 0
|
||||
m=audio [auto_media_port] RTP/AVP 8 101
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:101 telephone-event/8000
|
||||
a=fmtp:101 0-11,16
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="403">
|
||||
</recv>
|
||||
|
||||
<!-- Packet lost can be simulated in any send/recv message by -->
|
||||
<!-- by adding the 'lost = "10"'. Value can be [1-100] percent. -->
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
ACK sip:[service]@jambonz.org SIP/2.0
|
||||
[last_Via]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 2 ACK
|
||||
Subject: uac-device-unknown-user
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<!-- definition of the response time repartition table (unit is ms) -->
|
||||
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
|
||||
|
||||
<!-- definition of the call length repartition table (unit is ms) -->
|
||||
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
|
||||
|
||||
</scenario>
|
||||
76
test/scenarios/uac-device-unknown-realm.xml
Normal file
76
test/scenarios/uac-device-unknown-realm.xml
Normal file
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp 'uac' scenario with pcap (rtp) play -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="UAC with media">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:[service]@jambones.org SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 INVITE
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
Max-Forwards: 70
|
||||
Subject: uac-device-unknown-user
|
||||
Content-Type: application/sdp
|
||||
Content-Length: [len]
|
||||
|
||||
v=0
|
||||
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||
s=-
|
||||
c=IN IP[local_ip_type] [local_ip]
|
||||
t=0 0
|
||||
m=audio [auto_media_port] RTP/AVP 8 101
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:101 telephone-event/8000
|
||||
a=fmtp:101 0-11,16
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="403">
|
||||
</recv>
|
||||
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
ACK sip:[service]@jambones.org SIP/2.0
|
||||
[last_Via]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 ACK
|
||||
Subject: uac-device-unknown-user
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
|
||||
|
||||
</scenario>
|
||||
132
test/scenarios/uac-device-unknown-user.xml
Normal file
132
test/scenarios/uac-device-unknown-user.xml
Normal file
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp 'uac' scenario with pcap (rtp) play -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="UAC with media">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:[service]@jambonz.org SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 INVITE
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
Max-Forwards: 70
|
||||
Subject: uac-device-unknown-user
|
||||
Content-Type: application/sdp
|
||||
Content-Length: [len]
|
||||
|
||||
v=0
|
||||
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||
s=-
|
||||
c=IN IP[local_ip_type] [local_ip]
|
||||
t=0 0
|
||||
m=audio [auto_media_port] RTP/AVP 8 101
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:101 telephone-event/8000
|
||||
a=fmtp:101 0-11,16
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="401" auth="true">
|
||||
</recv>
|
||||
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
ACK sip:[service]@jambonz.org SIP/2.0
|
||||
[last_Via]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 ACK
|
||||
Subject: uac-device-unknown-user
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:[service]@jambonz.org SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 2 INVITE
|
||||
[authentication username=jay password=1234]
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
Max-Forwards: 70
|
||||
Subject: uac-device-unknown-user
|
||||
Content-Type: application/sdp
|
||||
Content-Length: [len]
|
||||
|
||||
v=0
|
||||
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||
s=-
|
||||
c=IN IP[local_ip_type] [local_ip]
|
||||
t=0 0
|
||||
m=audio [auto_media_port] RTP/AVP 8 101
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:101 telephone-event/8000
|
||||
a=fmtp:101 0-11,16
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="403">
|
||||
</recv>
|
||||
|
||||
<!-- Packet lost can be simulated in any send/recv message by -->
|
||||
<!-- by adding the 'lost = "10"'. Value can be [1-100] percent. -->
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
ACK sip:[service]@jambonz.org SIP/2.0
|
||||
[last_Via]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 2 ACK
|
||||
Subject: uac-device-unknown-user
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<!-- definition of the response time repartition table (unit is ms) -->
|
||||
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
|
||||
|
||||
<!-- definition of the call length repartition table (unit is ms) -->
|
||||
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
|
||||
|
||||
</scenario>
|
||||
187
test/scenarios/uac-pcap-device-success-in-dialog-request.xml
Normal file
187
test/scenarios/uac-pcap-device-success-in-dialog-request.xml
Normal file
@@ -0,0 +1,187 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
||||
|
||||
<!-- This program is free software; you can redistribute it and/or -->
|
||||
<!-- modify it under the terms of the GNU General Public License as -->
|
||||
<!-- published by the Free Software Foundation; either version 2 of the -->
|
||||
<!-- License, or (at your option) any later version. -->
|
||||
<!-- -->
|
||||
<!-- This program is distributed in the hope that it will be useful, -->
|
||||
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
||||
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
||||
<!-- GNU General Public License for more details. -->
|
||||
<!-- -->
|
||||
<!-- You should have received a copy of the GNU General Public License -->
|
||||
<!-- along with this program; if not, write to the -->
|
||||
<!-- Free Software Foundation, Inc., -->
|
||||
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
||||
<!-- -->
|
||||
<!-- Sipp 'uac' scenario with pcap (rtp) play -->
|
||||
<!-- -->
|
||||
|
||||
<scenario name="UAC with media">
|
||||
<!-- In client mode (sipp placing calls), the Call-ID MUST be -->
|
||||
<!-- generated by sipp. To do so, use [call_id] keyword. -->
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:[service]@jambonz.org SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 INVITE
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
Max-Forwards: 70
|
||||
Subject: uac-pcap-device-success
|
||||
Content-Type: application/sdp
|
||||
Content-Length: [len]
|
||||
|
||||
v=0
|
||||
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||
s=-
|
||||
c=IN IP[local_ip_type] [local_ip]
|
||||
t=0 0
|
||||
m=audio [auto_media_port] RTP/AVP 8 101
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:101 telephone-event/8000
|
||||
a=fmtp:101 0-11,16
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="401" auth="true">
|
||||
</recv>
|
||||
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
ACK sip:[service]@jambonz.org SIP/2.0
|
||||
[last_Via]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 1 ACK
|
||||
Subject: uac-pcap-device-success
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INVITE sip:[service]@jambonz.org SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
|
||||
Call-ID: [call_id]
|
||||
CSeq: 2 INVITE
|
||||
[authentication username=john password=1234]
|
||||
Contact: sip:sipp@[local_ip]:[local_port]
|
||||
Max-Forwards: 70
|
||||
Subject: uac-pcap-device-success
|
||||
Content-Type: application/sdp
|
||||
Content-Length: [len]
|
||||
|
||||
v=0
|
||||
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||
s=-
|
||||
c=IN IP[local_ip_type] [local_ip]
|
||||
t=0 0
|
||||
m=audio [auto_media_port] RTP/AVP 8 101
|
||||
a=rtpmap:8 PCMA/8000
|
||||
a=rtpmap:101 telephone-event/8000
|
||||
a=fmtp:101 0-11,16
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="100" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="180" optional="true">
|
||||
</recv>
|
||||
|
||||
<recv response="200" rtd="true" crlf="true">
|
||||
</recv>
|
||||
|
||||
<!-- Packet lost can be simulated in any send/recv message by -->
|
||||
<!-- by adding the 'lost = "10"'. Value can be [1-100] percent. -->
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
ACK sip:[service]@jambonz.org SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 2 ACK
|
||||
Subject: uac-pcap-device-success
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<!-- Play a pre-recorded PCAP file (RTP stream) -->
|
||||
<nop>
|
||||
<action>
|
||||
<exec play_pcap_audio="pcap/g711a.pcap"/>
|
||||
</action>
|
||||
</nop>
|
||||
|
||||
<!-- Pause briefly -->
|
||||
<pause milliseconds="1000"/>
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
INFO sip:[service]@jambonz.org SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 3 INFO
|
||||
Max-Forwards: 70
|
||||
Event: X-custom-Event
|
||||
Subject: uac-pcap-device-success
|
||||
Content-Type: application/text
|
||||
Content-Length: [len]
|
||||
|
||||
foobar
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="200" crlf="true">
|
||||
</recv>
|
||||
|
||||
<send retrans="500">
|
||||
<![CDATA[
|
||||
|
||||
BYE sip:[service]@jambonz.org SIP/2.0
|
||||
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
|
||||
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag09[call_number]
|
||||
To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
|
||||
Call-ID: [call_id]
|
||||
CSeq: 4 BYE
|
||||
Max-Forwards: 70
|
||||
Subject: uac-pcap-device-success
|
||||
Content-Length: 0
|
||||
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<recv response="200" crlf="true">
|
||||
</recv>
|
||||
|
||||
<!-- definition of the response time repartition table (unit is ms) -->
|
||||
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
|
||||
|
||||
<!-- definition of the call length repartition table (unit is ms) -->
|
||||
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
|
||||
|
||||
</scenario>
|
||||
@@ -87,10 +87,13 @@
|
||||
crlf="true">
|
||||
</recv>
|
||||
|
||||
<recv request="INFO" optional="true" next="1">
|
||||
</recv>
|
||||
|
||||
<recv request="BYE">
|
||||
</recv>
|
||||
|
||||
<send>
|
||||
<send next="2">
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 200 OK
|
||||
@@ -105,16 +108,23 @@
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<!-- Keep the call open for a while in case the 200 is lost to be -->
|
||||
<!-- able to retransmit it if we receive the BYE again. -->
|
||||
<timewait milliseconds="4000"/>
|
||||
<label id="1"/>
|
||||
<send>
|
||||
<![CDATA[
|
||||
|
||||
SIP/2.0 200 OK
|
||||
[last_Via:]
|
||||
[last_From:]
|
||||
[last_To:]
|
||||
[last_Call-ID:]
|
||||
[last_CSeq:]
|
||||
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
|
||||
Content-Length: 0
|
||||
|
||||
<!-- definition of the response time repartition table (unit is ms) -->
|
||||
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
|
||||
]]>
|
||||
</send>
|
||||
|
||||
<!-- definition of the call length repartition table (unit is ms) -->
|
||||
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
|
||||
<label id="2"/>
|
||||
|
||||
</scenario>
|
||||
|
||||
|
||||
@@ -31,6 +31,30 @@ test('incoming call tests', (t) => {
|
||||
.then(() => {
|
||||
return t.pass('incoming call from authenticated device completed successfully');
|
||||
})
|
||||
.then(() => {
|
||||
return sippUac('uac-device-unknown-user.xml', '172.38.0.30');
|
||||
})
|
||||
.then(() => {
|
||||
return t.pass('unknown user is rejected with a 403');
|
||||
})
|
||||
.then(() => {
|
||||
return sippUac('uac-device-unknown-realm.xml', '172.38.0.30');
|
||||
})
|
||||
.then(() => {
|
||||
return t.pass('unknown realm is rejected with a 403');
|
||||
})
|
||||
.then(() => {
|
||||
return sippUac('uac-device-invalid-password.xml', '172.38.0.30');
|
||||
})
|
||||
.then(() => {
|
||||
return t.pass('invalid password for valid user is rejected with a 403');
|
||||
})
|
||||
.then(() => {
|
||||
return sippUac('uac-pcap-device-success-in-dialog-request.xml', '172.38.0.30');
|
||||
})
|
||||
.then(() => {
|
||||
return t.pass('handles in-dialog requests');
|
||||
})
|
||||
.then(() => {
|
||||
srf.disconnect();
|
||||
t.end();
|
||||
|
||||
Reference in New Issue
Block a user