initial commit
This commit is contained in:
commit
636959b37b
2474 files changed
+1343178
No files matched your search
@@ -0,0 +1,65 @@
|
||||
|
||||
PJSUA TEST FRAMEWORK
|
||||
=========================
|
||||
|
||||
0. What is this
|
||||
---------------
|
||||
This is the automated testing scripts for pjsua. It can do many things (just
|
||||
don't ask it to write good documentation :) ).
|
||||
|
||||
|
||||
1. Requirements
|
||||
---------------
|
||||
To run the tests you need:
|
||||
- Python (tested with Python 2.5.2)
|
||||
- pjsua application, built and placed in pjsip-apps/bin directory
|
||||
- the pjsua must be built with:
|
||||
- SRTP enabled (the default)
|
||||
|
||||
|
||||
2. Using
|
||||
--------
|
||||
To run all the tests:
|
||||
$ python [OPTIONS] runall.py
|
||||
|
||||
To run individual test:
|
||||
$ python [OPTIONS] run.py MODULE CONFIG
|
||||
|
||||
Where options:
|
||||
-e EXE use EXE as pjsua executable
|
||||
-n use null audio
|
||||
-r TEST (for runall.py only) resume test at TEST
|
||||
|
||||
|
||||
For each individual tests, the run.py is the main entry for the test. It
|
||||
imports the various inc_xxx.py files, and it will load the MODULE. The MODULE
|
||||
contains specific test flows, and we have few of them:
|
||||
|
||||
- mod_run.py:
|
||||
a simple test which just run pjsua with the configuration from CONFIG
|
||||
file and checks if pjsua can start properly.
|
||||
|
||||
- mod_call.py:
|
||||
call testing where it spawns two pjsua instances each with configura-
|
||||
tions as specified in CONFIG file, makes one pjsua call the other, and
|
||||
checks if the call can be established.
|
||||
|
||||
- mod_pres.py:
|
||||
presence testing
|
||||
|
||||
- mod_sendto.py:
|
||||
Simple UAC to send arbitrary SIP message to pjsua. Good to test
|
||||
various incoming INVITE scenarios
|
||||
|
||||
- mod_media_playrec.py:
|
||||
Mainly for resampling quality testing
|
||||
|
||||
- mod_pesq.py
|
||||
Measure call quality of various call settings with PESQ, for people
|
||||
who have PESQ tool and license
|
||||
|
||||
Example:
|
||||
$ python run.py mod_run.py scripts-run/100_simple.py
|
||||
$ python run.py mod_call.py scripts-call/100_simple.py
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# $Id$
|
||||
|
||||
# Specify if host has sound device, or test should be performed using sound device
|
||||
HAS_SND_DEV = 0
|
||||
@@ -0,0 +1,152 @@
|
||||
# $Id$
|
||||
import random
|
||||
import config_site
|
||||
import socket
|
||||
import errno
|
||||
|
||||
DEFAULT_ECHO = True
|
||||
DEFAULT_TRACE = True
|
||||
DEFAULT_START_SIP_PORT = 50000
|
||||
DEFAULT_TELNET = True
|
||||
DEFAULT_START_TELNET_PORT = 60000
|
||||
|
||||
# Shared vars
|
||||
ARGS = [] # arguments containing script module & config
|
||||
HAS_SND_DEV = config_site.HAS_SND_DEV
|
||||
|
||||
# Individual pjsua instance configuration class
|
||||
class InstanceParam:
|
||||
# Name to identify this pjsua instance (e.g. "caller", "callee", etc.)
|
||||
name = ""
|
||||
# pjsua command line arguments, concatenated in string
|
||||
arg = ""
|
||||
# Specify whether pjsua telnet CLI is enabled
|
||||
telnet_enabled = DEFAULT_TELNET
|
||||
# Telnet port number, zero to automatically assign
|
||||
telnet_port = 0
|
||||
# Specify whether pjsua output should be echoed to stdout
|
||||
echo_enabled = DEFAULT_ECHO
|
||||
# Enable/disable test tracing
|
||||
trace_enabled = DEFAULT_TRACE
|
||||
# SIP URI to send request to this instance
|
||||
uri = ""
|
||||
# SIP port number, zero to automatically assign
|
||||
sip_port = 0
|
||||
# Does this have registration? If yes then the test function will
|
||||
# wait until the UA is registered before doing anything else
|
||||
have_reg = False
|
||||
# Does this have PUBLISH?
|
||||
have_publish = False
|
||||
# Enable stdout buffer?
|
||||
enable_buffer = False
|
||||
def __init__( self,
|
||||
name, # Instance name
|
||||
arg, # Cmd-line arguments
|
||||
uri="", # URI
|
||||
uri_param="", # Additional URI param
|
||||
telnet_port=0, # Telnet port
|
||||
sip_port=0, # SIP port
|
||||
have_reg=False, # Have registration?
|
||||
have_publish=False, # Have publish?
|
||||
echo_enabled=DEFAULT_ECHO,
|
||||
trace_enabled=DEFAULT_TRACE,
|
||||
telnet_enabled = DEFAULT_TELNET,
|
||||
enable_buffer = False):
|
||||
# Instance name
|
||||
self.name = name
|
||||
# Give random telnet_port if it's not specified and telnet CLI is enabled
|
||||
if telnet_enabled and telnet_port==0:
|
||||
# avoid port conflict
|
||||
cnt = 0
|
||||
port = 0
|
||||
while cnt < 10:
|
||||
cnt = cnt + 1
|
||||
port = random.randint(DEFAULT_START_TELNET_PORT, 65534)
|
||||
s = socket.socket(socket.AF_INET)
|
||||
try:
|
||||
s.bind(("0.0.0.0", port))
|
||||
except socket.error as serr:
|
||||
s.close()
|
||||
if serr.errno == errno.EADDRINUSE:
|
||||
continue
|
||||
s.close()
|
||||
break;
|
||||
self.telnet_port = port
|
||||
else:
|
||||
self.telnet_port = telnet_port
|
||||
# Give random sip_port if it's not specified
|
||||
if sip_port==0:
|
||||
# avoid port conflict
|
||||
cnt = 0
|
||||
port = 0
|
||||
while cnt < 10:
|
||||
cnt = cnt + 1
|
||||
port = random.randint(DEFAULT_START_SIP_PORT, 60000)
|
||||
s = socket.socket(socket.AF_INET)
|
||||
try:
|
||||
s.bind(("0.0.0.0", port))
|
||||
except socket.error as serr:
|
||||
s.close()
|
||||
if serr.errno == errno.EADDRINUSE:
|
||||
continue
|
||||
s.close()
|
||||
break;
|
||||
self.sip_port = port
|
||||
else:
|
||||
self.sip_port = sip_port
|
||||
# Autogenerate URI if it's empty.
|
||||
self.uri = uri
|
||||
if self.uri=="":
|
||||
self.uri = "sip:pjsip@127.0.0.1:" + str(self.sip_port)
|
||||
# Add uri_param to the URI
|
||||
self.uri = self.uri + uri_param
|
||||
# Add bracket to the URI
|
||||
if self.uri[0] != "<":
|
||||
self.uri = "<" + self.uri + ">"
|
||||
# Add SIP local port to the argument
|
||||
self.arg = arg + " --local-port=" + str(self.sip_port)
|
||||
self.have_reg = have_reg
|
||||
self.have_publish = have_publish
|
||||
if have_publish and have_reg and not ("--publish" in self.arg):
|
||||
self.arg = self.arg + " --publish"
|
||||
self.echo_enabled = echo_enabled
|
||||
self.trace_enabled = trace_enabled
|
||||
self.enable_buffer = enable_buffer
|
||||
|
||||
|
||||
############################################
|
||||
# Test parameter class
|
||||
class TestParam:
|
||||
title = ""
|
||||
# params is list containing InstanceParams objects
|
||||
inst_params = []
|
||||
# flag if this tes should be skipped
|
||||
skip = None
|
||||
# list of Expect instances, to be filled at run-time by
|
||||
# the test program
|
||||
process = []
|
||||
# the function for test body
|
||||
test_func = None
|
||||
post_func = None
|
||||
def __init__( self,
|
||||
title, # Test title
|
||||
inst_params, # InstanceParam's as list
|
||||
func=None,
|
||||
skip=False,
|
||||
post_func=None,
|
||||
need_stdout_buffer=False):
|
||||
self.title = title
|
||||
self.inst_params = inst_params
|
||||
self.skip = skip
|
||||
self.test_func = func
|
||||
self.post_func = post_func
|
||||
|
||||
|
||||
###################################
|
||||
# TestError exception
|
||||
class TestError:
|
||||
desc = ""
|
||||
def __init__(self, desc):
|
||||
self.desc = desc
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# $Id$
|
||||
# Useful constants
|
||||
|
||||
|
||||
##########################
|
||||
# MENU OUTPUT
|
||||
#
|
||||
|
||||
|
||||
##########################
|
||||
# EVENTS
|
||||
#
|
||||
|
||||
# Text to expect when there is incoming call
|
||||
EVENT_INCOMING_CALL = "Press .* answer"
|
||||
|
||||
|
||||
##########################
|
||||
# CALL STATES
|
||||
#
|
||||
|
||||
# Call state is CALLING
|
||||
STATE_CALLING = "state.*CALLING"
|
||||
# Call state is EARLY
|
||||
STATE_EARLY = "state.*EARLY"
|
||||
# Call state is CONFIRMED
|
||||
STATE_CONFIRMED = "state.*CONFIRMED"
|
||||
# Call state is DISCONNECTED
|
||||
STATE_DISCONNECTED = "Call .* DISCONNECTED"
|
||||
|
||||
# Media call is put on-hold
|
||||
MEDIA_HOLD = "Call [0-9]+ media [0-9]+ .*, status is .* hold"
|
||||
# Media call is active
|
||||
MEDIA_ACTIVE = "Call [0-9]+ media [0-9]+ .*, status is Active"
|
||||
#MEDIA_ACTIVE = "Media for call [0-9]+ is active"
|
||||
# RX_DTMF
|
||||
RX_DTMF = "Incoming DTMF on call [0-9]+: "
|
||||
|
||||
##########################
|
||||
# MEDIA
|
||||
#
|
||||
|
||||
# Connecting/disconnecting ports
|
||||
MEDIA_CONN_PORT_SUCCESS = "Port \d+ \(.+\) transmitting to port"
|
||||
MEDIA_DISCONN_PORT_SUCCESS = "Port \d+ \(.+\) stop transmitting to port"
|
||||
|
||||
# Filename to play / record
|
||||
MEDIA_PLAY_FILE = "--play-file\s+(\S+)"
|
||||
MEDIA_REC_FILE = "--rec-file\s+(\S+)"
|
||||
|
||||
##########################
|
||||
# MISC
|
||||
#
|
||||
|
||||
# The command prompt
|
||||
PROMPT = ">>>"
|
||||
# When pjsua has been destroyed
|
||||
DESTROYED = "PJSUA destroyed"
|
||||
# Assertion failure
|
||||
ASSERT = "Assertion failed"
|
||||
# Stdout refresh text
|
||||
STDOUT_REFRESH = "XXSTDOUT_REFRESHXX"
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# $Id$
|
||||
|
||||
# SDP template
|
||||
sdp_templ = \
|
||||
"""v=0\r
|
||||
o=- 1 1 $NET_TYPE $ADDR_TYPE $LOCAL_IP\r
|
||||
s=pjmedia\r
|
||||
t=0 0\r
|
||||
$SDP_LINES"""
|
||||
|
||||
sdp_media_templ = \
|
||||
"""m=$MEDIA_TYPE $PORT $TRANSPORT 0\r
|
||||
c=$NET_TYPE $ADDR_TYPE $LOCAL_IP\r
|
||||
$SDP_LINES"""
|
||||
|
||||
# Create SDP session
|
||||
def session(local_ip="127.0.0.1", extra_lines="", net_type="IN", addr_type="IP4"):
|
||||
sdp = sdp_templ
|
||||
sdp = sdp.replace("$NET_TYPE", net_type)
|
||||
sdp = sdp.replace("$ADDR_TYPE", addr_type)
|
||||
sdp = sdp.replace("$LOCAL_IP", local_ip)
|
||||
sdp = sdp.replace("$SDP_LINES", extra_lines)
|
||||
return sdp
|
||||
|
||||
# Create basic SDP media
|
||||
def media(media_type="audio", local_port=4000, local_ip="127.0.0.1", extra_lines="",
|
||||
net_type = "IN", addr_type="IP4", transport="RTP/AVP"):
|
||||
sdp = sdp_media_templ
|
||||
sdp = sdp.replace("$MEDIA_TYPE", media_type)
|
||||
sdp = sdp.replace("$LOCAL_IP", local_ip)
|
||||
sdp = sdp.replace("$PORT", str(local_port))
|
||||
sdp = sdp.replace("$NET_TYPE", net_type)
|
||||
sdp = sdp.replace("$ADDR_TYPE", addr_type)
|
||||
sdp = sdp.replace("$TRANSPORT", transport)
|
||||
sdp = sdp.replace("$SDP_LINES", extra_lines)
|
||||
return sdp
|
||||
|
||||
|
||||
@@ -0,0 +1,343 @@
|
||||
# $Id$
|
||||
#
|
||||
from socket import *
|
||||
import re
|
||||
import random
|
||||
import time
|
||||
import sys
|
||||
import inc_cfg as cfg
|
||||
from select import *
|
||||
|
||||
# SIP request template
|
||||
req_templ = \
|
||||
"""$METHOD $TARGET_URI SIP/2.0\r
|
||||
Via: SIP/2.0/UDP $LOCAL_IP:$LOCAL_PORT;rport;branch=z9hG4bK$BRANCH\r
|
||||
Max-Forwards: 70\r
|
||||
From: <sip:caller@pjsip.org>$FROM_TAG\r
|
||||
To: <$TARGET_URI>$TO_TAG\r
|
||||
Contact: <sip:$LOCAL_IP:$LOCAL_PORT;transport=udp>\r
|
||||
Call-ID: $CALL_ID@pjsip.org\r
|
||||
CSeq: $CSEQ $METHOD\r
|
||||
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, REFER\r
|
||||
Supported: replaces, 100rel, norefersub\r
|
||||
User-Agent: pjsip.org Python tester\r
|
||||
Content-Length: $CONTENT_LENGTH\r
|
||||
$SIP_HEADERS"""
|
||||
|
||||
|
||||
def is_request(msg):
|
||||
return msg.split(" ", 1)[0] != "SIP/2.0"
|
||||
|
||||
def is_response(msg):
|
||||
return msg.split(" ", 1)[0] == "SIP/2.0"
|
||||
|
||||
def get_code(msg):
|
||||
if msg=="":
|
||||
return 0
|
||||
return int(msg.split(" ", 2)[1])
|
||||
|
||||
def get_tag(msg, hdr="To"):
|
||||
pat = "^" + hdr + ":.*"
|
||||
result = re.search(pat, msg, re.M | re.I)
|
||||
if result==None:
|
||||
return ""
|
||||
line = result.group()
|
||||
#print "line=", line
|
||||
tags = line.split(";tag=")
|
||||
if len(tags)>1:
|
||||
return tags[1]
|
||||
return ""
|
||||
#return re.split("[;& ]", s)
|
||||
|
||||
def get_header(msg, hname):
|
||||
headers = msg.splitlines()
|
||||
for hdr in headers:
|
||||
hfields = hdr.split(": ", 2)
|
||||
if hfields[0]==hname:
|
||||
return hfields[1]
|
||||
return None
|
||||
|
||||
class Dialog:
|
||||
sock = None
|
||||
dst_addr = ""
|
||||
dst_port = 5060
|
||||
local_ip = ""
|
||||
local_port = 0
|
||||
tcp = False
|
||||
call_id = str(random.random())
|
||||
cseq = 0
|
||||
local_tag = ";tag=" + str(random.random())
|
||||
rem_tag = ""
|
||||
last_resp_code = 0
|
||||
inv_branch = ""
|
||||
trace_enabled = True
|
||||
last_request = ""
|
||||
def __init__(self, dst_addr, dst_port=5060, tcp=False, trace=True, local_port=0):
|
||||
self.dst_addr = dst_addr
|
||||
self.dst_port = dst_port
|
||||
self.tcp = tcp
|
||||
self.trace_enabled = trace
|
||||
if tcp==True:
|
||||
self.sock = socket(AF_INET, SOCK_STREAM)
|
||||
self.sock.connect(dst_addr, dst_port)
|
||||
else:
|
||||
self.sock = socket(AF_INET, SOCK_DGRAM)
|
||||
self.sock.bind(("127.0.0.1", local_port))
|
||||
|
||||
self.local_ip, self.local_port = self.sock.getsockname()
|
||||
self.trace("Dialog socket bound to " + self.local_ip + ":" + str(self.local_port))
|
||||
|
||||
def trace(self, txt):
|
||||
if self.trace_enabled:
|
||||
print str(time.strftime("%H:%M:%S ")) + txt
|
||||
|
||||
def update_fields(self, msg):
|
||||
if self.tcp:
|
||||
transport_param = ";transport=tcp"
|
||||
else:
|
||||
transport_param = ""
|
||||
msg = msg.replace("$TARGET_URI", "sip:"+self.dst_addr+":"+str(self.dst_port) + transport_param)
|
||||
msg = msg.replace("$LOCAL_IP", self.local_ip)
|
||||
msg = msg.replace("$LOCAL_PORT", str(self.local_port))
|
||||
msg = msg.replace("$FROM_TAG", self.local_tag)
|
||||
msg = msg.replace("$TO_TAG", self.rem_tag)
|
||||
msg = msg.replace("$CALL_ID", self.call_id)
|
||||
msg = msg.replace("$CSEQ", str(self.cseq))
|
||||
branch=str(random.random())
|
||||
msg = msg.replace("$BRANCH", branch)
|
||||
return msg
|
||||
|
||||
def create_req(self, method, sdp, branch="", extra_headers="", body=""):
|
||||
if branch=="":
|
||||
self.cseq = self.cseq + 1
|
||||
msg = req_templ
|
||||
msg = msg.replace("$METHOD", method)
|
||||
msg = msg.replace("$SIP_HEADERS", extra_headers)
|
||||
if branch=="":
|
||||
branch=str(random.random())
|
||||
msg = msg.replace("$BRANCH", branch)
|
||||
if sdp!="":
|
||||
msg = msg.replace("$CONTENT_LENGTH", str(len(sdp)))
|
||||
msg = msg + "Content-Type: application/sdp\r\n"
|
||||
msg = msg + "\r\n"
|
||||
msg = msg + sdp
|
||||
elif body!="":
|
||||
msg = msg.replace("$CONTENT_LENGTH", str(len(body)))
|
||||
msg = msg + "\r\n"
|
||||
msg = msg + body
|
||||
else:
|
||||
msg = msg.replace("$CONTENT_LENGTH", "0")
|
||||
return self.update_fields(msg)
|
||||
|
||||
def create_response(self, request, code, reason, to_tag=""):
|
||||
response = "SIP/2.0 " + str(code) + " " + reason + "\r\n"
|
||||
lines = request.splitlines()
|
||||
for line in lines:
|
||||
hdr = line.split(":", 1)[0]
|
||||
if hdr in ["Via", "From", "To", "CSeq", "Call-ID"]:
|
||||
if hdr=="To" and to_tag!="":
|
||||
line = line + ";tag=" + to_tag
|
||||
elif hdr=="Via":
|
||||
line = line + ";received=127.0.0.1"
|
||||
response = response + line + "\r\n"
|
||||
return response
|
||||
|
||||
def create_invite(self, sdp, extra_headers="", body=""):
|
||||
self.inv_branch = str(random.random())
|
||||
return self.create_req("INVITE", sdp, branch=self.inv_branch, extra_headers=extra_headers, body=body)
|
||||
|
||||
def create_ack(self, sdp="", extra_headers=""):
|
||||
return self.create_req("ACK", sdp, extra_headers=extra_headers, branch=self.inv_branch)
|
||||
|
||||
def create_bye(self, extra_headers=""):
|
||||
return self.create_req("BYE", "", extra_headers)
|
||||
|
||||
def send_msg(self, msg, dst_addr=None):
|
||||
if (is_request(msg)):
|
||||
self.last_request = msg.split(" ", 1)[0]
|
||||
if not dst_addr:
|
||||
dst_addr = (self.dst_addr, self.dst_port)
|
||||
self.trace("============== TX MSG to " + str(dst_addr) + " ============= \n" + msg)
|
||||
self.sock.sendto(msg, 0, dst_addr)
|
||||
|
||||
def wait_msg_from(self, timeout):
|
||||
endtime = time.time() + timeout
|
||||
msg = ""
|
||||
src_addr = None
|
||||
while time.time() < endtime:
|
||||
readset = select([self.sock], [], [], 1)
|
||||
if len(readset[0]) < 1 or not self.sock in readset[0]:
|
||||
if len(readset[0]) < 1:
|
||||
print "select() timeout (will wait for " + str(int(endtime - time.time())) + "more secs)"
|
||||
elif not self.sock in readset[0]:
|
||||
print "select() alien socket"
|
||||
else:
|
||||
print "select other error"
|
||||
continue
|
||||
try:
|
||||
msg, src_addr = self.sock.recvfrom(4096)
|
||||
break
|
||||
except:
|
||||
print "recv() exception: ", sys.exc_info()[0]
|
||||
continue
|
||||
|
||||
if msg=="":
|
||||
return "", None
|
||||
if self.last_request=="INVITE" and self.rem_tag=="":
|
||||
self.rem_tag = get_tag(msg, "To")
|
||||
self.rem_tag = self.rem_tag.rstrip("\r\n;")
|
||||
if self.rem_tag != "":
|
||||
self.rem_tag = ";tag=" + self.rem_tag
|
||||
self.trace("=== rem_tag:" + self.rem_tag)
|
||||
self.trace("=========== RX MSG from " + str(src_addr) + " ===========\n" + msg)
|
||||
return (msg, src_addr)
|
||||
|
||||
def wait_msg(self, timeout):
|
||||
return self.wait_msg_from(timeout)[0]
|
||||
|
||||
# Send request and wait for final response
|
||||
def send_request_wait(self, msg, timeout):
|
||||
t1 = 1.0
|
||||
endtime = time.time() + timeout
|
||||
resp = ""
|
||||
code = 0
|
||||
for i in range(0,5):
|
||||
self.send_msg(msg)
|
||||
resp = self.wait_msg(t1)
|
||||
if resp!="" and is_response(resp):
|
||||
code = get_code(resp)
|
||||
break
|
||||
last_resp = resp
|
||||
while code < 200 and time.time() < endtime:
|
||||
resp = self.wait_msg(endtime - time.time())
|
||||
if resp != "" and is_response(resp):
|
||||
code = get_code(resp)
|
||||
last_resp = resp
|
||||
elif resp=="":
|
||||
break
|
||||
return last_resp
|
||||
|
||||
def hangup(self, last_code=0):
|
||||
self.trace("====== hangup =====")
|
||||
if last_code!=0:
|
||||
self.last_resp_code = last_code
|
||||
if self.last_resp_code>0 and self.last_resp_code<200:
|
||||
msg = self.create_req("CANCEL", "", branch=self.inv_branch, extra_headers="")
|
||||
self.send_request_wait(msg, 5)
|
||||
msg = self.create_ack()
|
||||
self.send_msg(msg)
|
||||
elif self.last_resp_code>=200 and self.last_resp_code<300:
|
||||
msg = self.create_ack()
|
||||
self.send_msg(msg)
|
||||
msg = self.create_bye()
|
||||
self.send_request_wait(msg, 5)
|
||||
else:
|
||||
msg = self.create_ack()
|
||||
self.send_msg(msg)
|
||||
|
||||
|
||||
class SendtoCfg:
|
||||
# Test name
|
||||
name = ""
|
||||
# pjsua InstanceParam
|
||||
inst_param = None
|
||||
# Complete INVITE message. If this is not empty, then this
|
||||
# message will be sent instead and the "sdp" and "extra_headers"
|
||||
# settings will be ignored.
|
||||
complete_msg = ""
|
||||
# Initial SDP
|
||||
sdp = ""
|
||||
# Extra headers to add to request
|
||||
extra_headers = ""
|
||||
# Expected code
|
||||
resp_code = 0
|
||||
# Use TCP?
|
||||
use_tcp = False
|
||||
# List of RE patterns that must exist in response
|
||||
resp_include = []
|
||||
# List of RE patterns that must NOT exist in response
|
||||
resp_exclude = []
|
||||
# Full (non-SDP) body
|
||||
body = ""
|
||||
# Constructor
|
||||
def __init__(self, name, pjsua_args, sdp, resp_code,
|
||||
resp_inc=[], resp_exc=[], use_tcp=False,
|
||||
extra_headers="", body="", complete_msg="",
|
||||
enable_buffer = False):
|
||||
self.complete_msg = complete_msg
|
||||
self.sdp = sdp
|
||||
self.resp_code = resp_code
|
||||
self.resp_include = resp_inc
|
||||
self.resp_exclude = resp_exc
|
||||
self.use_tcp = use_tcp
|
||||
self.extra_headers = extra_headers
|
||||
self.body = body
|
||||
self.inst_param = cfg.InstanceParam("pjsua", pjsua_args)
|
||||
self.inst_param.enable_buffer = enable_buffer
|
||||
|
||||
|
||||
class RecvfromTransaction:
|
||||
# The test title for this transaction
|
||||
title = ""
|
||||
# Optinal list of pjsua command and optional expect patterns
|
||||
# to be invoked to make pjsua send a request
|
||||
# Sample:
|
||||
# (to make call and wait for INVITE to be sent)
|
||||
# cmds = [ ["m"], ["sip:127.0.0.1", "INVITE sip:"] ]
|
||||
cmds = []
|
||||
# Check if the CSeq must be greater than last Cseq?
|
||||
check_cseq = True
|
||||
# List of RE patterns that must exists in incoming request
|
||||
include = []
|
||||
# List of RE patterns that MUST NOT exist in incoming request
|
||||
exclude = []
|
||||
# Response code to send
|
||||
resp_code = 0
|
||||
# Additional list of headers to be sent on the response
|
||||
# Note: no need to add CRLF on the header
|
||||
resp_hdr = []
|
||||
# Message body. This should include the Content-Type header too.
|
||||
# Sample:
|
||||
# body = """Content-Type: application/sdp\r\n
|
||||
# \r\n
|
||||
# v=0\r\n
|
||||
# ...
|
||||
# """
|
||||
body = None
|
||||
# Pattern to be expected on pjsua when receiving the response
|
||||
expect = ""
|
||||
|
||||
def __init__(self, title, resp_code, check_cseq=True,
|
||||
include=[], exclude=[], cmds=[], resp_hdr=[], resp_body=None, expect=""):
|
||||
self.title = title
|
||||
self.cmds = cmds
|
||||
self.include = include
|
||||
self.exclude = exclude
|
||||
self.resp_code = resp_code
|
||||
self.resp_hdr = resp_hdr
|
||||
self.body = resp_body
|
||||
self.expect = expect
|
||||
|
||||
|
||||
class RecvfromCfg:
|
||||
# Test name
|
||||
name = ""
|
||||
# pjsua InstanceParam
|
||||
inst_param = None
|
||||
# List of RecvfromTransaction
|
||||
transaction = None
|
||||
# Use TCP?
|
||||
tcp = False
|
||||
|
||||
# Note:
|
||||
# Any "$PORT" string in the pjsua_args will be replaced
|
||||
# by server port
|
||||
def __init__(self, name, pjsua_args, transaction, tcp=False):
|
||||
self.name = name
|
||||
self.inst_param = cfg.InstanceParam("pjsua", pjsua_args)
|
||||
self.transaction = transaction
|
||||
self.tcp=tcp
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
# $Id$
|
||||
import time
|
||||
import imp
|
||||
import sys
|
||||
import inc_const as const
|
||||
from inc_cfg import *
|
||||
|
||||
# Load configuration
|
||||
cfg_file = imp.load_source("cfg_file", ARGS[1])
|
||||
|
||||
# Trigger address switch for media flow between ua1 and ua2.
|
||||
# When the receiver uses STUN while both sides are actually in the same
|
||||
# private network, initial media packets may be sent to public IP address
|
||||
# as specified in the receiver SDP and those packets may not be delivered
|
||||
# if the NAT does not support hairpinning. This function will make both
|
||||
# sides to send some initial packets to trigger destination address switch
|
||||
# in media transport, so future packets will be delivered to the correct
|
||||
# address (private IP address).
|
||||
def hole_punch(ua1, ua2):
|
||||
if ua1.use_telnet:
|
||||
ua1.send("# 987")
|
||||
else:
|
||||
ua1.send("#")
|
||||
ua1.expect("#")
|
||||
ua1.send("987")
|
||||
|
||||
if ua2.use_telnet:
|
||||
ua2.send("# 789")
|
||||
else:
|
||||
ua2.send("#")
|
||||
ua2.expect("#")
|
||||
ua2.send("789")
|
||||
|
||||
time.sleep(0.1)
|
||||
|
||||
|
||||
# Check media flow between ua1 and ua2
|
||||
def check_media(ua1, ua2):
|
||||
if ua1.use_telnet:
|
||||
ua1.send("# 1122")
|
||||
else:
|
||||
ua1.send("#")
|
||||
ua1.expect("#")
|
||||
ua1.send("1122")
|
||||
ua2.expect(const.RX_DTMF + "1")
|
||||
ua2.expect(const.RX_DTMF + "1")
|
||||
ua2.expect(const.RX_DTMF + "2")
|
||||
ua2.expect(const.RX_DTMF + "2")
|
||||
|
||||
|
||||
# Test body function
|
||||
def test_func(t):
|
||||
callee = t.process[0]
|
||||
caller = t.process[1]
|
||||
|
||||
# if have_reg then wait for couple of seconds for PUBLISH
|
||||
# to complete (just in case pUBLISH is used)
|
||||
if callee.inst_param.have_reg:
|
||||
time.sleep(1)
|
||||
if caller.inst_param.have_reg:
|
||||
time.sleep(1)
|
||||
|
||||
# Check if ICE is used
|
||||
use_ice = ("--use-ice" in caller.inst_param.arg) and ("--use-ice" in callee.inst_param.arg)
|
||||
|
||||
# Check if STUN is used (by either side)
|
||||
use_stun = ("--stun-srv" in caller.inst_param.arg) or ("--stun-srv" in callee.inst_param.arg)
|
||||
|
||||
# Check if DTLS-SRTP is used
|
||||
use_dtls_srtp = "--srtp-keying=1" in caller.inst_param.arg
|
||||
|
||||
# Caller making call
|
||||
if caller.use_telnet:
|
||||
caller.send("call new " + t.inst_params[0].uri)
|
||||
else:
|
||||
caller.send("m")
|
||||
caller.send(t.inst_params[0].uri)
|
||||
caller.expect(const.STATE_CALLING)
|
||||
|
||||
# Callee waits for call and answers with 180/Ringing
|
||||
time.sleep(0.2)
|
||||
callee.expect(const.EVENT_INCOMING_CALL)
|
||||
if callee.use_telnet:
|
||||
callee.send("call answer 180")
|
||||
else:
|
||||
callee.send("a")
|
||||
callee.send("180")
|
||||
callee.expect("SIP/2.0 180")
|
||||
caller.expect("SIP/2.0 180")
|
||||
|
||||
# Synchronize stdout
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
|
||||
# Callee answers with 200/OK
|
||||
if callee.use_telnet:
|
||||
callee.send("call answer 200")
|
||||
else:
|
||||
callee.send("a")
|
||||
callee.send("200")
|
||||
|
||||
# Wait until call is connected in both endpoints
|
||||
##time.sleep(0.2)
|
||||
caller.expect(const.STATE_CONFIRMED)
|
||||
callee.expect(const.STATE_CONFIRMED)
|
||||
|
||||
# Synchronize stdout
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
##time.sleep(0.1)
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
|
||||
# Wait ICE nego before checking media
|
||||
if use_ice:
|
||||
# Unfortunately ICE nego may race with STATE_CONFIRMED (esp. on callee side), so let's just sleep
|
||||
#caller.expect("ICE negotiation success")
|
||||
#callee.expect("ICE negotiation success")
|
||||
# Additional wait for ICE updating address (via UPDATE/re-INVITE)
|
||||
time.sleep(0.5)
|
||||
|
||||
# Wait DTLS-SRTP nego before checking media
|
||||
if use_dtls_srtp:
|
||||
# Unfortunately DTLS-SRTP nego may race with STATE_CONFIRMED, so let's just sleep
|
||||
#caller.expect("SRTP started, keying=DTLS-SRTP")
|
||||
#callee.expect("SRTP started, keying=DTLS-SRTP")
|
||||
time.sleep(0.5)
|
||||
|
||||
# Trigger address switch before checking media
|
||||
if use_stun and not use_ice:
|
||||
hole_punch(caller, callee)
|
||||
|
||||
# Test that media is okay
|
||||
check_media(caller, callee)
|
||||
check_media(callee, caller)
|
||||
|
||||
# Hold call by caller
|
||||
if caller.use_telnet:
|
||||
caller.send("call hold")
|
||||
else:
|
||||
caller.send("H")
|
||||
caller.expect("INVITE sip:")
|
||||
callee.expect("INVITE sip:")
|
||||
callee.expect(const.MEDIA_HOLD)
|
||||
caller.expect(const.MEDIA_HOLD)
|
||||
|
||||
# Synchronize stdout
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
|
||||
# Release hold
|
||||
##time.sleep(0.5)
|
||||
if caller.use_telnet:
|
||||
caller.send("call reinvite")
|
||||
else:
|
||||
caller.send("v")
|
||||
caller.expect("INVITE sip:")
|
||||
callee.expect("INVITE sip:")
|
||||
callee.expect(const.MEDIA_ACTIVE, title="waiting for media active after call hold")
|
||||
caller.expect(const.MEDIA_ACTIVE, title="waiting for media active after call hold")
|
||||
|
||||
# Synchronize stdout
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
|
||||
# Trigger address switch before checking media
|
||||
if use_stun and not use_ice:
|
||||
hole_punch(caller, callee)
|
||||
|
||||
# Test that media is okay
|
||||
check_media(caller, callee)
|
||||
check_media(callee, caller)
|
||||
|
||||
# Synchronize stdout
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
|
||||
# Hold call by callee
|
||||
if callee.use_telnet:
|
||||
callee.send("call hold")
|
||||
else:
|
||||
callee.send("H")
|
||||
callee.expect("INVITE sip:")
|
||||
caller.expect("INVITE sip:")
|
||||
caller.expect(const.MEDIA_HOLD)
|
||||
callee.expect(const.MEDIA_HOLD)
|
||||
|
||||
# Synchronize stdout
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
|
||||
# Release hold
|
||||
##time.sleep(0.1)
|
||||
if callee.use_telnet:
|
||||
callee.send("call reinvite")
|
||||
else:
|
||||
callee.send("v")
|
||||
callee.expect("INVITE sip:")
|
||||
caller.expect("INVITE sip:")
|
||||
caller.expect(const.MEDIA_ACTIVE, title="waiting for media active after call hold")
|
||||
callee.expect(const.MEDIA_ACTIVE, title="waiting for media active after call hold")
|
||||
|
||||
# Synchronize stdout
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
|
||||
# Trigger address switch before checking media
|
||||
if use_stun and not use_ice:
|
||||
hole_punch(caller, callee)
|
||||
|
||||
# Test that media is okay
|
||||
# Wait for some time for ICE negotiation
|
||||
##time.sleep(0.6)
|
||||
check_media(caller, callee)
|
||||
check_media(callee, caller)
|
||||
|
||||
# Synchronize stdout
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
|
||||
# UPDATE (by caller)
|
||||
if caller.use_telnet:
|
||||
caller.send("call update")
|
||||
else:
|
||||
caller.send("U")
|
||||
#caller.sync_stdout()
|
||||
callee.expect(const.MEDIA_ACTIVE, title="waiting for media active with UPDATE")
|
||||
caller.expect(const.MEDIA_ACTIVE, title="waiting for media active with UPDATE")
|
||||
|
||||
# Synchronize stdout
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
|
||||
# Trigger address switch before checking media
|
||||
if use_stun and not use_ice:
|
||||
hole_punch(caller, callee)
|
||||
|
||||
# Test that media is okay
|
||||
##time.sleep(0.1)
|
||||
check_media(caller, callee)
|
||||
check_media(callee, caller)
|
||||
|
||||
# UPDATE (by callee)
|
||||
if callee.use_telnet:
|
||||
callee.send("call update")
|
||||
else:
|
||||
callee.send("U")
|
||||
callee.expect("UPDATE sip:")
|
||||
caller.expect("UPDATE sip:")
|
||||
caller.expect(const.MEDIA_ACTIVE, title="waiting for media active with UPDATE")
|
||||
callee.expect(const.MEDIA_ACTIVE, title="waiting for media active with UPDATE")
|
||||
|
||||
# Synchronize stdout
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
|
||||
# Trigger address switch before checking media
|
||||
if use_stun and not use_ice:
|
||||
hole_punch(caller, callee)
|
||||
|
||||
# Test that media is okay
|
||||
##time.sleep(0.1)
|
||||
check_media(caller, callee)
|
||||
check_media(callee, caller)
|
||||
|
||||
# Synchronize stdout
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
|
||||
# Set codecs in both caller and callee so that there is
|
||||
# no common codec between them.
|
||||
# In caller we only enable PCMU, in callee we only enable PCMA
|
||||
if caller.use_telnet:
|
||||
caller.send("Cp * 0")
|
||||
caller.send("Cp")
|
||||
caller.expect("PCMU/8000.* prio: 0")
|
||||
caller.send("Cp PCMU 120")
|
||||
caller.send("Cp")
|
||||
caller.expect("PCMU/8000.* prio: 120")
|
||||
else:
|
||||
caller.send("Cp")
|
||||
caller.expect("Enter codec")
|
||||
caller.send("* 0")
|
||||
caller.send("Cp")
|
||||
caller.expect("Enter codec")
|
||||
caller.send("pcmu 120")
|
||||
|
||||
if callee.use_telnet:
|
||||
callee.send("Cp * 0")
|
||||
callee.send("Cp")
|
||||
callee.expect("PCMA/8000.* prio: 0")
|
||||
callee.send("Cp PCMA 120")
|
||||
callee.send("Cp")
|
||||
callee.expect("PCMA/8000.* prio: 120")
|
||||
else:
|
||||
callee.send("Cp")
|
||||
callee.expect("Enter codec")
|
||||
callee.send("* 0")
|
||||
callee.send("Cp")
|
||||
callee.expect("Enter codec")
|
||||
callee.send("pcma 120")
|
||||
|
||||
# Test when UPDATE fails (by callee)
|
||||
if callee.use_telnet:
|
||||
callee.send("call update")
|
||||
else:
|
||||
callee.send("U")
|
||||
caller.expect("SIP/2.0 488")
|
||||
callee.expect("SIP/2.0 488")
|
||||
callee.sync_stdout()
|
||||
caller.sync_stdout()
|
||||
|
||||
# Test that media is still okay
|
||||
##time.sleep(0.1)
|
||||
check_media(caller, callee)
|
||||
check_media(callee, caller)
|
||||
|
||||
# Test when UPDATE fails (by caller)
|
||||
if caller.use_telnet:
|
||||
caller.send("call update")
|
||||
else:
|
||||
caller.send("U")
|
||||
caller.expect("UPDATE sip:")
|
||||
callee.expect("UPDATE sip:")
|
||||
callee.expect("SIP/2.0 488")
|
||||
caller.expect("SIP/2.0 488")
|
||||
caller.sync_stdout()
|
||||
callee.sync_stdout()
|
||||
|
||||
# Test that media is still okay
|
||||
##time.sleep(0.1)
|
||||
check_media(callee, caller)
|
||||
check_media(caller, callee)
|
||||
|
||||
# Hangup call
|
||||
##time.sleep(0.1)
|
||||
if caller.use_telnet:
|
||||
caller.send("call hangup")
|
||||
else:
|
||||
caller.send("h")
|
||||
|
||||
# Wait until calls are cleared in both endpoints
|
||||
caller.expect(const.STATE_DISCONNECTED)
|
||||
callee.expect(const.STATE_DISCONNECTED)
|
||||
|
||||
|
||||
# Here where it all comes together
|
||||
test = cfg_file.test_param
|
||||
test.test_func = test_func
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
# $Id$
|
||||
|
||||
# PLAYFILE -> RECFILE:
|
||||
# Input file is played and is recorded to output, then compare them.
|
||||
# Useful to tes clock rates compatibility and resample quality
|
||||
# null-audio
|
||||
# port 1: wav file input xxxxxx.clock_rate.wav, e.g: test1.8.wav
|
||||
# port 2: wav file ouput xxxxxx.clock_rate.wav, e.g: res1.8.wav
|
||||
# wav input must be more than 3 seconds long
|
||||
|
||||
import time
|
||||
import imp
|
||||
import sys
|
||||
import re
|
||||
import subprocess
|
||||
import inc_const as const
|
||||
from inc_cfg import *
|
||||
|
||||
# Load configuration
|
||||
cfg_file = imp.load_source("cfg_file", ARGS[1])
|
||||
|
||||
# WAV similarity calculator
|
||||
COMPARE_WAV_EXE = ""
|
||||
if sys.platform.find("win32")!=-1:
|
||||
COMPARE_WAV_EXE = "tools/cmp_wav.exe"
|
||||
G_INUNIX = False
|
||||
else:
|
||||
COMPARE_WAV_EXE = "tools/cmp_wav"
|
||||
G_INUNIX = True
|
||||
|
||||
|
||||
# Threshold to declare degradation is too high when result is lower than this value
|
||||
COMPARE_THRESHOLD = 2
|
||||
|
||||
# COMPARE params
|
||||
input_filename = "" # Input filename
|
||||
output_filename = "" # Output filename
|
||||
|
||||
# Test body function
|
||||
def test_func(t):
|
||||
global input_filename
|
||||
global output_filename
|
||||
|
||||
endpt = t.process[0]
|
||||
|
||||
# Get input file name
|
||||
input_filename = re.compile(const.MEDIA_PLAY_FILE).search(endpt.inst_param.arg).group(1)
|
||||
endpt.trace("Input file = " + input_filename)
|
||||
|
||||
# Get output file name
|
||||
output_filename = re.compile(const.MEDIA_REC_FILE).search(endpt.inst_param.arg).group(1)
|
||||
endpt.trace("Output file = " + output_filename)
|
||||
|
||||
# Find appropriate clock rate for the input file
|
||||
clock_rate = re.compile(".+(\.\d+\.wav)$").match(output_filename).group(1)
|
||||
if (clock_rate==None):
|
||||
endpt.trace("Cannot compare input & output, incorrect output filename format")
|
||||
return
|
||||
input_filename = re.sub("\.\d+\.wav$", clock_rate, input_filename)
|
||||
endpt.trace("WAV file to be compared with output = " + input_filename)
|
||||
|
||||
# Connect input-output file
|
||||
endpt.sync_stdout()
|
||||
|
||||
endpt.send("cc 1 2")
|
||||
endpt.expect(const.MEDIA_CONN_PORT_SUCCESS)
|
||||
|
||||
# Wait
|
||||
time.sleep(3)
|
||||
|
||||
endpt.sync_stdout()
|
||||
|
||||
# Disconnect input-output file
|
||||
endpt.send("cd 1 2")
|
||||
endpt.expect(const.MEDIA_DISCONN_PORT_SUCCESS)
|
||||
|
||||
|
||||
# Post body function
|
||||
def post_func(t):
|
||||
global input_filename
|
||||
global output_filename
|
||||
|
||||
endpt = t.process[0]
|
||||
|
||||
# Check WAV similarity
|
||||
fullcmd = COMPARE_WAV_EXE + " " + input_filename + " " + output_filename + " " + "3000"
|
||||
endpt.trace("Popen " + fullcmd)
|
||||
cmp_proc = subprocess.Popen(fullcmd, shell=G_INUNIX, stdout=subprocess.PIPE, universal_newlines=True)
|
||||
|
||||
# Parse similarity ouput
|
||||
line = cmp_proc.stdout.readline()
|
||||
mo_sim_val = re.match(".+=\s+(\d+)", line)
|
||||
if (mo_sim_val == None):
|
||||
raise TestError("Error comparing WAV files")
|
||||
return
|
||||
|
||||
# Evaluate the similarity value
|
||||
sim_val = mo_sim_val.group(1)
|
||||
if (sim_val >= COMPARE_THRESHOLD):
|
||||
endpt.trace("WAV similarity = " + sim_val)
|
||||
else:
|
||||
raise TestError("WAV degraded heavily, similarity = " + sim_val)
|
||||
|
||||
|
||||
# Here where it all comes together
|
||||
test = cfg_file.test_param
|
||||
test.test_func = test_func
|
||||
test.post_func = post_func
|
||||
@@ -0,0 +1,174 @@
|
||||
# $Id$
|
||||
|
||||
# Quality test of media calls.
|
||||
# - UA1 calls UA2
|
||||
# - UA1 plays a file until finished to be streamed to UA2
|
||||
# - UA2 records from stream
|
||||
# - Apply PESQ to played file (reference) and recorded file (degraded)
|
||||
#
|
||||
# File should be:
|
||||
# - naming: xxxxxx.CLOCK_RATE.wav, e.g: test1.8.wav
|
||||
# - clock-rate of those files can only be 8khz or 16khz
|
||||
|
||||
import time
|
||||
import imp
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import subprocess
|
||||
import wave
|
||||
import shutil
|
||||
import inc_const as const
|
||||
|
||||
from inc_cfg import *
|
||||
|
||||
# Load configuration
|
||||
cfg_file = imp.load_source("cfg_file", ARGS[1])
|
||||
|
||||
# PESQ configs
|
||||
PESQ = "tools/pesq" # PESQ executable path
|
||||
PESQ_DEFAULT_THRESHOLD = 3.4 # Default minimum acceptable PESQ MOS value
|
||||
|
||||
# PESQ params
|
||||
pesq_sample_rate_opt = "" # Sample rate option for PESQ
|
||||
input_filename = "" # Input/Reference filename
|
||||
output_filename = "" # Output/Degraded filename
|
||||
|
||||
|
||||
# Test body function
|
||||
def test_func(t):
|
||||
global pesq_sample_rate_opt
|
||||
global input_filename
|
||||
global output_filename
|
||||
|
||||
ua1 = t.process[0]
|
||||
ua2 = t.process[1]
|
||||
|
||||
# Get input file name
|
||||
input_filename = re.compile(const.MEDIA_PLAY_FILE).search(ua1.inst_param.arg).group(1)
|
||||
|
||||
# Get output file name
|
||||
output_filename = re.compile(const.MEDIA_REC_FILE).search(ua2.inst_param.arg).group(1)
|
||||
|
||||
# Get WAV input length, in seconds
|
||||
fin = wave.open(input_filename, "r")
|
||||
if fin == None:
|
||||
raise TestError("Failed opening input WAV file")
|
||||
inwavlen = fin.getnframes() * 1.0 / fin.getframerate()
|
||||
inwavlen += 0.2
|
||||
fin.close()
|
||||
print "WAV input len = " + str(inwavlen) + "s"
|
||||
|
||||
# Get clock rate of the output
|
||||
mo_clock_rate = re.compile("\.(\d+)\.wav").search(output_filename)
|
||||
if (mo_clock_rate==None):
|
||||
raise TestError("Cannot compare input & output, incorrect output filename format")
|
||||
clock_rate = mo_clock_rate.group(1)
|
||||
|
||||
# Get channel count of the output
|
||||
channel_count = 1
|
||||
if re.search("--stereo", ua2.inst_param.arg) != None:
|
||||
channel_count = 2
|
||||
|
||||
# Get matched input file from output file
|
||||
# (PESQ evaluates only files whose same clock rate & channel count)
|
||||
if channel_count == 2:
|
||||
if re.search("\.\d+\.\d+\.wav", input_filename) != None:
|
||||
input_filename = re.sub("\.\d+\.\d+\.wav", "." + str(channel_count) + "."+clock_rate+".wav", input_filename)
|
||||
else:
|
||||
input_filename = re.sub("\.\d+\.wav", "." + str(channel_count) + "."+clock_rate+".wav", input_filename)
|
||||
|
||||
if (clock_rate != "8") & (clock_rate != "16"):
|
||||
raise TestError("PESQ only works on clock rate 8kHz or 16kHz, clock rate used = "+clock_rate+ "kHz")
|
||||
|
||||
# Get conference clock rate of UA2 for PESQ sample rate option
|
||||
pesq_sample_rate_opt = "+" + clock_rate + "000"
|
||||
|
||||
# UA1 making call
|
||||
if ua1.use_telnet:
|
||||
ua1.send("call new " + t.inst_params[1].uri)
|
||||
else:
|
||||
ua1.send("m")
|
||||
ua1.send(t.inst_params[1].uri)
|
||||
ua1.expect(const.STATE_CALLING)
|
||||
|
||||
# UA2 wait until call established
|
||||
ua2.expect(const.STATE_CONFIRMED)
|
||||
|
||||
ua1.sync_stdout()
|
||||
ua2.sync_stdout()
|
||||
time.sleep(2)
|
||||
|
||||
# Disconnect mic -> rec file, to avoid echo recorded when using sound device
|
||||
# Disconnect stream -> spk, make it silent
|
||||
# Connect stream -> rec file, start recording
|
||||
ua2.send("cd 0 1")
|
||||
ua2.send("cd 4 0")
|
||||
ua2.send("cc 4 1")
|
||||
|
||||
# Disconnect mic -> stream, make stream purely sending from file
|
||||
# Disconnect stream -> spk, make it silent
|
||||
# Connect file -> stream, start sending
|
||||
ua1.send("cd 0 4")
|
||||
ua1.send("cd 4 0")
|
||||
ua1.send("cc 1 4")
|
||||
|
||||
time.sleep(inwavlen)
|
||||
|
||||
# Disconnect files from bridge
|
||||
ua2.send("cd 4 1")
|
||||
ua2.expect(const.MEDIA_DISCONN_PORT_SUCCESS)
|
||||
ua1.send("cd 1 4")
|
||||
ua1.expect(const.MEDIA_DISCONN_PORT_SUCCESS)
|
||||
|
||||
|
||||
# Post body function
|
||||
def post_func(t):
|
||||
global pesq_sample_rate_opt
|
||||
global input_filename
|
||||
global output_filename
|
||||
|
||||
endpt = t.process[0]
|
||||
|
||||
# Execute PESQ
|
||||
fullcmd = os.path.normpath(PESQ) + " " + pesq_sample_rate_opt + " " + input_filename + " " + output_filename
|
||||
endpt.trace("Popen " + fullcmd)
|
||||
pesq_proc = subprocess.Popen(fullcmd, shell=True, stdout=subprocess.PIPE, universal_newlines=True)
|
||||
pesq_out = pesq_proc.communicate()
|
||||
|
||||
# Parse ouput
|
||||
mo_pesq_out = re.compile("Prediction[^=]+=\s+([\-\d\.]+)\s*").search(pesq_out[0])
|
||||
if (mo_pesq_out == None):
|
||||
raise TestError("Failed to fetch PESQ result")
|
||||
|
||||
# Get threshold
|
||||
if (cfg_file.pesq_threshold != None) | (cfg_file.pesq_threshold > -0.5 ):
|
||||
threshold = cfg_file.pesq_threshold
|
||||
else:
|
||||
threshold = PESQ_DEFAULT_THRESHOLD
|
||||
|
||||
# Evaluate the PESQ MOS value
|
||||
pesq_res = mo_pesq_out.group(1)
|
||||
if (float(pesq_res) >= threshold):
|
||||
endpt.trace("Success, PESQ result = " + pesq_res + " (target=" + str(threshold) + ").")
|
||||
else:
|
||||
endpt.trace("Failed, PESQ result = " + pesq_res + " (target=" + str(threshold) + ").")
|
||||
# Save the wav file
|
||||
wavoutname = ARGS[1]
|
||||
wavoutname = re.sub("[\\\/]", "_", wavoutname)
|
||||
wavoutname = re.sub("\.py$", ".wav", wavoutname)
|
||||
wavoutname = "logs/" + wavoutname
|
||||
try:
|
||||
shutil.copyfile(output_filename, wavoutname)
|
||||
print "Output WAV is copied to " + wavoutname
|
||||
except:
|
||||
print "Couldn't copy output WAV, please check if 'logs' directory exists."
|
||||
|
||||
raise TestError("WAV seems to be degraded badly, PESQ = "+ pesq_res + " (target=" + str(threshold) + ").")
|
||||
|
||||
|
||||
# Here where it all comes together
|
||||
test = cfg_file.test_param
|
||||
test.test_func = test_func
|
||||
test.post_func = post_func
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
# $Id$
|
||||
import time
|
||||
import imp
|
||||
import sys
|
||||
import inc_const as const
|
||||
from inc_cfg import *
|
||||
|
||||
# Load configuration
|
||||
cfg_file = imp.load_source("cfg_file", ARGS[1])
|
||||
|
||||
|
||||
# Test body function
|
||||
def test_func(t):
|
||||
u1 = t.process[0]
|
||||
uri1 = cfg_file.test_param.inst_params[0].uri
|
||||
acc1 = "-1"
|
||||
u2 = t.process[1]
|
||||
uri2 = cfg_file.test_param.inst_params[1].uri
|
||||
acc2 = "-1"
|
||||
|
||||
# if have_reg then wait for couple of seconds for PUBLISH
|
||||
# to complete (just in case pUBLISH is used)
|
||||
if u1.inst_param.have_reg:
|
||||
time.sleep(1)
|
||||
if u2.inst_param.have_reg:
|
||||
time.sleep(1)
|
||||
|
||||
# U1 adds U2 as buddy
|
||||
if u1.use_telnet:
|
||||
u1.send("im add_b " + uri2)
|
||||
else:
|
||||
u1.send("+b")
|
||||
u1.send(uri2)
|
||||
u1.expect("Subscription state changed NULL --> SENT")
|
||||
u1.expect("Presence subscription.*is ACCEPTED")
|
||||
if not u2.inst_param.have_publish:
|
||||
# Process incoming SUBSCRIBE in U2
|
||||
# Finds out which account gets the subscription in U2
|
||||
line = u2.expect("pjsua_pres.*subscription.*using account")
|
||||
acc2 = line.split("using account ")[1]
|
||||
# wait until we've got Online notification
|
||||
u1.expect(uri2 + ".*Online")
|
||||
|
||||
# Synchronize stdout
|
||||
u1.sync_stdout()
|
||||
u2.sync_stdout()
|
||||
|
||||
# U2 adds U1 as buddy
|
||||
if u2.use_telnet:
|
||||
u2.send("im add_b " + uri1)
|
||||
else:
|
||||
u2.send("+b")
|
||||
u2.send(uri1)
|
||||
u2.expect("Subscription state changed NULL --> SENT")
|
||||
# sometime it is NULL->SENT->ACCEPTED->ACTIVE
|
||||
# some othertime NULL->SENT->ACTIVE
|
||||
#u2.expect("Presence subscription.*is ACCEPTED")
|
||||
u2.expect("Presence subscription.*is ACTIVE")
|
||||
if not u1.inst_param.have_publish:
|
||||
# Process incoming SUBSCRIBE in U1
|
||||
# Finds out which account gets the subscription in U1
|
||||
line = u1.expect("pjsua_pres.*subscription.*using account")
|
||||
acc1 = line.split("using account ")[1]
|
||||
# wait until we've got Online notification
|
||||
u2.expect(uri1 + ".*Online")
|
||||
|
||||
# Synchronize stdout
|
||||
u1.sync_stdout()
|
||||
u2.sync_stdout()
|
||||
|
||||
# Set current account in both U1 and U2
|
||||
if acc1!="-1":
|
||||
if u1.use_telnet:
|
||||
u1.send("acc prev " + acc1)
|
||||
else:
|
||||
u1.send(">")
|
||||
u1.send(acc1)
|
||||
u1.expect("Current account changed")
|
||||
if acc2!="-1":
|
||||
if u2.use_telnet:
|
||||
u2.send("acc prev " + acc2)
|
||||
else:
|
||||
u2.send(">")
|
||||
u2.send(acc2)
|
||||
u2.expect("Current account changed")
|
||||
|
||||
# Synchronize stdout
|
||||
u1.sync_stdout()
|
||||
u2.sync_stdout()
|
||||
|
||||
# u2 toggles online status
|
||||
if u2.use_telnet:
|
||||
u2.send("im tog_state")
|
||||
else:
|
||||
u2.send("t")
|
||||
u1.expect(uri2 + ".*status.*Offline")
|
||||
u2.expect("offline")
|
||||
|
||||
# Synchronize stdout
|
||||
u1.sync_stdout()
|
||||
u2.sync_stdout()
|
||||
|
||||
# u1 toggles online status
|
||||
if u1.use_telnet:
|
||||
u1.send("im tog_state")
|
||||
else:
|
||||
u1.send("t")
|
||||
u2.expect(uri1 + ".*status.*Offline")
|
||||
u1.expect("offline")
|
||||
|
||||
# Synchronize stdout
|
||||
u1.sync_stdout()
|
||||
u2.sync_stdout()
|
||||
|
||||
# u2 set online status to On the phone
|
||||
if u2.use_telnet:
|
||||
u2.send("im pre_text 3")
|
||||
else:
|
||||
u2.send("T")
|
||||
u2.send("3")
|
||||
u1.expect(uri2 + ".*status.*On the phone")
|
||||
u2.expect("On the phone")
|
||||
|
||||
# Synchronize stdout
|
||||
u1.sync_stdout()
|
||||
u2.sync_stdout()
|
||||
|
||||
# Synchronize stdout
|
||||
u1.sync_stdout()
|
||||
u2.sync_stdout()
|
||||
|
||||
# U1 send IM
|
||||
if u1.use_telnet:
|
||||
im_text = "Hello-World-from-U1"
|
||||
u1.send("im send_im %s %s" % (uri2, im_text))
|
||||
else:
|
||||
im_text = "Hello World from U1"
|
||||
u1.send("i")
|
||||
u1.send(uri2)
|
||||
u2.expect(" is typing")
|
||||
u1.send(im_text)
|
||||
u1.expect(im_text+".*delivered successfully")
|
||||
u2.expect("MESSAGE from.*"+im_text)
|
||||
|
||||
# Synchronize stdout
|
||||
u1.sync_stdout()
|
||||
u2.sync_stdout()
|
||||
|
||||
|
||||
# Here where it all comes together
|
||||
test = cfg_file.test_param
|
||||
test.test_func = test_func
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
# $Id$
|
||||
import imp
|
||||
import sys
|
||||
import inc_sip as sip
|
||||
import inc_const as const
|
||||
import re
|
||||
from inc_cfg import *
|
||||
|
||||
# Read configuration
|
||||
cfg_file = imp.load_source("cfg_file", ARGS[1])
|
||||
|
||||
# Default server port (should we randomize?)
|
||||
srv_port = 50070
|
||||
|
||||
def test_func(test):
|
||||
pjsua = test.process[0]
|
||||
dlg = sip.Dialog("127.0.0.1", pjsua.inst_param.sip_port,
|
||||
local_port=srv_port,
|
||||
tcp=cfg_file.recvfrom_cfg.tcp)
|
||||
|
||||
last_cseq = 0
|
||||
last_method = ""
|
||||
last_call_id = ""
|
||||
for t in cfg_file.recvfrom_cfg.transaction:
|
||||
# Print transaction title
|
||||
if t.title != "":
|
||||
dlg.trace(t.title)
|
||||
# Run command and expect patterns
|
||||
for c in t.cmds:
|
||||
if c[0] and c[0] != "":
|
||||
pjsua.send(c[0])
|
||||
if len(c)>1 and c[1] and c[1] != "":
|
||||
pjsua.expect(c[1])
|
||||
# Wait for request
|
||||
if t.check_cseq:
|
||||
# Absorbs retransmissions
|
||||
cseq = 0
|
||||
method = last_method
|
||||
call_id = last_call_id
|
||||
while cseq <= last_cseq and method == last_method and call_id == last_call_id:
|
||||
request, src_addr = dlg.wait_msg_from(30)
|
||||
if request==None or request=="":
|
||||
raise TestError("Timeout waiting for request")
|
||||
method = request.split(" ", 1)[0]
|
||||
cseq_hval = sip.get_header(request, "CSeq")
|
||||
cseq_hval = cseq_hval.split(" ")[0]
|
||||
cseq = int(cseq_hval)
|
||||
call_id = sip.get_header(request, "Call-ID")
|
||||
last_cseq = cseq
|
||||
last_method = method
|
||||
else:
|
||||
request, src_addr = dlg.wait_msg_from(30)
|
||||
if request==None or request=="":
|
||||
raise TestError("Timeout waiting for request")
|
||||
|
||||
# Check for include patterns
|
||||
for pat in t.include:
|
||||
if re.search(pat, request, re.M | re.I)==None:
|
||||
if t.title:
|
||||
tname = " in " + t.title + " transaction"
|
||||
else:
|
||||
tname = ""
|
||||
raise TestError("Pattern " + pat + " not found" + tname)
|
||||
# Check for exclude patterns
|
||||
for pat in t.exclude:
|
||||
if re.search(pat, request, re.M | re.I)!=None:
|
||||
if t.title:
|
||||
tname = " in " + t.title + " transaction"
|
||||
else:
|
||||
tname = ""
|
||||
raise TestError("Excluded pattern " + pat + " found" + tname)
|
||||
# Create response
|
||||
if t.resp_code!=0:
|
||||
response = dlg.create_response(request, t.resp_code, "Status reason")
|
||||
# Add headers to response
|
||||
for h in t.resp_hdr:
|
||||
response = response + h + "\r\n"
|
||||
# Add message body if required
|
||||
if t.body:
|
||||
response = response + t.body
|
||||
# Send response
|
||||
dlg.send_msg(response, src_addr)
|
||||
|
||||
# Expect something to happen in pjsua
|
||||
if t.expect != "":
|
||||
pjsua.expect(t.expect)
|
||||
# Sync
|
||||
pjsua.sync_stdout()
|
||||
|
||||
# Replace "$PORT" with server port in pjsua args
|
||||
cfg_file.recvfrom_cfg.inst_param.arg = cfg_file.recvfrom_cfg.inst_param.arg.replace("$PORT", str(srv_port))
|
||||
|
||||
# Here where it all comes together
|
||||
test = TestParam(cfg_file.recvfrom_cfg.name,
|
||||
[cfg_file.recvfrom_cfg.inst_param],
|
||||
test_func)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
import imp
|
||||
import sys
|
||||
|
||||
from inc_cfg import *
|
||||
|
||||
# Read configuration
|
||||
cfg_file = imp.load_source("cfg_file", ARGS[1])
|
||||
|
||||
# Here where it all comes together
|
||||
test = cfg_file.test_param
|
||||
@@ -0,0 +1,53 @@
|
||||
# $Id$
|
||||
import imp
|
||||
import sys
|
||||
import inc_sip as sip
|
||||
import inc_const as const
|
||||
import re
|
||||
from inc_cfg import *
|
||||
|
||||
# Read configuration
|
||||
cfg_file = imp.load_source("cfg_file", ARGS[1])
|
||||
|
||||
# Test body function
|
||||
def test_func(t):
|
||||
pjsua = t.process[0]
|
||||
# Create dialog
|
||||
dlg = sip.Dialog("127.0.0.1", pjsua.inst_param.sip_port,
|
||||
tcp=cfg_file.sendto_cfg.use_tcp)
|
||||
#dlg = sip.Dialog("127.0.0.1", 5060, tcp=cfg_file.sendto_cfg.use_tcp)
|
||||
cfg = cfg_file.sendto_cfg
|
||||
|
||||
if len(cfg.complete_msg) != 0:
|
||||
req = dlg.update_fields(cfg.complete_msg)
|
||||
else:
|
||||
req = dlg.create_invite(cfg.sdp, cfg.extra_headers, cfg.body)
|
||||
resp = dlg.send_request_wait(req, 10)
|
||||
if resp=="":
|
||||
raise TestError("Timed-out waiting for response")
|
||||
# Check response code
|
||||
code = int(sip.get_code(resp))
|
||||
if code != cfg.resp_code:
|
||||
dlg.hangup(code)
|
||||
raise TestError("Expecting code " + str(cfg.resp_code) +
|
||||
" got " + str(code))
|
||||
# Check for patterns that must exist
|
||||
for p in cfg.resp_include:
|
||||
if re.search(p, resp, re.M | re.I)==None:
|
||||
dlg.hangup(code)
|
||||
raise TestError("Pattern " + p + " not found")
|
||||
# Check for patterns that must not exist
|
||||
for p in cfg.resp_exclude:
|
||||
if re.search(p, resp, re.M | re.I)!=None:
|
||||
dlg.hangup(code)
|
||||
raise TestError("Excluded pattern " + p + " found")
|
||||
pjsua.sync_stdout()
|
||||
dlg.hangup(code)
|
||||
pjsua.sync_stdout()
|
||||
|
||||
# Here where it all comes together
|
||||
test = TestParam(cfg_file.sendto_cfg.name,
|
||||
[cfg_file.sendto_cfg.inst_param],
|
||||
test_func)
|
||||
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
# $Id$
|
||||
|
||||
## Automatic test module for SIPp.
|
||||
##
|
||||
## This module will need a test driver for each SIPp scenario:
|
||||
## - For simple scenario, i.e: make/receive call (including auth), this
|
||||
## test module can auto-generate a default test driver, i.e: make call
|
||||
## or apply auto answer. Just name the SIPp scenario using "uas" or
|
||||
## "uac" prefix accordingly.
|
||||
## - Custom test driver can be defined in a python script file containing
|
||||
## a list of the PJSUA instances and another list for PJSUA expects/
|
||||
## commands. The custom test driver file must use the same filename as
|
||||
## the SIPp XML scenario. See samples of SIPp scenario + its driver
|
||||
## in tests/pjsua/scripts-sipp/ folder for detail.
|
||||
##
|
||||
## Here are defined macros that can be used in the custom driver:
|
||||
## - $SIPP_PORT : SIPp binding port
|
||||
## - $SIPP_URI : SIPp SIP URI
|
||||
## - $PJSUA_PORT[N] : binding port of PJSUA instance #N
|
||||
## - $PJSUA_URI[N] : SIP URI of PJSUA instance #N
|
||||
|
||||
import ctypes
|
||||
import time
|
||||
import imp
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
from inc_cfg import *
|
||||
import inc_const
|
||||
|
||||
# flags that test is running in Unix
|
||||
G_INUNIX = False
|
||||
if sys.platform.lower().find("win32")!=-1 or sys.platform.lower().find("microsoft")!=-1:
|
||||
G_INUNIX = False
|
||||
else:
|
||||
G_INUNIX = True
|
||||
|
||||
# /dev/null handle, for redirecting output when SIPP is not in background mode
|
||||
FDEVNULL = None
|
||||
|
||||
# SIPp executable path and param
|
||||
#SIPP_PATH = '"C:\\devs\\bin\\Sipp_3.2\\sipp.exe"'
|
||||
SIPP_PATH = 'sipp'
|
||||
SIPP_PORT = 50070
|
||||
SIPP_PARAM = "-m 1 -i 127.0.0.1 -p " + str(SIPP_PORT)
|
||||
SIPP_TIMEOUT = 60
|
||||
# On BG mode, SIPp doesn't require special terminal
|
||||
# On non-BG mode, on win, it needs env var: "TERMINFO=c:\cygwin\usr\share\terminfo"
|
||||
# TODO: on unix with BG mode, waitpid() always fails, need to be fixed
|
||||
SIPP_BG_MODE = False
|
||||
#SIPP_BG_MODE = not G_INUNIX
|
||||
|
||||
# Will be updated based on the test driver file (a .py file whose the same name as SIPp XML file)
|
||||
PJSUA_INST_PARAM = []
|
||||
PJSUA_EXPECTS = []
|
||||
|
||||
# Default PJSUA param if test driver is not available:
|
||||
# - no-tcp as SIPp is on UDP only
|
||||
# - id, username, and realm: to allow PJSUA sending re-INVITE with auth after receiving 401/407 response
|
||||
PJSUA_DEF_PARAM = "--null-audio --max-calls=1 --no-tcp --id=sip:a@localhost --username=a --realm=*"
|
||||
|
||||
# Get SIPp scenario (XML file)
|
||||
SIPP_SCEN_XML = ""
|
||||
if ARGS[1].endswith('.xml'):
|
||||
SIPP_SCEN_XML = ARGS[1]
|
||||
else:
|
||||
exit(-99)
|
||||
|
||||
|
||||
# Functions for resolving macros in the test driver
|
||||
def resolve_pjsua_port(mo):
|
||||
return str(PJSUA_INST_PARAM[int(mo.group(1))].sip_port)
|
||||
|
||||
def resolve_pjsua_uri(mo):
|
||||
return PJSUA_INST_PARAM[int(mo.group(1))].uri[1:-1]
|
||||
|
||||
def resolve_driver_macros(st):
|
||||
st = re.sub("\$SIPP_PORT", str(SIPP_PORT), st)
|
||||
st = re.sub("\$SIPP_URI", "sip:sipp@127.0.0.1:"+str(SIPP_PORT), st)
|
||||
st = re.sub("\$PJSUA_PORT\[(\d+)\]", resolve_pjsua_port, st)
|
||||
st = re.sub("\$PJSUA_URI\[(\d+)\]", resolve_pjsua_uri, st)
|
||||
return st
|
||||
|
||||
|
||||
# Init test driver
|
||||
if os.access(SIPP_SCEN_XML[:-4]+".py", os.R_OK):
|
||||
# Load test driver file (the corresponding .py file), if any
|
||||
cfg_file = imp.load_source("cfg_file", SIPP_SCEN_XML[:-4]+".py")
|
||||
for ua_idx, ua_param in enumerate(cfg_file.PJSUA):
|
||||
ua_param = resolve_driver_macros(ua_param)
|
||||
PJSUA_INST_PARAM.append(InstanceParam("pjsua"+str(ua_idx), ua_param))
|
||||
if DEFAULT_TELNET and hasattr(cfg_file, 'PJSUA_CLI_EXPECTS'):
|
||||
PJSUA_EXPECTS = cfg_file.PJSUA_CLI_EXPECTS
|
||||
else:
|
||||
PJSUA_EXPECTS = cfg_file.PJSUA_EXPECTS
|
||||
else:
|
||||
# Generate default test driver
|
||||
if os.path.basename(SIPP_SCEN_XML)[0:3] == "uas":
|
||||
# auto make call when SIPp is as UAS
|
||||
ua_param = PJSUA_DEF_PARAM + " sip:127.0.0.1:" + str(SIPP_PORT)
|
||||
else:
|
||||
# auto answer when SIPp is as UAC
|
||||
ua_param = PJSUA_DEF_PARAM + " --auto-answer=200"
|
||||
PJSUA_INST_PARAM.append(InstanceParam("pjsua", ua_param))
|
||||
|
||||
|
||||
# Start SIPp process, returning PID
|
||||
def start_sipp():
|
||||
global SIPP_BG_MODE
|
||||
sipp_proc = None
|
||||
|
||||
sipp_param = SIPP_PARAM + " -sf " + SIPP_SCEN_XML
|
||||
if SIPP_BG_MODE:
|
||||
sipp_param = sipp_param + " -bg"
|
||||
if SIPP_TIMEOUT:
|
||||
sipp_param = sipp_param + " -timeout "+str(SIPP_TIMEOUT)+"s -timeout_error" + " -deadcall_wait "+str(SIPP_TIMEOUT)+"s"
|
||||
|
||||
# add target param
|
||||
sipp_param = sipp_param + " 127.0.0.1:" + str(PJSUA_INST_PARAM[0].sip_port)
|
||||
|
||||
# run SIPp
|
||||
fullcmd = os.path.normpath(SIPP_PATH) + " " + sipp_param
|
||||
print "Running SIPP: " + fullcmd
|
||||
if SIPP_BG_MODE:
|
||||
sipp_proc = subprocess.Popen(fullcmd, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=G_INUNIX, universal_newlines=False)
|
||||
else:
|
||||
# redirect output to NULL
|
||||
global FDEVNULL
|
||||
#FDEVNULL = open(os.devnull, 'w')
|
||||
FDEVNULL = open("logs/sipp_output.tmp", 'w')
|
||||
sipp_proc = subprocess.Popen(fullcmd, shell=G_INUNIX, stdout=FDEVNULL, stderr=FDEVNULL)
|
||||
|
||||
if not SIPP_BG_MODE:
|
||||
if sipp_proc == None or sipp_proc.poll():
|
||||
return None
|
||||
return sipp_proc
|
||||
|
||||
else:
|
||||
# get SIPp child process PID
|
||||
pid = 0
|
||||
r = re.compile("PID=\[(\d+)\]", re.I)
|
||||
|
||||
while True:
|
||||
line = sipp_proc.stdout.readline()
|
||||
pid_r = r.search(line)
|
||||
if pid_r:
|
||||
pid = int(pid_r.group(1))
|
||||
break
|
||||
if not sipp_proc.poll():
|
||||
break
|
||||
|
||||
if pid != 0:
|
||||
# Win specific: get process handle from PID, as on win32, os.waitpid() takes process handle instead of pid
|
||||
if (sys.platform == "win32"):
|
||||
SYNCHRONIZE = 0x00100000
|
||||
PROCESS_QUERY_INFORMATION = 0x0400
|
||||
hnd = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, False, pid)
|
||||
pid = hnd
|
||||
|
||||
return pid
|
||||
|
||||
|
||||
# Wait SIPp process to exit, returning SIPp exit code
|
||||
def wait_sipp(sipp):
|
||||
if not SIPP_BG_MODE:
|
||||
global FDEVNULL
|
||||
sipp.wait()
|
||||
FDEVNULL.close()
|
||||
return sipp.returncode
|
||||
|
||||
else:
|
||||
print "Waiting SIPp (PID=" + str(sipp) + ") to exit.."
|
||||
wait_cnt = 0
|
||||
while True:
|
||||
try:
|
||||
wait_cnt = wait_cnt + 1
|
||||
[pid_, ret_code] = os.waitpid(sipp, 0)
|
||||
if sipp == pid_:
|
||||
#print "SIPP returned ", ret_code
|
||||
ret_code = ret_code >> 8
|
||||
|
||||
# Win specific: Close process handle
|
||||
if (sys.platform == "win32"):
|
||||
ctypes.windll.kernel32.CloseHandle(sipp)
|
||||
|
||||
return ret_code
|
||||
except os.error:
|
||||
if wait_cnt <= 5:
|
||||
print "Retry ("+str(wait_cnt)+") waiting SIPp.."
|
||||
else:
|
||||
return -99
|
||||
|
||||
|
||||
# Execute PJSUA flow
|
||||
def exec_pjsua_expects(t, sipp):
|
||||
# Get all PJSUA instances
|
||||
ua = []
|
||||
for ua_idx in range(len(PJSUA_INST_PARAM)):
|
||||
ua.append(t.process[ua_idx])
|
||||
|
||||
ua_err_st = ""
|
||||
while len(PJSUA_EXPECTS):
|
||||
expect = PJSUA_EXPECTS.pop(0)
|
||||
ua_idx = expect[0]
|
||||
expect_st = expect[1]
|
||||
send_cmd = resolve_driver_macros(expect[2])
|
||||
timeout = expect[3] if len(expect)>=4 else 0
|
||||
# Handle exception in pjsua flow, to avoid zombie SIPp process
|
||||
try:
|
||||
if expect_st != "":
|
||||
if timeout > 0:
|
||||
ua[ua_idx].expect(expect_st, raise_on_error = True, timeout = timeout)
|
||||
else:
|
||||
ua[ua_idx].expect(expect_st, raise_on_error = True)
|
||||
if send_cmd != "":
|
||||
ua[ua_idx].send(send_cmd)
|
||||
except TestError, e:
|
||||
ua_err_st = e.desc
|
||||
break;
|
||||
except:
|
||||
ua_err_st = "Unknown error"
|
||||
break;
|
||||
|
||||
# Need to poll here for handling these cases:
|
||||
# - If there is no PJSUA EXPECT scenario, we must keep polling the stdout,
|
||||
# otherwise PJSUA process may stuck (due to stdout pipe buffer full?).
|
||||
# - last PJSUA_EXPECT contains a pjsua command that needs time to
|
||||
# finish, for example "v" (re-INVITE), the SIPp XML scenario may expect
|
||||
# that re-INVITE transaction to be completed and without stdout poll
|
||||
# PJSUA process may stuck.
|
||||
# Ideally the poll should be done contiunously until SIPp process is
|
||||
# terminated.
|
||||
# Update: now pjsua stdout is polled continuously by a dedicated thread,
|
||||
# so the poll is no longer needed
|
||||
#for ua_idx in range(len(ua)):
|
||||
# ua[ua_idx].expect(inc_const.STDOUT_REFRESH, raise_on_error = False)
|
||||
|
||||
return ua_err_st
|
||||
|
||||
|
||||
def sipp_err_to_str(err_code):
|
||||
if err_code == 0:
|
||||
return "All calls were successful"
|
||||
elif err_code == 1:
|
||||
return "At least one call failed"
|
||||
elif err_code == 97:
|
||||
return "exit on internal command. Calls may have been processed"
|
||||
elif err_code == 99:
|
||||
return "Normal exit without calls processed"
|
||||
elif err_code == -1:
|
||||
return "Fatal error (timeout)"
|
||||
elif err_code == -2:
|
||||
return "Fatal error binding a socket"
|
||||
else:
|
||||
return "Unknown error"
|
||||
|
||||
|
||||
# Test body function
|
||||
def TEST_FUNC(t):
|
||||
|
||||
sipp_ret_code = 0
|
||||
ua_err_st = ""
|
||||
|
||||
sipp = start_sipp()
|
||||
if not sipp:
|
||||
raise TestError("Failed starting SIPp")
|
||||
|
||||
ua_err_st = exec_pjsua_expects(t, sipp)
|
||||
|
||||
sipp_ret_code = wait_sipp(sipp)
|
||||
|
||||
if ua_err_st != "":
|
||||
raise TestError(ua_err_st)
|
||||
|
||||
if sipp_ret_code:
|
||||
rc = ctypes.c_byte(sipp_ret_code).value
|
||||
raise TestError("SIPp returned error " + str(rc) + ": " + sipp_err_to_str(rc))
|
||||
|
||||
|
||||
# Here where it all comes together
|
||||
test = TestParam(SIPP_SCEN_XML[:-4],
|
||||
PJSUA_INST_PARAM,
|
||||
TEST_FUNC)
|
||||
@@ -0,0 +1,410 @@
|
||||
# $Id$
|
||||
import sys
|
||||
import imp
|
||||
import re
|
||||
import os
|
||||
import subprocess
|
||||
import random
|
||||
import telnetlib
|
||||
import time
|
||||
import threading
|
||||
import traceback
|
||||
import getopt
|
||||
|
||||
import inc_cfg as inc
|
||||
import inc_const as const
|
||||
|
||||
# Vars
|
||||
G_EXE = "" # pjsua executable path
|
||||
G_INUNIX = False # flags that test is running in Unix
|
||||
|
||||
|
||||
# Usage string
|
||||
usage = \
|
||||
"""
|
||||
run.py - Automated test driver
|
||||
|
||||
Usage:
|
||||
run.py [options] MODULE CONFIG
|
||||
Options:
|
||||
--exe, -e pjsua executable path
|
||||
--null-audio, -n use null audio
|
||||
Sample:
|
||||
run.py -n mod_run.py scripts-run/100_simple.py
|
||||
"""
|
||||
|
||||
# Parse arguments
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "hne:", ["help", "null-audio", "exe="])
|
||||
except getopt.GetoptError, err:
|
||||
print str(err)
|
||||
print usage
|
||||
sys.exit(2)
|
||||
for o, a in opts:
|
||||
if o in ("-h", "--help"):
|
||||
print usage
|
||||
sys.exit()
|
||||
elif o in ("-n", "--null-audio"):
|
||||
inc.HAS_SND_DEV = 0
|
||||
elif o in ("-e", "--exe"):
|
||||
G_EXE = a
|
||||
else:
|
||||
print "Unknown options"
|
||||
sys.exit(2)
|
||||
|
||||
if len(args) != 2:
|
||||
print "Invalid arguments"
|
||||
print usage
|
||||
sys.exit(2)
|
||||
|
||||
# Set global ARGS to be used by modules
|
||||
inc.ARGS = args
|
||||
|
||||
# Get the pjsua executable name
|
||||
if G_EXE == "":
|
||||
if sys.platform.find("win32")!=-1:
|
||||
EXE_DIR = "../../pjsip-apps/bin/"
|
||||
EXECUTABLES = [ "pjsua_vc6d.exe",
|
||||
"pjsua_vc6.exe",
|
||||
"pjsua-i386-Win32-vc8-Debug.exe",
|
||||
"pjsua-i386-Win32-vc8-Debug-Dynamic.exe",
|
||||
"pjsua-i386-Win32-vc8-Debug-Static.exe",
|
||||
"pjsua-i386-Win32-vc8-Release.exe",
|
||||
"pjsua-i386-Win32-vc8-Release-Dynamic.exe",
|
||||
"pjsua-i386-Win32-vc8-Release-Static.exe"
|
||||
]
|
||||
e_ts = 0
|
||||
for e in EXECUTABLES:
|
||||
e = EXE_DIR + e
|
||||
if os.access(e, os.F_OK):
|
||||
st = os.stat(e)
|
||||
if e_ts==0 or e_ts<st.st_mtime:
|
||||
G_EXE = e
|
||||
e_ts = st.st_mtime
|
||||
|
||||
if G_EXE=="":
|
||||
print "Unable to find valid pjsua. Please build pjsip first"
|
||||
sys.exit(1)
|
||||
|
||||
G_INUNIX = False
|
||||
else:
|
||||
f = open("../../build.mak", "r")
|
||||
while True:
|
||||
line = f.readline()
|
||||
if not line:
|
||||
break
|
||||
if line.find("TARGET_NAME")!=-1:
|
||||
print line
|
||||
G_EXE="../../pjsip-apps/bin/pjsua-" + line.split(":= ")[1]
|
||||
break
|
||||
if G_EXE=="":
|
||||
print "Unable to find ../../../build.mak. Please build pjsip first"
|
||||
sys.exit(1)
|
||||
G_INUNIX = True
|
||||
else:
|
||||
if sys.platform.lower().find("win32")!=-1 or sys.platform.lower().find("microsoft")!=-1:
|
||||
G_INUNIX = False
|
||||
else:
|
||||
G_INUNIX = True
|
||||
|
||||
|
||||
G_EXE = G_EXE.rstrip("\n\r \t")
|
||||
|
||||
###################################
|
||||
# Poor man's 'expect'-like class
|
||||
class Expect(threading.Thread):
|
||||
proc = None
|
||||
telnet = None
|
||||
use_telnet = False
|
||||
echo = False
|
||||
trace_enabled = False
|
||||
inst_param = None
|
||||
rh = re.compile(const.DESTROYED)
|
||||
ra = re.compile(const.ASSERT, re.I)
|
||||
rr = re.compile(const.STDOUT_REFRESH)
|
||||
t0 = time.time()
|
||||
output = ""
|
||||
lock = threading.Lock()
|
||||
running = False
|
||||
def __init__(self, inst_param):
|
||||
threading.Thread.__init__(self)
|
||||
self.inst_param = inst_param
|
||||
self.name = inst_param.name
|
||||
self.echo = inst_param.echo_enabled
|
||||
self.trace_enabled = inst_param.trace_enabled
|
||||
self.use_telnet = inst_param.telnet_enabled
|
||||
self.telnet = None
|
||||
|
||||
def run(self):
|
||||
if self.use_telnet:
|
||||
fullcmd = G_EXE + " " + inst_param.arg + " --use-cli --no-cli-console --cli-telnet-port=%d" % (inst_param.telnet_port)
|
||||
self.trace("Popen " + fullcmd)
|
||||
self.proc = subprocess.Popen(fullcmd, shell=G_INUNIX)
|
||||
|
||||
# start telnet-ing to pjsua, raise exception if telnet fails after 5s
|
||||
t0 = time.time()
|
||||
while self.proc.poll() is None and self.telnet is None:
|
||||
try:
|
||||
time.sleep(0.01)
|
||||
self.telnet = telnetlib.Telnet('127.0.0.1', port=self.inst_param.telnet_port, timeout=60)
|
||||
except Exception as e:
|
||||
t1 = time.time()
|
||||
dur = int(t1 - t0)
|
||||
if dur > 5:
|
||||
raise inc.TestError(self.name + ": Timeout connecting to pjsua: " + repr(e))
|
||||
|
||||
self.running = True
|
||||
while self.proc.poll() is None:
|
||||
line = self.telnet.read_until('\n', 60)
|
||||
if line == "" or const.DESTROYED in line:
|
||||
break;
|
||||
|
||||
#Print the line if echo is ON
|
||||
if self.echo:
|
||||
print self.name + ": " + line.rstrip()
|
||||
|
||||
self.lock.acquire()
|
||||
self.output += line
|
||||
self.lock.release()
|
||||
self.running = False
|
||||
else:
|
||||
fullcmd = G_EXE + " " + inst_param.arg + " --stdout-refresh=5 --stdout-refresh-text=" + const.STDOUT_REFRESH
|
||||
if not inst_param.enable_buffer:
|
||||
fullcmd = fullcmd + " --stdout-no-buf"
|
||||
self.trace("Popen " + fullcmd)
|
||||
self.proc = subprocess.Popen(fullcmd, shell=G_INUNIX, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=False)
|
||||
self.running = True
|
||||
while self.proc.poll() is None:
|
||||
line = self.proc.stdout.readline()
|
||||
if line == "":
|
||||
break;
|
||||
|
||||
#Print the line if echo is ON
|
||||
if self.echo:
|
||||
print self.name + ": " + line.rstrip()
|
||||
|
||||
self.lock.acquire()
|
||||
self.output += line
|
||||
self.lock.release()
|
||||
self.running = False
|
||||
|
||||
def send(self, cmd):
|
||||
self.trace("send " + cmd)
|
||||
if self.use_telnet:
|
||||
self.telnet.write(cmd + '\r\n')
|
||||
else:
|
||||
self.proc.stdin.writelines(cmd + "\n")
|
||||
self.proc.stdin.flush()
|
||||
|
||||
def expect(self, pattern, raise_on_error=True, title="", timeout=15):
|
||||
# no prompt for telnet
|
||||
if self.use_telnet and pattern==const.PROMPT:
|
||||
return
|
||||
|
||||
self.trace("expect " + pattern)
|
||||
r = re.compile(pattern, re.I)
|
||||
found_at = -1
|
||||
t0 = time.time()
|
||||
while found_at < 0:
|
||||
self.lock.acquire()
|
||||
lines = self.output.splitlines()
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
# Search for expected text
|
||||
if r.search(line) != None:
|
||||
found_at = i
|
||||
break
|
||||
|
||||
# Trap assertion error
|
||||
if raise_on_error:
|
||||
if self.ra.search(line) != None:
|
||||
self.lock.release()
|
||||
raise inc.TestError(self.name + ": " + line)
|
||||
|
||||
self.output = '\n'.join(lines[found_at+1:])+"\n" if found_at >= 0 else ""
|
||||
self.lock.release()
|
||||
|
||||
if found_at >= 0:
|
||||
return line
|
||||
|
||||
if not self.running:
|
||||
if raise_on_error:
|
||||
raise inc.TestError(self.name + ": Premature EOF")
|
||||
break
|
||||
else:
|
||||
t1 = time.time()
|
||||
dur = int(t1 - t0)
|
||||
if dur > timeout:
|
||||
self.trace("Timed-out!")
|
||||
if raise_on_error:
|
||||
raise inc.TestError(self.name + " " + title + ": Timeout expecting pattern: \"" + pattern + "\"")
|
||||
break
|
||||
else:
|
||||
time.sleep(0.01)
|
||||
return None
|
||||
|
||||
|
||||
def sync_stdout(self):
|
||||
if not self.use_telnet:
|
||||
self.trace("sync_stdout")
|
||||
cmd = "echo 1" + str(random.randint(1000,9999))
|
||||
self.send(cmd)
|
||||
self.expect(cmd)
|
||||
|
||||
def wait(self):
|
||||
self.trace("wait")
|
||||
self.join()
|
||||
self.proc.communicate()
|
||||
if self.telnet:
|
||||
self.telnet.close()
|
||||
|
||||
def trace(self, s):
|
||||
if self.trace_enabled:
|
||||
now = time.time()
|
||||
fmt = self.name + ": " + "================== " + s + " ==================" + " [at t=%(time)03d]"
|
||||
print fmt % {'time':int(now - self.t0)}
|
||||
|
||||
#########################
|
||||
# Error handling
|
||||
def handle_error(errmsg, t, close_processes = True):
|
||||
print "====== Caught error: " + errmsg + " ======"
|
||||
if (close_processes):
|
||||
time.sleep(1)
|
||||
for p in t.process:
|
||||
# Protect against 'Broken pipe' exception
|
||||
try:
|
||||
if not p.use_telnet:
|
||||
p.send("q")
|
||||
p.send("q")
|
||||
else:
|
||||
p.send("shutdown")
|
||||
except:
|
||||
pass
|
||||
is_err = False
|
||||
try:
|
||||
ret = p.expect(const.DESTROYED, False)
|
||||
if ret is None:
|
||||
is_err = True
|
||||
except:
|
||||
is_err = True
|
||||
if is_err and p.proc.poll() is None:
|
||||
if sys.hexversion >= 0x02060000:
|
||||
p.proc.terminate()
|
||||
else:
|
||||
p.wait()
|
||||
else:
|
||||
p.wait()
|
||||
|
||||
print "Test completed with error: " + errmsg
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
#########################
|
||||
# MAIN
|
||||
|
||||
# Import the test script
|
||||
script = imp.load_source("script", inc.ARGS[0])
|
||||
|
||||
# Init random seed
|
||||
random.seed()
|
||||
|
||||
# Validate
|
||||
if script.test == None:
|
||||
print "Error: no test defined"
|
||||
sys.exit(1)
|
||||
|
||||
if script.test.skip:
|
||||
print "Test " + script.test.title + " is skipped"
|
||||
sys.exit(0)
|
||||
|
||||
if len(script.test.inst_params) == 0:
|
||||
print "Error: test doesn't contain pjsua run descriptions"
|
||||
sys.exit(1)
|
||||
|
||||
# Instantiate pjsuas
|
||||
print "====== Running " + script.test.title + " ======"
|
||||
print "Using " + G_EXE + " as pjsua executable"
|
||||
|
||||
for inst_param in script.test.inst_params:
|
||||
try:
|
||||
# Create pjsua's Expect instance from the param
|
||||
p = Expect(inst_param)
|
||||
p.start()
|
||||
except inc.TestError, e:
|
||||
handle_error(e.desc, script.test)
|
||||
|
||||
# wait process ready
|
||||
if not p.use_telnet:
|
||||
while True:
|
||||
try:
|
||||
p.send("echo 1")
|
||||
except:
|
||||
time.sleep(0.1)
|
||||
continue
|
||||
break
|
||||
else:
|
||||
t0 = time.time()
|
||||
while p.telnet is None:
|
||||
time.sleep(0.1)
|
||||
dur = int(time.time() - t0)
|
||||
if dur > 5:
|
||||
handle_error("Timeout connecting to pjsua", script.test)
|
||||
|
||||
# add running instance
|
||||
script.test.process.append(p)
|
||||
|
||||
for p in script.test.process:
|
||||
try:
|
||||
# Wait until registration completes
|
||||
if p.inst_param.have_reg:
|
||||
p.send("rr")
|
||||
p.expect(p.inst_param.uri+".*registration success")
|
||||
# Synchronize stdout
|
||||
if not p.use_telnet:
|
||||
p.send("")
|
||||
p.expect(const.PROMPT)
|
||||
p.send("echo 1")
|
||||
p.expect("echo 1")
|
||||
|
||||
except inc.TestError, e:
|
||||
handle_error(e.desc, script.test)
|
||||
|
||||
# Run the test function
|
||||
if script.test.test_func != None:
|
||||
try:
|
||||
script.test.test_func(script.test)
|
||||
except inc.TestError, e:
|
||||
handle_error(e.desc, script.test)
|
||||
except:
|
||||
handle_error("Unknown error: " + str(traceback.format_exc()), script.test)
|
||||
|
||||
# Shutdown all instances
|
||||
for p in script.test.process:
|
||||
# Unregister if we have_reg to make sure that next tests
|
||||
# won't fail
|
||||
if p.inst_param.have_reg:
|
||||
p.send("ru")
|
||||
p.expect(p.inst_param.uri+".*unregistration success")
|
||||
|
||||
if p.use_telnet:
|
||||
p.send("shutdown")
|
||||
else:
|
||||
p.send("q")
|
||||
|
||||
time.sleep(0.5)
|
||||
for p in script.test.process:
|
||||
if p.running:
|
||||
p.expect(const.DESTROYED, False)
|
||||
p.wait()
|
||||
|
||||
# Run the post test function
|
||||
if script.test.post_func != None:
|
||||
try:
|
||||
script.test.post_func(script.test)
|
||||
except inc.TestError, e:
|
||||
handle_error(e.desc, script.test, False)
|
||||
|
||||
# Done
|
||||
print "Test " + script.test.title + " completed successfully"
|
||||
sys.exit(0)
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
# $Id$
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import re
|
||||
import shutil
|
||||
|
||||
PYTHON = os.path.basename(sys.executable)
|
||||
|
||||
# Usage:
|
||||
# runall.py [test-to-resume]
|
||||
|
||||
|
||||
# Initialize test list
|
||||
tests = []
|
||||
|
||||
# Excluded tests (because they fail?)
|
||||
excluded_tests = [
|
||||
"svn",
|
||||
"pyc",
|
||||
"scripts-call/150_srtp_2_1", # SRTP optional 'cannot' call SRTP mandatory
|
||||
"scripts-call/150_srtp_2_3.py", # disabled because #1267 wontfix
|
||||
"scripts-call/301_ice_public_a.py", # Unreliable, proxy returns 408 sometimes
|
||||
"scripts-call/301_ice_public_b.py", # Doesn't work because OpenSER modifies SDP
|
||||
"scripts-pres/200_publish.py", # Ok from cmdline, error from runall.py
|
||||
"scripts-media-playrec/100_resample_lf_8_11.py", # related to clock-rate 11 kHz problem
|
||||
"scripts-media-playrec/100_resample_lf_8_22.py", # related to clock-rate 22 kHz problem
|
||||
"scripts-media-playrec/100_resample_lf_11", # related to clock-rate 11 kHz problem
|
||||
"pesq", # temporarily disabling all pesq related test due to unreliability
|
||||
# TODO check all tests below for false negatives
|
||||
"pjmedia-test",
|
||||
"pjsip-test",
|
||||
"call_305_ice_comp_1_2",
|
||||
"scripts-sendto/155_err_sdp_bad_syntax",
|
||||
"transfer-attended",
|
||||
"uac-inv-and-ack-without-sdp",
|
||||
"uac-subscribe",
|
||||
"uac-ticket-1148",
|
||||
"uas-422-then-200-bad-se",
|
||||
"uas-answer-180-multiple-fmts-support-update",
|
||||
"uas-inv-answered-with-srtp",
|
||||
"uas-mwi-0",
|
||||
"uas-mwi",
|
||||
"uas-register-ip-change-port-only",
|
||||
"uas-register-ip-change",
|
||||
"uas-timer-update"
|
||||
]
|
||||
|
||||
# Add basic tests
|
||||
for f in os.listdir("scripts-run"):
|
||||
tests.append("mod_run.py scripts-run/" + f)
|
||||
|
||||
# Add basic call tests
|
||||
for f in os.listdir("scripts-call"):
|
||||
tests.append("mod_call.py scripts-call/" + f)
|
||||
|
||||
# Add presence tests
|
||||
for f in os.listdir("scripts-pres"):
|
||||
tests.append("mod_pres.py scripts-pres/" + f)
|
||||
|
||||
# Add mod_sendto tests
|
||||
for f in os.listdir("scripts-sendto"):
|
||||
tests.append("mod_sendto.py scripts-sendto/" + f)
|
||||
|
||||
# Add mod_media_playrec tests
|
||||
for f in os.listdir("scripts-media-playrec"):
|
||||
tests.append("mod_media_playrec.py scripts-media-playrec/" + f)
|
||||
|
||||
# Add mod_pesq tests
|
||||
for f in os.listdir("scripts-pesq"):
|
||||
tests.append("mod_pesq.py scripts-pesq/" + f)
|
||||
|
||||
# Add recvfrom tests
|
||||
for f in os.listdir("scripts-recvfrom"):
|
||||
tests.append("mod_recvfrom.py scripts-recvfrom/" + f)
|
||||
|
||||
# Add sipp tests
|
||||
for f in os.listdir("scripts-sipp"):
|
||||
if f.endswith(".xml"):
|
||||
tests.append("mod_sipp.py scripts-sipp/" + f)
|
||||
|
||||
|
||||
resume_script=""
|
||||
shell_cmd=""
|
||||
with_log=True
|
||||
|
||||
# Parse arguments
|
||||
sys.argv.pop(0)
|
||||
while len(sys.argv):
|
||||
if sys.argv[0]=='/h' or sys.argv[0]=='-h' or sys.argv[0]=='--help' or sys.argv[0]=='/help':
|
||||
sys.argv.pop(0)
|
||||
print "Usage:"
|
||||
print " runall.py [OPTIONS] [run.py-OPTIONS]"
|
||||
print "OPTIONS:"
|
||||
print " --list"
|
||||
print " List the tests"
|
||||
print " --list-xml"
|
||||
print " List the tests as XML format suitable for ccdash"
|
||||
print " --resume,-r RESUME"
|
||||
print " RESUME is string/substring to specify where to resume tests."
|
||||
print " If this argument is omited, tests will start from the beginning."
|
||||
print " --disable,-d TEST_NAME"
|
||||
print " Disable a specific test that contains the specified TEST_NAME."
|
||||
print " --shell,-s SHELL"
|
||||
print " Run the tests with the specified SHELL cmd. This can also be"
|
||||
print " used to run the test with ccdash. Example:"
|
||||
print " --shell '/bin/sh -c'"
|
||||
print " --no-log"
|
||||
print " Do not generate log files. By default log files will be generated"
|
||||
print " and put in 'logs' dir."
|
||||
print ""
|
||||
print " run.py-OPTIONS are applicable here"
|
||||
sys.exit(0)
|
||||
elif sys.argv[0] == '-r' or sys.argv[0] == '--resume':
|
||||
if len(sys.argv) > 1:
|
||||
resume_script=sys.argv[1]
|
||||
sys.argv.pop(0)
|
||||
sys.argv.pop(0)
|
||||
else:
|
||||
sys.argv.pop(0)
|
||||
sys.stderr.write("Error: argument value required")
|
||||
sys.exit(1)
|
||||
elif sys.argv[0] == '--list':
|
||||
sys.argv.pop(0)
|
||||
for t in tests:
|
||||
print t
|
||||
sys.exit(0)
|
||||
elif sys.argv[0] == '--list-xml':
|
||||
sys.argv.pop(0)
|
||||
for t in tests:
|
||||
(mod,param) = t.split(None,2)
|
||||
tname = mod[4:mod.find(".py")] + "_" + \
|
||||
param[param.find("/")+1:param.rfind(".")]
|
||||
c = ""
|
||||
if len(sys.argv):
|
||||
c = " ".join(sys.argv) + " "
|
||||
tcmd = PYTHON + ' run.py ' + c + t
|
||||
print '\t\t<Test name="%s" cmd="%s" wdir="tests/pjsua" />' % (tname, tcmd)
|
||||
sys.exit(0)
|
||||
elif sys.argv[0] == '-s' or sys.argv[0] == '--shell':
|
||||
if len(sys.argv) > 1:
|
||||
shell_cmd = sys.argv[1]
|
||||
sys.argv.pop(0)
|
||||
sys.argv.pop(0)
|
||||
else:
|
||||
sys.argv.pop(0)
|
||||
sys.stderr.write("Error: argument value required")
|
||||
sys.exit(1)
|
||||
elif sys.argv[0] == '-d' or sys.argv[0] == '--disable':
|
||||
if len(sys.argv) > 1:
|
||||
excluded_tests.append(sys.argv[1])
|
||||
sys.argv.pop(0)
|
||||
sys.argv.pop(0)
|
||||
else:
|
||||
sys.argv.pop(0)
|
||||
sys.stderr.write("Error: argument value required")
|
||||
sys.exit(1)
|
||||
elif sys.argv[0] == '--no-log':
|
||||
sys.argv.pop(0)
|
||||
with_log=False
|
||||
else:
|
||||
# should be run.py options
|
||||
break
|
||||
|
||||
|
||||
# Generate arguments for run.py
|
||||
argv_st = " ".join(sys.argv) + " "
|
||||
|
||||
# Init vars
|
||||
fails_cnt = 0
|
||||
tests_cnt = 0
|
||||
|
||||
# Filter-out excluded tests
|
||||
for pat in excluded_tests:
|
||||
tests = [t for t in tests if t.find(pat)==-1]
|
||||
|
||||
# Now run the tests
|
||||
total_cnt = len(tests)
|
||||
for t in tests:
|
||||
if resume_script!="" and t.find(resume_script)==-1:
|
||||
print "Skipping " + t +".."
|
||||
total_cnt = total_cnt - 1
|
||||
continue
|
||||
resume_script=""
|
||||
cmdline = "python run.py " + argv_st + t
|
||||
if shell_cmd:
|
||||
cmdline = "%s '%s'" % (shell_cmd, cmdline)
|
||||
t0 = time.time()
|
||||
msg = "Running %3d/%d: %s..." % (tests_cnt+1, total_cnt, cmdline)
|
||||
sys.stdout.write(msg)
|
||||
sys.stdout.flush()
|
||||
if with_log:
|
||||
logname = re.search(".*\s+(.*)", t).group(1)
|
||||
logname = re.sub("[\\\/]", "_", logname)
|
||||
logname = re.sub("\.py$", ".log", logname)
|
||||
logname = re.sub("\.xml$", ".log", logname)
|
||||
logname = "logs/" + logname
|
||||
else:
|
||||
logname = os.devnull
|
||||
ret = os.system(cmdline + " > " + logname)
|
||||
t1 = time.time()
|
||||
if ret != 0:
|
||||
dur = int(t1 - t0)
|
||||
print " failed!! [" + str(dur) + "s]"
|
||||
if with_log:
|
||||
lines = open(logname, "r").readlines()
|
||||
print ''.join(lines)
|
||||
print "Log file: '" + logname + "'."
|
||||
fails_cnt += 1
|
||||
else:
|
||||
dur = int(t1 - t0)
|
||||
print " ok [" + str(dur) + "s]"
|
||||
tests_cnt += 1
|
||||
|
||||
if fails_cnt == 0:
|
||||
print "All " + str(tests_cnt) + " tests completed successfully"
|
||||
else:
|
||||
print str(tests_cnt) + " tests completed, " + str(fails_cnt) + " test(s) failed"
|
||||
|
||||
sys.exit(fails_cnt)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Simple call
|
||||
test_param = TestParam(
|
||||
"Basic call",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param= TestParam(
|
||||
"Callee=no SRTP, caller=optional SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param = TestParam(
|
||||
"Callee=no SRTP, caller=optional (with duplicated offer) SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=0 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param = TestParam(
|
||||
"Callee=optional SRTP, caller=no SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param = TestParam(
|
||||
"Callee=optional SRTP, caller=optional SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param = TestParam(
|
||||
"Callee=optional SRTP, caller=mandatory SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param = TestParam(
|
||||
"Callee=optional SRTP, caller=optional (with duplicated offer) SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Simple call
|
||||
test_param = TestParam(
|
||||
"Callee=mandatory SRTP, caller=optional SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param = TestParam(
|
||||
"Callee=mandatory SRTP, caller=mandatory SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param = TestParam(
|
||||
"Callee=mandatory SRTP, caller=optional (with duplicated offer) SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param = TestParam(
|
||||
"Callee=optional (with duplicated offer) SRTP, caller=no SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=0 --srtp-secure=0 --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param = TestParam(
|
||||
"Callee=optional (with duplicated offer) SRTP, caller=optional SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param = TestParam(
|
||||
"Callee=optional (with duplicated offer) SRTP, caller=mandatory SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param = TestParam(
|
||||
"Callee=optional (with duplicated offer) SRTP, caller=optional (with duplicated offer) SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
test_param = TestParam(
|
||||
"Callee=mandatory SRTP, caller=mandatory SRTP with DTLS keying",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1 --srtp-keying=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# TCP call
|
||||
test_param = TestParam(
|
||||
"TCP transport",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --no-udp --max-calls=1", uri_param=";transport=tcp"),
|
||||
InstanceParam("caller", "--null-audio --no-udp --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# ICE mismatch
|
||||
test_param = TestParam(
|
||||
"Callee=no ICE, caller=use ICE",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-ice --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# ICE mismatch
|
||||
test_param = TestParam(
|
||||
"Callee=use ICE, caller=no ICE",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-ice --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# ICE mismatch
|
||||
test_param = TestParam(
|
||||
"Callee=use ICE, caller=use ICE",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-ice --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-ice --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Note:
|
||||
# - need --dis-codec to make INVITE packet less than typical MTU
|
||||
uas_args = "--null-audio --id=\"<sip:test1@pjsip.org>\" --registrar=sip:sip.pjsip.org --username=test1 --password=test1 --realm=pjsip.org --proxy=\"sip:sip.pjsip.org;lr\" --rtp-port 0 --stun-srv stun.pjsip.org --use-ice --use-compact-form --max-calls 1 --dis-codec=i --dis-codec=s --dis-codec=g"
|
||||
|
||||
uac_args = "--null-audio --id=\"<sip:test2@pjsip.org>\" --registrar=sip:sip.pjsip.org --username=test2 --password=test2 --realm=pjsip.org --proxy=\"sip:sip.pjsip.org;lr\" --rtp-port 0 --stun-srv stun.pjsip.org --use-ice --use-compact-form --max-calls 1 --dis-codec=i --dis-codec=s --dis-codec=g"
|
||||
|
||||
test_param = TestParam(
|
||||
"ICE via public internet",
|
||||
[
|
||||
InstanceParam( "callee", uas_args,
|
||||
uri="<sip:test1@pjsip.org>",
|
||||
have_reg=True, have_publish=False),
|
||||
InstanceParam( "caller", uac_args,
|
||||
uri="<sip:test2@pjsip.org>",
|
||||
have_reg=True, have_publish=False),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# This test:
|
||||
# to make call with ICE but without STUN.
|
||||
|
||||
# Note:
|
||||
# - need --dis-codec to make INVITE packet less than typical MTU
|
||||
uas_args = "--null-audio --id=\"<sip:test1@pjsip.org>\" --registrar=sip:sip.pjsip.org --username=test1 --password=test1 --realm=pjsip.org --proxy=\"sip:sip.pjsip.org;lr\" --rtp-port 0 --use-ice --use-compact-form --max-calls 1 --dis-codec=i --dis-codec=s --dis-codec=g --log-file callee.log"
|
||||
|
||||
uac_args = "--null-audio --id=\"<sip:test2@pjsip.org>\" --registrar=sip:sip.pjsip.org --username=test2 --password=test2 --realm=pjsip.org --proxy=\"sip:sip.pjsip.org;lr\" --rtp-port 0 --use-ice --use-compact-form --max-calls 1 --dis-codec=i --dis-codec=s --dis-codec=g --log-file caller.log"
|
||||
|
||||
test_param = TestParam(
|
||||
"ICE via public internet with no STUN",
|
||||
[
|
||||
InstanceParam( "callee", uas_args,
|
||||
uri="<sip:test1@pjsip.org>",
|
||||
have_reg=True, have_publish=False),
|
||||
InstanceParam( "caller", uac_args,
|
||||
uri="<sip:test2@pjsip.org>",
|
||||
have_reg=True, have_publish=False),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Different number of ICE components
|
||||
test_param = TestParam(
|
||||
"Callee=use ICE, caller=use ICE",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-ice --max-calls=1 --ice-no-rtcp"),
|
||||
InstanceParam("caller", "--null-audio --use-ice --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Different number of ICE components
|
||||
test_param = TestParam(
|
||||
"Callee=use ICE, caller=use ICE",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-ice --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --use-ice --max-calls=1 --ice-no-rtcp")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# ICE mismatch
|
||||
test_param = TestParam(
|
||||
"Callee=use ICE & SRTP, caller=use ICE & DTLS-SRTP",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --use-ice --max-calls=1 --use-srtp=2 --srtp-secure=0"),
|
||||
InstanceParam("caller", "--null-audio --use-ice --max-calls=1 --use-srtp=2 --srtp-secure=0 --srtp-keying=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# No ICE vs trickle ICE full, should be okay (as ICE will be disabled)
|
||||
test_param = TestParam(
|
||||
"Callee=Trickle ICE (full), caller=no ICE",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1 --use-ice --ice-trickle=2 --stun-srv stun.pjsip.org"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Regular ICE vs trickle ICE full, should be okay (as trickle will be disabled)
|
||||
test_param = TestParam(
|
||||
"Callee=Trickle ICE (full), caller=Regular ICE",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1 --use-ice --ice-trickle=2 --stun-srv stun.pjsip.org"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1 --use-ice --ice-trickle=0 --stun-srv stun.pjsip.org")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Trickle ICE full vs full
|
||||
test_param = TestParam(
|
||||
"Callee=Trickle ICE (full), caller=Trickle ICE (full)",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1 --use-ice --ice-trickle=2 --stun-srv stun.pjsip.org"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1 --use-ice --ice-trickle=2 --stun-srv stun.pjsip.org")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Trickle ICE full vs no ICE, should be okay (as there are host candidates)
|
||||
test_param = TestParam(
|
||||
"Callee=no ICE, caller=Trickle ICE (full)",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1 --use-ice --ice-trickle=2 --stun-srv stun.pjsip.org")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Trickle ICE full vs regular, should be okay (as there are host candidates)
|
||||
test_param = TestParam(
|
||||
"Callee=Regular ICE, caller=Trickle ICE (full)",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1 --use-ice --ice-trickle=0 --stun-srv stun.pjsip.org"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1 --use-ice --ice-trickle=2 --stun-srv stun.pjsip.org")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Trickle ICE half vs half
|
||||
test_param = TestParam(
|
||||
"Callee=Trickle ICE (half), caller=Trickle ICE (half)",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1 --use-ice --ice-trickle=1 --stun-srv stun.pjsip.org"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1 --use-ice --ice-trickle=1 --stun-srv stun.pjsip.org")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Trickle ICE half vs regular, should be okay (just like regular vs regular)
|
||||
test_param = TestParam(
|
||||
"Callee=Regular ICE, caller=Trickle ICE (half)",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1 --use-ice --ice-trickle=0 --stun-srv stun.pjsip.org"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1 --use-ice --ice-trickle=1 --stun-srv stun.pjsip.org")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# TCP call
|
||||
test_param = TestParam(
|
||||
"Callee requires PRACK",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1 --use-100rel"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# TCP call
|
||||
test_param = TestParam(
|
||||
"Caller requires PRACK",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1 --use-100rel")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Simple call
|
||||
test_param = TestParam(
|
||||
"tel: URI in From",
|
||||
[
|
||||
InstanceParam("callee", "--null-audio --max-calls=1 --id tel:+111"),
|
||||
InstanceParam("caller", "--null-audio --max-calls=1")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# simple test
|
||||
test_param = TestParam(
|
||||
"Resample (large filter) 11 KHZ to 16 KHZ",
|
||||
[
|
||||
InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 16000 --play-file wavs/input.11.wav --rec-file wavs/tmp.16.wav")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# simple test
|
||||
test_param = TestParam(
|
||||
"Resample (large filter) 11 KHZ to 22 KHZ",
|
||||
[
|
||||
InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 22050 --play-file wavs/input.11.wav --rec-file wavs/tmp.22.wav")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# simple test
|
||||
test_param = TestParam(
|
||||
"Resample (large filter) 11 KHZ to 32 KHZ",
|
||||
[
|
||||
InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 32000 --play-file wavs/input.11.wav --rec-file wavs/tmp.32.wav")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# simple test
|
||||
test_param = TestParam(
|
||||
"Resample (large filter) 11 KHZ to 44 KHZ",
|
||||
[
|
||||
InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 44100 --play-file wavs/input.11.wav --rec-file wavs/tmp.44.wav")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# simple test
|
||||
test_param = TestParam(
|
||||
"Resample (large filter) 11 KHZ to 48 KHZ",
|
||||
[
|
||||
InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 48000 --play-file wavs/input.11.wav --rec-file wavs/tmp.48.wav")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# simple test
|
||||
test_param = TestParam(
|
||||
"Resample (large filter) 11 KHZ to 8 KHZ",
|
||||
[
|
||||
InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 8000 --play-file wavs/input.11.wav --rec-file wavs/tmp.8.wav")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# simple test
|
||||
test_param = TestParam(
|
||||
"Resample (large filter) 8 KHZ to 11 KHZ",
|
||||
[
|
||||
InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 11025 --play-file wavs/input.8.wav --rec-file wavs/tmp.11.wav")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# simple test
|
||||
test_param = TestParam(
|
||||
"Resample (large filter) 8 KHZ to 16 KHZ",
|
||||
[
|
||||
InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 16000 --play-file wavs/input.8.wav --rec-file wavs/tmp.16.wav")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# simple test
|
||||
test_param = TestParam(
|
||||
"Resample (large filter) 8 KHZ to 22 KHZ",
|
||||
[
|
||||
InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 22050 --play-file wavs/input.8.wav --rec-file wavs/tmp.22.wav")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# simple test
|
||||
test_param = TestParam(
|
||||
"Resample (large filter) 8 KHZ to 32 KHZ",
|
||||
[
|
||||
InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 32000 --play-file wavs/input.8.wav --rec-file wavs/tmp.32.wav")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# simple test
|
||||
test_param = TestParam(
|
||||
"Resample (large filter) 8 KHZ to 44 KHZ",
|
||||
[
|
||||
InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 44100 --play-file wavs/input.8.wav --rec-file wavs/tmp.44.wav")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# simple test
|
||||
test_param = TestParam(
|
||||
"Resample (large filter) 8 KHZ to 48 KHZ",
|
||||
[
|
||||
InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 48000 --play-file wavs/input.8.wav --rec-file wavs/tmp.48.wav")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
ADD_PARAM = ""
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
ADD_PARAM += "--null-audio"
|
||||
|
||||
# Call with default pjsua settings
|
||||
test_param = TestParam(
|
||||
"PESQ defaults pjsua settings",
|
||||
[
|
||||
InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --play-file wavs/input.16.wav --no-vad"),
|
||||
InstanceParam("UA2", "--null-audio --max-calls=1 --rec-file wavs/tmp.16.wav --clock-rate 16000 --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
pesq_threshold = 3.8
|
||||
@@ -0,0 +1,18 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Call with default pjsua settings
|
||||
test_param = TestParam(
|
||||
"PESQ defaults pjsua settings (RX side uses snd dev)",
|
||||
[
|
||||
InstanceParam("UA1", "--max-calls=1 --play-file wavs/input.16.wav --null-audio"),
|
||||
InstanceParam("UA2", "--max-calls=1 --rec-file wavs/tmp.16.wav --clock-rate 16000 --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
test_param.skip = True
|
||||
|
||||
pesq_threshold = None
|
||||
@@ -0,0 +1,19 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
ADD_PARAM = ""
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
ADD_PARAM += "--null-audio"
|
||||
|
||||
# Call with PCMA codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec PCMA",
|
||||
[
|
||||
InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec pcma --clock-rate 8000 --play-file wavs/input.8.wav"),
|
||||
InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec pcma --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
pesq_threshold = 3.5
|
||||
@@ -0,0 +1,19 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
ADD_PARAM = ""
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
ADD_PARAM += "--null-audio"
|
||||
|
||||
# Call with PCMU codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec PCMU",
|
||||
[
|
||||
InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec pcmu --clock-rate 8000 --play-file wavs/input.8.wav"),
|
||||
InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec pcmu --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
pesq_threshold = 3.5
|
||||
@@ -0,0 +1,19 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
ADD_PARAM = ""
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
ADD_PARAM += "--null-audio"
|
||||
|
||||
# Call with G722 codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec G722",
|
||||
[
|
||||
InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec g722 --clock-rate 16000 --play-file wavs/input.16.wav"),
|
||||
InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec g722 --clock-rate 16000 --rec-file wavs/tmp.16.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
pesq_threshold = 3.7
|
||||
@@ -0,0 +1,19 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
ADD_PARAM = ""
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
ADD_PARAM += "--null-audio"
|
||||
|
||||
# Call with GSM codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec GSM",
|
||||
[
|
||||
InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec gsm --clock-rate 8000 --play-file wavs/input.8.wav"),
|
||||
InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec gsm --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
pesq_threshold = 3.0
|
||||
@@ -0,0 +1,19 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
ADD_PARAM = ""
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
ADD_PARAM += "--null-audio"
|
||||
|
||||
# Call with iLBC codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec iLBC",
|
||||
[
|
||||
InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec ilbc --clock-rate 8000 --play-file wavs/input.8.wav"),
|
||||
InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec ilbc --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
pesq_threshold = 3.0
|
||||
@@ -0,0 +1,19 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
ADD_PARAM = ""
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
ADD_PARAM += "--null-audio"
|
||||
|
||||
# Call with L16/16000/1 codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec L16/16000/1",
|
||||
[
|
||||
InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec L16/16000/1 --clock-rate 16000 --play-file wavs/input.16.wav"),
|
||||
InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec L16/16000/1 --clock-rate 16000 --rec-file wavs/tmp.16.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
pesq_threshold = 3.5
|
||||
@@ -0,0 +1,19 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
ADD_PARAM = ""
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
ADD_PARAM += "--null-audio"
|
||||
|
||||
# Call with L16/16000/2 codec
|
||||
test_param = TestParam(
|
||||
"PESQ defaults pjsua settings",
|
||||
[
|
||||
InstanceParam("UA1", ADD_PARAM + " --stereo --max-calls=1 --clock-rate 16000 --add-codec L16/16000/2 --play-file wavs/input.2.16.wav"),
|
||||
InstanceParam("UA2", "--null-audio --stereo --max-calls=1 --clock-rate 16000 --add-codec L16/16000/2 --rec-file wavs/tmp.2.16.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
pesq_threshold = None
|
||||
@@ -0,0 +1,19 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
ADD_PARAM = ""
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
ADD_PARAM += "--null-audio"
|
||||
|
||||
# Call with L16/8000/1 codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec L16/8000/1",
|
||||
[
|
||||
InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec L16/8000/1 --clock-rate 8000 --play-file wavs/input.8.wav"),
|
||||
InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec L16/8000/1 --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
pesq_threshold = 3.5
|
||||
@@ -0,0 +1,19 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
ADD_PARAM = ""
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
ADD_PARAM += "--null-audio"
|
||||
|
||||
# Call with L16/8000/2 codec
|
||||
test_param = TestParam(
|
||||
"PESQ defaults pjsua settings",
|
||||
[
|
||||
InstanceParam("UA1", ADD_PARAM + " --stereo --max-calls=1 --clock-rate 8000 --add-codec L16/8000/2 --play-file wavs/input.2.8.wav"),
|
||||
InstanceParam("UA2", "--null-audio --stereo --max-calls=1 --clock-rate 8000 --add-codec L16/8000/2 --rec-file wavs/tmp.2.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
pesq_threshold = None
|
||||
@@ -0,0 +1,19 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
ADD_PARAM = ""
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
ADD_PARAM += "--null-audio"
|
||||
|
||||
# Call with Speex/16000 codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec Speex WB",
|
||||
[
|
||||
InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --clock-rate 16000 --add-codec speex/16000 --play-file wavs/input.16.wav --no-vad"),
|
||||
InstanceParam("UA2", "--null-audio --max-calls=1 --clock-rate 16000 --add-codec speex/16000 --rec-file wavs/tmp.16.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
pesq_threshold = 3.8
|
||||
@@ -0,0 +1,19 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
ADD_PARAM = ""
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
ADD_PARAM += "--null-audio"
|
||||
|
||||
# Call with Speex/8000 codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec Speex NB",
|
||||
[
|
||||
InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec speex/8000 --clock-rate 8000 --play-file wavs/input.8.wav --no-vad"),
|
||||
InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec speex/8000 --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
pesq_threshold = 3.65
|
||||
@@ -0,0 +1,17 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Call with PCMA codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec PCMA (RX side uses snd dev)",
|
||||
[
|
||||
InstanceParam("UA1", "--max-calls=1 --add-codec pcma --clock-rate 8000 --play-file wavs/input.8.wav --null-audio"),
|
||||
InstanceParam("UA2", "--max-calls=1 --add-codec pcma --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
test_param.skip = True
|
||||
|
||||
pesq_threshold = 3.5
|
||||
@@ -0,0 +1,17 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Call with PCMU codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec PCMU (RX side uses snd dev)",
|
||||
[
|
||||
InstanceParam("UA1", "--max-calls=1 --add-codec pcmu --clock-rate 8000 --play-file wavs/input.8.wav --null-audio"),
|
||||
InstanceParam("UA2", "--max-calls=1 --add-codec pcmu --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
test_param.skip = True
|
||||
|
||||
pesq_threshold = 3.5
|
||||
@@ -0,0 +1,17 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Call with G722 codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec G722 (RX side uses snd dev)",
|
||||
[
|
||||
InstanceParam("UA1", "--max-calls=1 --add-codec g722 --clock-rate 16000 --play-file wavs/input.16.wav --null-audio"),
|
||||
InstanceParam("UA2", "--max-calls=1 --add-codec g722 --clock-rate 16000 --rec-file wavs/tmp.16.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
test_param.skip = True
|
||||
|
||||
pesq_threshold = 3.7
|
||||
@@ -0,0 +1,17 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Call with GSM codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec GSM (RX side uses snd dev)",
|
||||
[
|
||||
InstanceParam("UA1", "--max-calls=1 --add-codec gsm --clock-rate 8000 --play-file wavs/input.8.wav --null-audio"),
|
||||
InstanceParam("UA2", "--max-calls=1 --add-codec gsm --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
test_param.skip = True
|
||||
|
||||
pesq_threshold = 3.0
|
||||
@@ -0,0 +1,17 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Call with iLBC codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec iLBC (RX side uses snd dev)",
|
||||
[
|
||||
InstanceParam("UA1", "--max-calls=1 --add-codec ilbc --clock-rate 8000 --play-file wavs/input.8.wav --null-audio"),
|
||||
InstanceParam("UA2", "--max-calls=1 --add-codec ilbc --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
test_param.skip = True
|
||||
|
||||
pesq_threshold = 3.0
|
||||
@@ -0,0 +1,17 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Call with L16/16000/1 codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec L16/16000/1 (RX side uses snd dev)",
|
||||
[
|
||||
InstanceParam("UA1", "--max-calls=1 --add-codec L16/16000/1 --clock-rate 16000 --play-file wavs/input.16.wav --null-audio"),
|
||||
InstanceParam("UA2", "--max-calls=1 --add-codec L16/16000/1 --clock-rate 16000 --rec-file wavs/tmp.16.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
test_param.skip = True
|
||||
|
||||
pesq_threshold = 3.5
|
||||
@@ -0,0 +1,17 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Call with L16/16000/2 codec
|
||||
test_param = TestParam(
|
||||
"PESQ defaults pjsua settings",
|
||||
[
|
||||
InstanceParam("UA1", "--stereo --max-calls=1 --clock-rate 16000 --add-codec L16/16000/2 --play-file wavs/input.2.16.wav --null-audio"),
|
||||
InstanceParam("UA2", "--stereo --max-calls=1 --clock-rate 16000 --add-codec L16/16000/2 --rec-file wavs/tmp.2.16.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
test_param.skip = True
|
||||
|
||||
pesq_threshold = None
|
||||
@@ -0,0 +1,17 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Call with L16/8000/1 codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec L16/8000/1 (RX side uses snd dev)",
|
||||
[
|
||||
InstanceParam("UA1", "--max-calls=1 --add-codec L16/8000/1 --clock-rate 8000 --play-file wavs/input.8.wav --null-audio"),
|
||||
InstanceParam("UA2", "--max-calls=1 --add-codec L16/8000/1 --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
test_param.skip = True
|
||||
|
||||
pesq_threshold = 3.5
|
||||
@@ -0,0 +1,17 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Call with L16/8000/2 codec
|
||||
test_param = TestParam(
|
||||
"PESQ defaults pjsua settings",
|
||||
[
|
||||
InstanceParam("UA1", "--stereo --max-calls=1 --clock-rate 8000 --add-codec L16/8000/2 --play-file wavs/input.2.8.wav --null-audio"),
|
||||
InstanceParam("UA2", "--stereo --max-calls=1 --clock-rate 8000 --add-codec L16/8000/2 --rec-file wavs/tmp.2.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
test_param.skip = True
|
||||
|
||||
pesq_threshold = None
|
||||
@@ -0,0 +1,17 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Call with Speex/16000 codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec Speex WB (RX side uses snd dev)",
|
||||
[
|
||||
InstanceParam("UA1", "--max-calls=1 --clock-rate 16000 --add-codec speex/16000 --play-file wavs/input.16.wav --null-audio"),
|
||||
InstanceParam("UA2", "--max-calls=1 --clock-rate 16000 --add-codec speex/16000 --rec-file wavs/tmp.16.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
test_param.skip = True
|
||||
|
||||
pesq_threshold = 3.7
|
||||
@@ -0,0 +1,17 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Call with Speex/8000 codec
|
||||
test_param = TestParam(
|
||||
"PESQ codec Speex NB (RX side uses snd dev)",
|
||||
[
|
||||
InstanceParam("UA1", "--max-calls=1 --add-codec speex/8000 --clock-rate 8000 --play-file wavs/input.8.wav --null-audio"),
|
||||
InstanceParam("UA2", "--max-calls=1 --add-codec speex/8000 --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
|
||||
]
|
||||
)
|
||||
|
||||
if (HAS_SND_DEV == 0):
|
||||
test_param.skip = True
|
||||
|
||||
pesq_threshold = 3.0
|
||||
@@ -0,0 +1,12 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Direct peer to peer presence
|
||||
test_param = TestParam(
|
||||
"Direct peer to peer presence",
|
||||
[
|
||||
InstanceParam("client1", "--null-audio"),
|
||||
InstanceParam("client2", "--null-audio")
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
# $Id$
|
||||
#
|
||||
from inc_cfg import *
|
||||
|
||||
# Basic registration
|
||||
test_param = TestParam(
|
||||
"Presence with PUBLISH",
|
||||
[
|
||||
InstanceParam( "ua1",
|
||||
"--null-audio"+
|
||||
" --id=\"<sip:test1@pjsip.org>\""+
|
||||
" --registrar=sip:sip.pjsip.org" +
|
||||
" --username=test1" +
|
||||
" --password=test1" +
|
||||
" --realm=*" +
|
||||
" --proxy=\"sip:sip.pjsip.org;lr\"" +
|
||||
" --publish",
|
||||
uri="<sip:test1@pjsip.org>",
|
||||
have_reg=True,
|
||||
have_publish=True),
|
||||
InstanceParam( "ua2",
|
||||
"--null-audio"+
|
||||
" --id=\"<sip:test2@pjsip.org>\""+
|
||||
" --registrar=sip:sip.pjsip.org" +
|
||||
" --username=test2" +
|
||||
" --password=test2" +
|
||||
" --realm=*" +
|
||||
" --proxy=\"sip:sip.pjsip.org;lr\"" +
|
||||
" --publish",
|
||||
uri="<sip:test2@pjsip.org>",
|
||||
have_reg=True,
|
||||
have_publish=True),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# $Id$
|
||||
import inc_sip as sip
|
||||
import inc_sdp as sdp
|
||||
|
||||
pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
|
||||
"--auto-update-nat=0"
|
||||
|
||||
req1 = sip.RecvfromTransaction("Registration", 200,
|
||||
include=["REGISTER sip"],
|
||||
exclude=["Authorization"],
|
||||
resp_hdr=["Server: Snake Registrar", "Expires: 221", "Contact: sip:localhost"],
|
||||
expect="registration success"
|
||||
)
|
||||
|
||||
recvfrom_cfg = sip.RecvfromCfg("Simple registration test",
|
||||
pjsua, [req1])
|
||||
@@ -0,0 +1,15 @@
|
||||
# $Id$
|
||||
import inc_sip as sip
|
||||
import inc_sdp as sdp
|
||||
|
||||
pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT"
|
||||
|
||||
req1 = sip.RecvfromTransaction("", 401,
|
||||
include=["REGISTER sip"],
|
||||
exclude=["Authorization"],
|
||||
resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""],
|
||||
expect="PJSIP_ENOCREDENTIAL"
|
||||
)
|
||||
|
||||
recvfrom_cfg = sip.RecvfromCfg("Failed registration test",
|
||||
pjsua, [req1])
|
||||
@@ -0,0 +1,23 @@
|
||||
# $Id$
|
||||
import inc_sip as sip
|
||||
import inc_sdp as sdp
|
||||
|
||||
pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
|
||||
"--username user --realm python --password passwd --auto-update-nat=0"
|
||||
|
||||
req1 = sip.RecvfromTransaction("Initial registration", 401,
|
||||
include=["REGISTER sip"],
|
||||
exclude=["Authorization"],
|
||||
resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""],
|
||||
expect="SIP/2.0 401"
|
||||
)
|
||||
|
||||
req2 = sip.RecvfromTransaction("Registration retry with auth", 200,
|
||||
include=["REGISTER sip", "Authorization:",
|
||||
"realm=\"python\"", "username=\"user\"",
|
||||
"nonce=\"1234\"", "response="],
|
||||
expect="registration success"
|
||||
)
|
||||
|
||||
recvfrom_cfg = sip.RecvfromCfg("Successful registration test",
|
||||
pjsua, [req1, req2])
|
||||
@@ -0,0 +1,23 @@
|
||||
# $Id$
|
||||
import inc_sip as sip
|
||||
import inc_sdp as sdp
|
||||
|
||||
pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
|
||||
"--username user --realm \"*\" --password passwd --auto-update-nat=0"
|
||||
|
||||
req1 = sip.RecvfromTransaction("Initial registration", 401,
|
||||
include=["REGISTER sip"],
|
||||
exclude=["Authorization"],
|
||||
resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""],
|
||||
expect="SIP/2.0 401"
|
||||
)
|
||||
|
||||
req2 = sip.RecvfromTransaction("Registration retry with auth", 200,
|
||||
include=["REGISTER sip", "Authorization:",
|
||||
"realm=\"python\"", "username=\"user\"",
|
||||
"nonce=\"1234\"", "response="],
|
||||
expect="registration success"
|
||||
)
|
||||
|
||||
recvfrom_cfg = sip.RecvfromCfg("Successful registration with wildcard realm test",
|
||||
pjsua, [req1, req2])
|
||||
@@ -0,0 +1,31 @@
|
||||
# $Id$
|
||||
import inc_sip as sip
|
||||
import inc_sdp as sdp
|
||||
|
||||
pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
|
||||
"--realm=* --user=username --password=password " + \
|
||||
"--auto-update-nat=0"
|
||||
|
||||
# 401 Response, missing realm value
|
||||
req1 = sip.RecvfromTransaction("Initial request", 401,
|
||||
include=["REGISTER sip"],
|
||||
exclude=[],
|
||||
resp_hdr=['WWW-Authenticate: Digest']
|
||||
)
|
||||
|
||||
# Client should retry, we giving it another 401 with empty realm
|
||||
req2 = sip.RecvfromTransaction("REGISTER retry #1 of 2", 407,
|
||||
include=["REGISTER sip"],
|
||||
exclude=[],
|
||||
resp_hdr=['Proxy-Authenticate: Digest realm=""']
|
||||
)
|
||||
|
||||
# Client should retry
|
||||
req3 = sip.RecvfromTransaction("REGISTER retry #2 of 2", 200,
|
||||
include=[],
|
||||
exclude=[],
|
||||
expect="registration success"
|
||||
)
|
||||
|
||||
recvfrom_cfg = sip.RecvfromCfg("Registration with empty realm",
|
||||
pjsua, [req1, req2, req3])
|
||||
@@ -0,0 +1,16 @@
|
||||
# $Id$
|
||||
import inc_sip as sip
|
||||
import inc_sdp as sdp
|
||||
|
||||
pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
|
||||
"--realm=provider --user=username --password=password"
|
||||
|
||||
req1 = sip.RecvfromTransaction("", 401,
|
||||
include=["REGISTER sip"],
|
||||
exclude=["Authorization"],
|
||||
resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""],
|
||||
expect="PJSIP_ENOCREDENTIAL"
|
||||
)
|
||||
|
||||
recvfrom_cfg = sip.RecvfromCfg("Failed registration because of realm test",
|
||||
pjsua, [req1])
|
||||
@@ -0,0 +1,26 @@
|
||||
# $Id$
|
||||
import inc_sip as sip
|
||||
import inc_sdp as sdp
|
||||
|
||||
# Authentication failure test with same nonce
|
||||
|
||||
|
||||
pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
|
||||
"--realm=python --user=username --password=password"
|
||||
|
||||
req1 = sip.RecvfromTransaction("Initial request", 401,
|
||||
include=["REGISTER sip"],
|
||||
exclude=["Authorization"],
|
||||
resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""]
|
||||
)
|
||||
|
||||
req2 = sip.RecvfromTransaction("REGISTER retry", 401,
|
||||
include=["REGISTER sip", "Authorization", "nonce=\"1\""],
|
||||
exclude=["Authorization:[\\s\\S]+Authorization:"],
|
||||
resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""],
|
||||
expect="PJSIP_EFAILEDCREDENTIAL"
|
||||
)
|
||||
|
||||
|
||||
recvfrom_cfg = sip.RecvfromCfg("Authentication failure with same nonce",
|
||||
pjsua, [req1, req2])
|
||||
@@ -0,0 +1,29 @@
|
||||
# $Id$
|
||||
import inc_sip as sip
|
||||
import inc_sdp as sdp
|
||||
|
||||
pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
|
||||
"--realm=python --user=username --password=password " + \
|
||||
"--auto-update-nat=0"
|
||||
|
||||
req1 = sip.RecvfromTransaction("Initial request", 401,
|
||||
include=["REGISTER sip"],
|
||||
exclude=["Authorization"],
|
||||
resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""]
|
||||
)
|
||||
|
||||
req2 = sip.RecvfromTransaction("REGISTER first retry", 401,
|
||||
include=["REGISTER sip", "Authorization", "nonce=\"1\""],
|
||||
exclude=["Authorization:[\\s\\S]+Authorization:"],
|
||||
resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"2\", stale=true"]
|
||||
)
|
||||
|
||||
|
||||
req3 = sip.RecvfromTransaction("REGISTER retry with new nonce", 200,
|
||||
include=["REGISTER sip", "Authorization", "nonce=\"2\""],
|
||||
exclude=["Authorization:[\\s\\S]+Authorization:"],
|
||||
expect="registration success"
|
||||
)
|
||||
|
||||
recvfrom_cfg = sip.RecvfromCfg("Authentication okay after retry with new nonce",
|
||||
pjsua, [req1, req2, req3])
|
||||
@@ -0,0 +1,31 @@
|
||||
# $Id$
|
||||
import inc_sip as sip
|
||||
import inc_sdp as sdp
|
||||
|
||||
pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
|
||||
"--realm=python --user=username --password=password " + \
|
||||
"--auto-update-nat=0"
|
||||
|
||||
# 423 Response without Min-Expires header
|
||||
req1 = sip.RecvfromTransaction("Initial request", 423,
|
||||
include=["REGISTER sip"],
|
||||
exclude=[],
|
||||
resp_hdr=[]
|
||||
)
|
||||
|
||||
# Client should retry with Expires header containing special value (pjsip specific)
|
||||
req2 = sip.RecvfromTransaction("REGISTER retry after 423 response without Min-Expires header", 423,
|
||||
include=["REGISTER sip", "Expires: 3601"],
|
||||
exclude=[],
|
||||
resp_hdr=["Min-Expires: 3612"]
|
||||
)
|
||||
|
||||
# Client should retry with proper Expires header now
|
||||
req3 = sip.RecvfromTransaction("REGISTER retry after proper 423", 200,
|
||||
include=["Expires: 3612"],
|
||||
exclude=[],
|
||||
expect="registration success"
|
||||
)
|
||||
|
||||
recvfrom_cfg = sip.RecvfromCfg("Reregistration after 423 response",
|
||||
pjsua, [req1, req2, req3])
|
||||
@@ -0,0 +1,20 @@
|
||||
# $Id$
|
||||
import inc_sip as sip
|
||||
import inc_sdp as sdp
|
||||
|
||||
pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
|
||||
"--realm=python --user=username --password=password " + \
|
||||
"--auto-update-nat=0 --reg-timeout 300"
|
||||
|
||||
# 423 Response with Min-Expires header that is lower than what the client
|
||||
# had requested
|
||||
req1 = sip.RecvfromTransaction("Initial request", 423,
|
||||
include=["REGISTER sip"],
|
||||
exclude=[],
|
||||
resp_hdr=["Min-Expires: 250"],
|
||||
expect="invalid Min-Expires"
|
||||
|
||||
)
|
||||
|
||||
recvfrom_cfg = sip.RecvfromCfg("Invalid 423 response to REGISTER",
|
||||
pjsua, [req1])
|
||||
@@ -0,0 +1,25 @@
|
||||
# $Id$
|
||||
import inc_sip as sip
|
||||
import inc_sdp as sdp
|
||||
|
||||
pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
|
||||
"--realm=python --user=username --password=password " + \
|
||||
"--auto-update-nat=0 --reg-timeout 300"
|
||||
|
||||
# 423 without Min-Expires. PJSIP would retry with Expires: 3601
|
||||
req1 = sip.RecvfromTransaction("Initial request", 423,
|
||||
include=["REGISTER sip"],
|
||||
exclude=[],
|
||||
resp_hdr=[]
|
||||
)
|
||||
|
||||
# Another 423, still without Min-Expires
|
||||
req2 = sip.RecvfromTransaction("Retry with guessed Expires header", 423,
|
||||
include=["REGISTER sip", "Expires: 3601"],
|
||||
exclude=[],
|
||||
resp_hdr=[],
|
||||
expect="without Min-Expires header is invalid"
|
||||
)
|
||||
|
||||
recvfrom_cfg = sip.RecvfromCfg("Invalid 423 response to REGISTER",
|
||||
pjsua, [req1, req2])
|
||||
@@ -0,0 +1,28 @@
|
||||
# $Id$
|
||||
import inc_sip as sip
|
||||
import inc_sdp as sdp
|
||||
|
||||
pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
|
||||
"--username theuser1 --realm python1 --password passwd --next-cred " + \
|
||||
"--username theuser2 --realm python2 --password passwd " + \
|
||||
"--auto-update-nat=0"
|
||||
|
||||
req1 = sip.RecvfromTransaction("Initial registration", 401,
|
||||
include=["REGISTER sip"],
|
||||
resp_hdr=["WWW-Authenticate: Digest realm=\"python1\", nonce=\"1234\"",
|
||||
"WWW-Authenticate: Digest realm=\"python2\", nonce=\"6789\""],
|
||||
expect="SIP/2.0 401"
|
||||
)
|
||||
|
||||
req2 = sip.RecvfromTransaction("Registration retry with auth", 200,
|
||||
include=["REGISTER sip",
|
||||
"Authorization:[\\s\\S]+Authorization:", # Must have 2 Auth hdrs
|
||||
"realm=\"python1\"", "realm=\"python2\"",
|
||||
"username=\"theuser1\"", "username=\"theuser2\"",
|
||||
"nonce=\"1234\"", "nonce=\"6789\"",
|
||||
"response="],
|
||||
expect="registration success"
|
||||
)
|
||||
|
||||
recvfrom_cfg = sip.RecvfromCfg("Multiple authentication challenges",
|
||||
pjsua, [req1, req2])
|
||||
Loaded 100 of 2474 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user