initial commit

This commit is contained in:
Dan Bastone committed 2021-10-29 14:41:03 -04:00
commit 636959b37b
2474 files changed
+1343178

No files matched your search

+65
View File
@@ -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
+152
View File
@@ -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
+64
View File
@@ -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"
+38
View File
@@ -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
+343
View File
@@ -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
+350
View File
@@ -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
+174
View File
@@ -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
+153
View File
@@ -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)
+11
View File
@@ -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)
+284
View File
@@ -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)
+410
View File
@@ -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)
+220
View File
@@ -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