mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-20 16:50:39 +00:00
feat: add dial verb testcases (#231)
* feat: add dial verb testcases * feat: add dial verb testcases * feat: add dial verb testcases * feat: add dial verb testcases Co-authored-by: Quan HL <quanluuhoang8@gmail.com>
This commit is contained in:
215
test/dial-tests.js
Normal file
215
test/dial-tests.js
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
const test = require('tape');
|
||||||
|
const { sippUac } = require('./sipp')('test_fs');
|
||||||
|
const bent = require('bent');
|
||||||
|
const getJSON = bent('json')
|
||||||
|
const clearModule = require('clear-module');
|
||||||
|
const {provisionCallHook} = require('./utils')
|
||||||
|
|
||||||
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
|
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||||
|
});
|
||||||
|
|
||||||
|
function connect(connectable) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
connectable.on('connect', () => {
|
||||||
|
return resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
test('\'dial-phone\'', async(t) => {
|
||||||
|
clearModule.all();
|
||||||
|
const {srf, disconnect} = require('../app');
|
||||||
|
try {
|
||||||
|
await connect(srf);
|
||||||
|
|
||||||
|
// GIVEN
|
||||||
|
const from = "dial_success";
|
||||||
|
let verbs = [
|
||||||
|
{
|
||||||
|
"verb": "dial",
|
||||||
|
"callerId": from,
|
||||||
|
"actionHook": "/actionHook",
|
||||||
|
"timeLimit": 5,
|
||||||
|
"target": [
|
||||||
|
{
|
||||||
|
"type": "phone",
|
||||||
|
"number": "15083084809"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
provisionCallHook(from, verbs);
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
const p = sippUac('uas-dial.xml', '172.38.0.10', undefined, undefined, 2);
|
||||||
|
|
||||||
|
let account_sid = '622f62e4-303a-49f2-bbe0-eb1e1714e37a';
|
||||||
|
|
||||||
|
let post = bent('http://127.0.0.1:3000/', 'POST', 'json', 201);
|
||||||
|
post('v1/createCall', {
|
||||||
|
'account_sid':account_sid,
|
||||||
|
"call_hook": {
|
||||||
|
"url": "http://127.0.0.1:3100/",
|
||||||
|
"method": "POST",
|
||||||
|
"username": "username",
|
||||||
|
"password": "password"
|
||||||
|
},
|
||||||
|
"from": from,
|
||||||
|
"to": {
|
||||||
|
"type": "phone",
|
||||||
|
"number": "15583084808"
|
||||||
|
}});
|
||||||
|
|
||||||
|
await p;
|
||||||
|
|
||||||
|
obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||||
|
t.ok(obj.body.from === from,
|
||||||
|
'dial: succeeds actionHook');
|
||||||
|
|
||||||
|
disconnect();
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`error received: ${err}`);
|
||||||
|
disconnect();
|
||||||
|
t.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('\'dial-sip\'', async(t) => {
|
||||||
|
clearModule.all();
|
||||||
|
const {srf, disconnect} = require('../app');
|
||||||
|
try {
|
||||||
|
await connect(srf);
|
||||||
|
|
||||||
|
// GIVEN
|
||||||
|
const from = "dial_sip";
|
||||||
|
let verbs = [
|
||||||
|
{
|
||||||
|
"verb": "dial",
|
||||||
|
"callerId": from,
|
||||||
|
"actionHook": "/actionHook",
|
||||||
|
"dtmfCapture":["*2", "*3"],
|
||||||
|
"target": [
|
||||||
|
{
|
||||||
|
"type": "sip",
|
||||||
|
"sipUri": "sip:15083084809@jambonz.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
provisionCallHook(from, verbs);
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
const p = sippUac('uas-dial.xml', '172.38.0.10', undefined, undefined, 2);
|
||||||
|
|
||||||
|
let account_sid = '622f62e4-303a-49f2-bbe0-eb1e1714e37a';
|
||||||
|
|
||||||
|
let post = bent('http://127.0.0.1:3000/', 'POST', 'json', 201);
|
||||||
|
post('v1/createCall', {
|
||||||
|
'account_sid':account_sid,
|
||||||
|
"call_hook": {
|
||||||
|
"url": "http://127.0.0.1:3100/",
|
||||||
|
"method": "POST",
|
||||||
|
"username": "username",
|
||||||
|
"password": "password"
|
||||||
|
},
|
||||||
|
"from": from,
|
||||||
|
"to": {
|
||||||
|
"type": "phone",
|
||||||
|
"number": "15583084808"
|
||||||
|
}});
|
||||||
|
|
||||||
|
await new Promise(r => setTimeout(r, 2000));
|
||||||
|
|
||||||
|
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}`);
|
||||||
|
const callSid = obj.body.call_sid;
|
||||||
|
|
||||||
|
post = bent('http://127.0.0.1:3000/', 'POST', 202);
|
||||||
|
await post(`v1/updateCall/${callSid}`, {
|
||||||
|
"call_status": "completed"
|
||||||
|
});
|
||||||
|
|
||||||
|
await p;
|
||||||
|
|
||||||
|
obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||||
|
t.ok(obj.body.from === from,
|
||||||
|
'dial: succeeds actionHook');
|
||||||
|
|
||||||
|
disconnect();
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`error received: ${err}`);
|
||||||
|
disconnect();
|
||||||
|
t.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('\'dial-user\'', async(t) => {
|
||||||
|
clearModule.all();
|
||||||
|
const {srf, disconnect} = require('../app');
|
||||||
|
try {
|
||||||
|
await connect(srf);
|
||||||
|
|
||||||
|
// GIVEN
|
||||||
|
const from = "dial_user";
|
||||||
|
let verbs = [
|
||||||
|
{
|
||||||
|
"verb": "dial",
|
||||||
|
"callerId": from,
|
||||||
|
"actionHook": "/actionHook",
|
||||||
|
"target": [
|
||||||
|
{
|
||||||
|
"type": "user",
|
||||||
|
"name": "user110@jambonz.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
provisionCallHook(from, verbs);
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
const p = sippUac('uas-dial.xml', '172.38.0.10', undefined, undefined, 2);
|
||||||
|
|
||||||
|
let account_sid = '622f62e4-303a-49f2-bbe0-eb1e1714e37a';
|
||||||
|
|
||||||
|
let post = bent('http://127.0.0.1:3000/', 'POST', 'json', 201);
|
||||||
|
post('v1/createCall', {
|
||||||
|
'account_sid':account_sid,
|
||||||
|
"call_hook": {
|
||||||
|
"url": "http://127.0.0.1:3100/",
|
||||||
|
"method": "POST",
|
||||||
|
"username": "username",
|
||||||
|
"password": "password"
|
||||||
|
},
|
||||||
|
"from": from,
|
||||||
|
"to": {
|
||||||
|
"type": "phone",
|
||||||
|
"number": "15583084808"
|
||||||
|
}});
|
||||||
|
|
||||||
|
await new Promise(r => setTimeout(r, 2000));
|
||||||
|
|
||||||
|
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}`);
|
||||||
|
const callSid = obj.body.call_sid;
|
||||||
|
|
||||||
|
post = bent('http://127.0.0.1:3000/', 'POST', 202);
|
||||||
|
await post(`v1/updateCall/${callSid}`, {
|
||||||
|
"call_status": "completed"
|
||||||
|
});
|
||||||
|
|
||||||
|
await p;
|
||||||
|
|
||||||
|
obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||||
|
t.ok(obj.body.from === from,
|
||||||
|
'dial: succeeds actionHook');
|
||||||
|
|
||||||
|
disconnect();
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`error received: ${err}`);
|
||||||
|
disconnect();
|
||||||
|
t.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -2,6 +2,7 @@ require('./unit-tests');
|
|||||||
require('./docker_start');
|
require('./docker_start');
|
||||||
require('./create-test-db');
|
require('./create-test-db');
|
||||||
require('./account-validation-tests');
|
require('./account-validation-tests');
|
||||||
|
require('./dial-tests');
|
||||||
require('./webhooks-tests');
|
require('./webhooks-tests');
|
||||||
require('./say-tests');
|
require('./say-tests');
|
||||||
require('./gather-tests');
|
require('./gather-tests');
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ test('\'listen-success\'', async(t) => {
|
|||||||
// THEN
|
// THEN
|
||||||
await sippUac('uac-gather-account-creds-success-send-bye.xml', '172.38.0.10', from);
|
await sippUac('uac-gather-account-creds-success-send-bye.xml', '172.38.0.10', from);
|
||||||
let obj = await getJSON(`http://127.0.0.1:3100/ws_packet_count/${from}`);
|
let obj = await getJSON(`http://127.0.0.1:3100/ws_packet_count/${from}`);
|
||||||
t.ok(38500 <= obj.count && obj.count <= 40100, 'listen: success incomming call audio');
|
t.ok(38000 <= obj.count, 'listen: success incomming call audio');
|
||||||
|
|
||||||
obj = await getJSON(`http://127.0.0.1:3100/ws_metadata/${from}`);
|
obj = await getJSON(`http://127.0.0.1:3100/ws_metadata/${from}`);
|
||||||
t.ok(obj.metadata.from === from && obj.metadata.sampleRate === 8000, 'listen: success metadata');
|
t.ok(obj.metadata.from === from && obj.metadata.sampleRate === 8000, 'listen: success metadata');
|
||||||
@@ -80,7 +80,7 @@ test('\'listen-maxLength\'', async(t) => {
|
|||||||
// THEN
|
// THEN
|
||||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||||
let obj = await getJSON(`http://127.0.0.1:3100/ws_packet_count/${from}`);
|
let obj = await getJSON(`http://127.0.0.1:3100/ws_packet_count/${from}`);
|
||||||
t.ok(31680 <= obj.count && obj.count <= 32500, 'listen: success maxLength incomming call audio');
|
t.ok(30000 <= obj.count, 'listen: success maxLength incomming call audio');
|
||||||
|
|
||||||
obj = await getJSON(`http://127.0.0.1:3100/ws_metadata/${from}`);
|
obj = await getJSON(`http://127.0.0.1:3100/ws_metadata/${from}`);
|
||||||
t.ok(obj.metadata.from === from && obj.metadata.sampleRate === 8000, 'listen: success maxLength metadata');
|
t.ok(obj.metadata.from === from && obj.metadata.sampleRate === 8000, 'listen: success maxLength metadata');
|
||||||
|
|||||||
164
test/scenarios/uas-dial.xml
Normal file
164
test/scenarios/uas-dial.xml
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
<?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 default 'uas' scenario. -->
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
|
<scenario name="Basic UAS responder">
|
||||||
|
<!-- By adding rrs="true" (Record Route Sets), the route sets -->
|
||||||
|
<!-- are saved and used for following messages sent. Useful to test -->
|
||||||
|
<!-- against stateful SIP proxies/B2BUAs. -->
|
||||||
|
<recv request="INVITE" crlf="true">
|
||||||
|
<action>
|
||||||
|
<ereg regexp=".*" search_in="hdr" header="Subject:" assign_to="1" />
|
||||||
|
</action>
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<!-- The '[last_*]' keyword is replaced automatically by the -->
|
||||||
|
<!-- specified header if it was present in the last message received -->
|
||||||
|
<!-- (except if it was a retransmission). If the header was not -->
|
||||||
|
<!-- present or if no message has been received, the '[last_*]' -->
|
||||||
|
<!-- keyword is discarded, and all bytes until the end of the line -->
|
||||||
|
<!-- are also discarded. -->
|
||||||
|
<!-- -->
|
||||||
|
<!-- If the specified header was present several times in the -->
|
||||||
|
<!-- message, all occurrences are concatenated (CRLF separated) -->
|
||||||
|
<!-- to be used in place of the '[last_*]' keyword. -->
|
||||||
|
|
||||||
|
<send>
|
||||||
|
<![CDATA[
|
||||||
|
|
||||||
|
SIP/2.0 180 Ringing
|
||||||
|
[last_Via:]
|
||||||
|
[last_From:]
|
||||||
|
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||||
|
[last_Call-ID:]
|
||||||
|
[last_CSeq:]
|
||||||
|
[last_Record-Route:]
|
||||||
|
Subject:[$1]
|
||||||
|
Content-Length: 0
|
||||||
|
|
||||||
|
]]>
|
||||||
|
</send>
|
||||||
|
|
||||||
|
<send>
|
||||||
|
<![CDATA[
|
||||||
|
|
||||||
|
SIP/2.0 200 OK
|
||||||
|
[last_Via:]
|
||||||
|
[last_From:]
|
||||||
|
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||||
|
[last_Call-ID:]
|
||||||
|
[last_CSeq:]
|
||||||
|
[last_Record-Route:]
|
||||||
|
Subject:[$1]
|
||||||
|
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
|
||||||
|
Content-Type: application/sdp
|
||||||
|
Content-Length: [len]
|
||||||
|
|
||||||
|
v=0
|
||||||
|
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||||
|
s=-
|
||||||
|
c=IN IP[media_ip_type] [media_ip]
|
||||||
|
t=0 0
|
||||||
|
m=audio [media_port] RTP/AVP 0
|
||||||
|
a=rtpmap:0 PCMU/8000
|
||||||
|
|
||||||
|
]]>
|
||||||
|
</send>
|
||||||
|
|
||||||
|
<recv request="ACK"
|
||||||
|
rtd="true"
|
||||||
|
crlf="true">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<recv request="INFO" optional="true" next="1">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<recv request="INVITE" crlf="true">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<send>
|
||||||
|
<![CDATA[
|
||||||
|
|
||||||
|
SIP/2.0 200 OK
|
||||||
|
[last_Via:]
|
||||||
|
[last_From:]
|
||||||
|
[last_To:];tag=[pid]SIPpTag01[call_number]
|
||||||
|
[last_Call-ID:]
|
||||||
|
[last_CSeq:]
|
||||||
|
[last_Record-Route:]
|
||||||
|
Subject:[$1]
|
||||||
|
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
|
||||||
|
Content-Type: application/sdp
|
||||||
|
Content-Length: [len]
|
||||||
|
|
||||||
|
v=0
|
||||||
|
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
||||||
|
s=-
|
||||||
|
c=IN IP[media_ip_type] [media_ip]
|
||||||
|
t=0 0
|
||||||
|
m=audio [media_port] RTP/AVP 0
|
||||||
|
a=rtpmap:0 PCMU/8000
|
||||||
|
|
||||||
|
]]>
|
||||||
|
</send>
|
||||||
|
|
||||||
|
<recv request="ACK"
|
||||||
|
rtd="true"
|
||||||
|
crlf="true">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<recv request="BYE">
|
||||||
|
</recv>
|
||||||
|
|
||||||
|
<send next="2">
|
||||||
|
<![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
|
||||||
|
|
||||||
|
]]>
|
||||||
|
</send>
|
||||||
|
|
||||||
|
<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
|
||||||
|
|
||||||
|
]]>
|
||||||
|
</send>
|
||||||
|
|
||||||
|
<label id="2"/>
|
||||||
|
|
||||||
|
</scenario>
|
||||||
|
|
||||||
@@ -24,13 +24,13 @@ obj.output = () => {
|
|||||||
return output;
|
return output;
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.sippUac = (file, bindAddress, from='sipp', to='16174000000') => {
|
obj.sippUac = (file, bindAddress, from='sipp', to='16174000000', loop=1) => {
|
||||||
const cmd = 'docker';
|
const cmd = 'docker';
|
||||||
const args = [
|
const args = [
|
||||||
'run', '-t', '--rm', '--net', `${network}`,
|
'run', '-t', '--rm', '--net', `${network}`,
|
||||||
'-v', `${__dirname}/scenarios:/tmp/scenarios`,
|
'-v', `${__dirname}/scenarios:/tmp/scenarios`,
|
||||||
'drachtio/sipp', 'sipp', '-sf', `/tmp/scenarios/${file}`,
|
'drachtio/sipp', 'sipp', '-sf', `/tmp/scenarios/${file}`,
|
||||||
'-m', '1',
|
'-m', loop,
|
||||||
'-sleep', '250ms',
|
'-sleep', '250ms',
|
||||||
'-nostdin',
|
'-nostdin',
|
||||||
'-cid_str', `%u-%p@%s-${idx++}`,
|
'-cid_str', `%u-%p@%s-${idx++}`,
|
||||||
|
|||||||
Reference in New Issue
Block a user