Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.

Review: https://reviewboard.asterisk.org/r/1891/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@369517 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Joshua Colp
2012-07-01 17:28:57 +00:00
parent 628425ba6f
commit 37256ea45d
1947 changed files with 1120896 additions and 37 deletions

View File

@@ -0,0 +1,4 @@
This directory contains files to run automated/unattended tests for PJSIP.
See https://trac.pjsip.org/repos/wiki/AutomatedTesting for more info.

View File

@@ -0,0 +1,354 @@
#!/usr/bin/python
import optparse
import os
import platform
import socket
import subprocess
import sys
PROG = "r" + "$Rev$".strip("$ ").replace("Rev: ", "")
PYTHON = os.path.basename(sys.executable)
build_type = ""
vs_target = ""
s60_target = ""
no_test = False
no_pjsua_test = False
#
# Get gcc version
#
def gcc_version(gcc):
proc = subprocess.Popen(gcc + " -v", stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, shell=True)
ver = ""
while True:
s = proc.stdout.readline()
if not s:
break
if s.find("gcc version") >= 0:
ver = s.split(None, 3)[2]
break
proc.wait()
return "gcc-" + ver
#
# Get Visual Studio info
#
class VSVersion:
def __init__(self):
self.version = "8"
self.release = "2005"
proc = subprocess.Popen("cl", stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
while True:
s = proc.stdout.readline()
if s=="":
break
pos = s.find("Version")
if pos > 0:
proc.wait()
s = s[pos+8:]
ver = s.split(None, 1)[0]
major = ver[0:2]
if major=="12":
self.version = "6"
self.release = "98"
break
elif major=="13":
self.version = "7"
self.release = "2003"
break
elif major=="14":
self.version = "8"
self.release = "2005"
break
elif major=="15":
self.version = "9"
self.release = "2008"
break
elif major=="16":
self.version = "10"
self.release = "2010"
break
else:
self.version = "11"
self.release = "2012"
break
proc.wait()
self.vs_version = "vs" + self.version
self.vs_release = "vs" + self.release
#
# Get S60 SDK info
#
class S60SDK:
def __init__(self):
self.epocroot = ""
self.sdk = ""
self.device = ""
# Check that EPOCROOT is set
if not "EPOCROOT" in os.environ:
sys.stderr.write("Error: EPOCROOT environment variable is not set\n")
sys.exit(1)
epocroot = os.environ["EPOCROOT"]
# EPOCROOT must have trailing backslash
if epocroot[-1] != "\\":
epocroot = epocroot + "\\"
os.environ["EPOCROOT"] = epocroot
self.epocroot = epocroot
self.sdk = sdk1 = epocroot.split("\\")[-2]
self.device = "@" + self.sdk + ":com.nokia.s60"
# Check that correct device is set
proc = subprocess.Popen("devices", stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, shell=True)
sdk2 = ""
while True:
line = proc.stdout.readline()
if line.find("- default") > 0:
sdk2 = line.split(":",1)[0]
break
proc.wait()
if sdk1 != sdk2:
sys.stderr.write("Error: default SDK in device doesn't match EPOCROOT\n")
sys.stderr.write("Default device SDK = '" + sdk2 + "'\n")
sys.stderr.write("EPOCROOT SDK = '" + sdk1 + "'\n")
sys.exit(1)
self.name = sdk2.replace("_", "-")
def replace_vars(text):
global vs_target, s60_target, build_type, no_test, no_pjsua_test
suffix = ""
os_info = platform.system() + platform.release() + "-" + platform.machine()
# osinfo
s60sdk_var = None
if build_type == "s60":
s60sdk_var = S60SDK()
os_info = s60sdk_var.name
elif platform.system().lower() == "windows" or platform.system().lower() == "microsoft":
if platform.system().lower() == "microsoft":
os_info = platform.release() + "-" + platform.version() + "-" + platform.win32_ver()[2]
elif platform.system().lower() == "linux":
os_info = "-" + "-".join(platform.linux_distribution()[0:2])
# vs_target
if not vs_target and text.find("$(VSTARGET)") >= 0:
if build_type != "vs":
sys.stderr.write("Warning: $(VSTARGET) only valid for Visual Studio\n")
print "Enter Visual Studio vs_target name (e.g. Release, Debug) [Release]: ",
vs_target = sys.stdin.readline().replace("\n", "").replace("\r", "")
if not vs_target:
vs_target = "Release"
# s60_target
if not s60_target and text.find("$(S60TARGET)") >= 0:
if build_type != "s60":
sys.stderr.write("Warning: $(S60TARGET) only valid for S60\n")
print "Enter S60 target name (e.g. \"gcce urel\") [gcce urel]: ",
s60_target = sys.stdin.readline().replace("\n", "").replace("\r", "")
if not s60_target:
s60_target = "gcce urel"
# Suffix
if build_type == "vs":
suffix = "i386-Win32-vc8-" + vs_target
elif build_type == "s60":
suffix = s60sdk_var.name + "-" + s60_target.replace(" ", "-")
elif build_type == "gnu":
proc = subprocess.Popen("sh config.guess", cwd="../..",
shell=True, stdout=subprocess.PIPE)
suffix = proc.stdout.readline().rstrip(" \r\n")
else:
sys.stderr.write("Error: unsupported build type '" + build_type + "'\n")
sys.exit(1)
while True:
if text.find("$(PJSUA-TESTS)") >= 0:
if no_test==False and no_pjsua_test==False:
# Determine pjsua exe to use
exe = "../../pjsip-apps/bin/pjsua-" + suffix
proc = subprocess.Popen(PYTHON + " runall.py --list-xml -e " + exe,
cwd="../pjsua",
shell=True, stdout=subprocess.PIPE)
content = proc.stdout.read()
else:
content = ""
text = text.replace("$(PJSUA-TESTS)", content)
elif text.find("$(GCC)") >= 0:
text = text.replace("$(GCC)", gcc_version("gcc"))
elif text.find("$(VS)") >= 0:
vsver = VSVersion()
text = text.replace("$(VS)", VSVersion().vs_release)
elif text.find("$(VSTARGET)") >= 0:
text = text.replace("$(VSTARGET)", vs_target)
elif text.find("$(S60TARGET)") >= 0:
text = text.replace("$(S60TARGET)", s60_target)
elif text.find("$(S60TARGETNAME)") >= 0:
text = text.replace("$(S60TARGETNAME)", s60_target.replace(" ", "-"))
elif text.find("$(S60DEVICE)") >= 0:
text = text.replace("$(S60DEVICE)", s60sdk_var.device)
elif text.find("$(EPOCROOT)") >= 0:
text = text.replace("$(EPOCROOT)", s60sdk_var.epocroot)
elif text.find("$(DISABLED)") >= 0:
text = text.replace("$(DISABLED)", "0")
elif text.find("$(IPPROOT)") >= 0:
if not os.environ.has_key("IPPROOT"):
sys.stderr.write("Error: environment variable IPPROOT is needed but not set\n")
sys.exit(1)
text = text.replace("$(IPPROOT)", os.environ["IPPROOT"])
elif text.find("$(IPPSAMPLES)") >= 0:
if not os.environ.has_key("IPPSAMPLES"):
sys.stderr.write("Error: environment variable IPPSAMPLES is needed but not set\n")
sys.exit(1)
text = text.replace("$(IPPSAMPLES)", os.environ["IPPSAMPLES"])
elif text.find("$(IPPARCH)") >= 0:
if not os.environ.has_key("IPPARCH"):
text = text.replace("$(IPPARCH)", "")
else:
text = text.replace("$(IPPARCH)", os.environ["IPPARCH"])
elif text.find("$(OS)") >= 0:
text = text.replace("$(OS)", os_info)
elif text.find("$(SUFFIX)") >= 0:
text = text.replace("$(SUFFIX)", suffix)
elif text.find("$(HOSTNAME)") >= 0:
text = text.replace("$(HOSTNAME)", socket.gethostname())
elif text.find("$(PJDIR)") >= 0:
wdir = os.path.join(os.getcwd(), "../..")
wdir = os.path.normpath(wdir)
text = text.replace("$(PJDIR)", wdir)
elif text.find("$(NOP)") >= 0:
if platform.system().lower() == "windows" or platform.system().lower() == "microsoft":
cmd = "CMD /C echo Success"
else:
cmd = "echo Success"
text = text.replace("$(NOP)", cmd)
elif text.find("$(NOTEST)") >= 0:
if no_test:
str = '"1"'
else:
str = '"0"'
text = text.replace("$(NOTEST)", str)
else:
break
return text
def main(args):
global vs_target, s60_target, build_type, no_test, no_pjsua_test
output = sys.stdout
usage = """Usage: configure.py [OPTIONS] scenario_template_file
Where OPTIONS:
-o FILE Output to file, otherwise to stdout.
-t TYPE Specify build type. If not specified, it will be
asked if necessary. Values are:
vs: Visual Studio
gnu: Makefile based
s60: Symbian S60
-vstarget TARGETNAME Specify Visual Studio target name if build type is set
to vs. If not specified then it will be asked.
Sample target names:
- Debug
- Release
- or any other target in the project file
-s60target TARGETNAME Specify S60 target name if build type is set to s60.
If not specified then it will be asked. Sample target
names:
- "gcce udeb"
- "gcce urel"
-notest Disable all tests in the scenario.
-nopjsuatest Disable pjsua tests in the scenario.
"""
args.pop(0)
while len(args):
if args[0]=='-o':
args.pop(0)
if len(args):
output = open(args[0], "wt")
args.pop(0)
else:
sys.stderr.write("Error: needs value for -o\n")
sys.exit(1)
elif args[0]=='-vstarget':
args.pop(0)
if len(args):
vs_target = args[0]
args.pop(0)
else:
sys.stderr.write("Error: needs value for -vstarget\n")
sys.exit(1)
elif args[0]=='-s60target':
args.pop(0)
if len(args):
s60_target = args[0]
args.pop(0)
else:
sys.stderr.write("Error: needs value for -s60target\n")
sys.exit(1)
elif args[0]=='-t':
args.pop(0)
if len(args):
build_type = args[0].lower()
args.pop(0)
else:
sys.stderr.write("Error: needs value for -t\n")
sys.exit(1)
if not ["vs", "gnu", "s60"].count(build_type):
sys.stderr.write("Error: invalid -t argument value\n")
sys.exit(1)
elif args[0]=='-notest' or args[0]=='-notests':
args.pop(0)
no_test = True
elif args[0]=='-nopjsuatest' or args[0]=='-nopjsuatests':
args.pop(0)
no_pjsua_test = True
else:
break
if len(args) != 1:
sys.stderr.write(usage + "\n")
return 1
if not build_type:
defval = "vs"
if "SHELL" in os.environ:
shell = os.environ["SHELL"]
if shell.find("sh") > -1:
defval = "gnu"
print "Enter the build type (values: vs, gnu, s60) [%s]: " % (defval),
build_type = sys.stdin.readline().replace("\n", "").replace("\r", "")
if not build_type:
build_type = defval
tpl_file = args[len(args)-1]
if not os.path.isfile(tpl_file):
print "Error: unable to find template file '%s'" % (tpl_file)
return 1
f = open(tpl_file, "r")
tpl = f.read()
f.close()
tpl = replace_vars(tpl)
output.write(tpl)
if output != sys.stdout:
output.close()
return 0
if __name__ == "__main__":
rc = main(sys.argv)
sys.exit(rc)

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" ?>
<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
<Submit group="Experimental" build="$(SUFFIX)-$(GCC)-IPP" disabled="$(DISABLED)" >
<Update />
<FileWrite file="user.mak">
<![CDATA[
# Written by ccdash
export CFLAGS += -Wno-unused-label -g
]]>
</FileWrite>
<FileWrite file="pjlib/include/pj/config_site.h">
<![CDATA[
/* Written by ccdash */
#define PJ_HAS_IPV6 1
#define PJMEDIA_HAS_G7221_CODEC 0
#define PJMEDIA_HAS_INTEL_IPP 1
]]>
</FileWrite>
<Configure cmd='./aconfigure --enable-ipp --with-ipp="$(IPPROOT)" --with-ipp-samples="$(IPPSAMPLES)" --with-ipp-arch=$(IPPARCH)' />
<Build cmd="make dep &amp;&amp; make clean &amp;&amp; make" />
<Test name="pjlib-test" wdir="pjlib/bin" cmd="./pjlib-test-$(SUFFIX)" disabled=$(NOTEST) />
<Test name="pjlib-util-test" wdir="pjlib-util/bin" cmd="./pjlib-util-test-$(SUFFIX)" disabled=$(NOTEST) />
<Test name="pjnath-test" wdir="pjnath/bin" cmd="./pjnath-test-$(SUFFIX)" disabled=$(NOTEST) />
<Test name="pjmedia-test" wdir="pjmedia/bin" cmd="./pjmedia-test-$(SUFFIX)" disabled=$(NOTEST) />
<Test name="pjsip-test" wdir="pjsip/bin" cmd="./pjsip-test-$(SUFFIX)" disabled=$(NOTEST) />
$(PJSUA-TESTS)
</Submit>
</Scenario>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" ?>
<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
<Submit group="Experimental" build="$(SUFFIX)-$(GCC)" exclude="(.*amr.*)">
<Update />
<FileWrite file="user.mak">
<![CDATA[
# Written by ccdash
export CFLAGS += -Wno-unused-label -g
]]>
</FileWrite>
<FileWrite file="pjlib/include/pj/config_site.h">
<![CDATA[
/* Written by ccdash */
#define PJ_HAS_IPV6 1
#define PJMEDIA_HAS_G7221_CODEC 1
]]>
</FileWrite>
<Configure cmd="./aconfigure" />
<Build cmd="make dep &amp;&amp; make clean &amp;&amp; make" />
<Test name="pjlib-test" wdir="pjlib/bin" cmd="./pjlib-test-$(SUFFIX)" disabled=$(NOTEST) />
<Test name="pjlib-util-test" wdir="pjlib-util/bin" cmd="./pjlib-util-test-$(SUFFIX)" disabled=$(NOTEST) />
<Test name="pjnath-test" wdir="pjnath/bin" cmd="./pjnath-test-$(SUFFIX)" disabled=$(NOTEST) />
<Test name="pjmedia-test" wdir="pjmedia/bin" cmd="./pjmedia-test-$(SUFFIX)" disabled=$(NOTEST) />
<Test name="pjsip-test" wdir="pjsip/bin" cmd="./pjsip-test-$(SUFFIX)" disabled=$(NOTEST) />
$(PJSUA-TESTS)
</Submit>
</Scenario>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" ?>
<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
<Submit group="Experimental" build="iPhoneOS-default">
<Update />
<FileWrite file="user.mak">
<![CDATA[
# Written by ccdash
export CFLAGS += -Wno-unused-label -g
]]>
</FileWrite>
<FileWrite file="pjlib/include/pj/config_site.h">
<![CDATA[
/* Written by ccdash */
#define PJ_CONFIG_IPHONE 1
#include <pj/config_site_sample.h>
]]>
</FileWrite>
<Configure cmd="./configure-iphone" />
<Build cmd="make distclean &amp;&amp; make dep &amp;&amp; make clean &amp;&amp; make" />
</Submit>
</Scenario>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" ?>
<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
<Submit group="Experimental" build="$(OS)-$(VS)-$(VSTARGET)-default" exclude="(.*amr.*)">
<Update />
<FileWrite file="pjlib/include/pj/config_site.h">
<![CDATA[
/* Written by ccdash */
#define PJ_HAS_IPV6 1
#define PJMEDIA_HAS_G7221_CODEC 1
#define PJ_TODO(x)
]]>
</FileWrite>
<Configure cmd="cmd /c echo success" />
<Build cmd='vcbuild.exe /nologo /nohtmllog /nocolor /rebuild pjproject-vs8.sln "$(VSTARGET)|Win32"' />
<Test name="pjlib-test" info="" wdir="pjlib/bin" cmd="pjlib-test-i386-Win32-vc8-$(VSTARGET)" disabled=$(NOTEST)/>
<Test name="pjlib-util-test" info="" wdir="pjlib-util/bin" cmd="pjlib-util-test-i386-Win32-vc8-$(VSTARGET)" disabled=$(NOTEST) />
<Test name="pjnath-test" info="" wdir="pjnath/bin" cmd="pjnath-test-i386-Win32-vc8-$(VSTARGET)" disabled=$(NOTEST) />
<Test name="pjmedia-test" info="" wdir="pjmedia/bin" cmd="pjmedia-test-i386-Win32-vc8-$(VSTARGET)" disabled=$(NOTEST) />
<Test name="pjsip-test" info="" wdir="pjsip/bin" cmd="pjsip-test-i386-Win32-vc8-$(VSTARGET)" disabled=$(NOTEST) />
$(PJSUA-TESTS)
</Submit>
</Scenario>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" ?>
<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)/tests/automated">
<Submit group="Experimental" build="Test-Preparation">
<Configure cmd="$(NOP)" />
<Build cmd="$(NOP)" />
<!-- GNU Makefile based scenario
Requirement:
- none
-->
<Test name="Configuring GNU scenario" cmd="python configure.py -t gnu -o gnu.xml gnu.xml.template" />
<!-- GNU Makefile with Intel IPP scenario.
Requirements:
- IPPROOT
- IPPSAMPLES
- IPPARCH (optional)
-->
<Test name="Configuring GNU IPP scenario" cmd="python configure.py -t gnu -o gnu-ipp.xml gnu-ipp.xml.template" />
<!-- iPhone target.
Requriement(s):
- valid SDK is installed
-->
<Test name="Configuring iPhone scenario" cmd="python configure.py -t gnu -o iphone.xml iphone.xml.template" />
<!-- MSVC target.
Requirements:
- Build from VS successfully
- VS paths are set
-->
<Test name="Configuring Visual Studio for Win32" cmd="python configure.py -t vs -vstarget Release -o msvc-win32.xml -nopjsuatest msvc.xml.template" />
<!-- Symbian target.
Requirement:
- EPOCROOT (modify below)
-->
<Test name="Configuring Symbian scenario" cmd='CMD /C SET EPOCROOT=\S60\devices\S60_5th_Edition_SDK_v1.0&amp;&amp; devices -setdefault @S60_5th_Edition_SDK_v1.0:com.nokia.s60&amp;&amp; python configure.py -t s60 -s60target &quot;gcce urel&quot; -o symbian.xml symbian.xml.template' />
</Submit>
</Scenario>

View File

@@ -0,0 +1,140 @@
#!/usr/bin/python
import os
import sys
import time
import datetime
import ccdash
INTERVAL = 300
DELAY = 0
ONCE = False
SUFFIX = ""
FORCE = False
def run_scenarios(scenarios, group):
# Run each scenario
rc = 0
for scenario in scenarios:
argv = []
argv.append("ccdash.py")
argv.append("scenario")
argv.append(scenario)
argv.append("--group")
argv.append(group)
thisrc = ccdash.main(argv)
if rc==0 and thisrc:
rc = thisrc
return rc
def usage():
print """Periodically monitor working directory for Continuous and Nightly builds
Usage:
run_continuous.py [options] scenario1.xml [scenario2.xml ...]
options:
These are options which will be processed by run_continuous.py:
--delay MIN Delay both Continuous and Nightly builds by MIN minutes.
This is useful to coordinate the build with other build
machines. By default, Continuous build will be done right
after changes are detected, and Nightly build will be done
at 00:00 GMT. MIN is a float number.
--once Just run one loop to see if anything needs to be done and
if so just do it once. Quit after that.
--suffix SFX Set group suffix to SFX. For example, if SFX is "-2.x", then
tests will be submitted to "Nightly-2.x", "Continuous-2.x",
and "Experimental-2.x"
--force Force running the test even when nothing has changed.
"""
sys.exit(1)
if __name__ == "__main__":
if len(sys.argv)<=1 or sys.argv[1]=="-h" or sys.argv[1]=="--h" or sys.argv[1]=="--help" or sys.argv[1]=="/h":
usage()
# Splice list
scenarios = []
i = 1
while i < len(sys.argv):
if sys.argv[i]=="--delay":
i = i + 1
if i >= len(sys.argv):
print "Error: missing argument"
sys.exit(1)
DELAY = float(sys.argv[i]) * 60
print "Delay is set to %f minute(s)" % (DELAY / 60)
elif sys.argv[i]=="--suffix":
i = i + 1
if i >= len(sys.argv):
print "Error: missing argument"
sys.exit(1)
SUFFIX = sys.argv[i]
print "Suffix is set to %s" % (SUFFIX)
elif sys.argv[i]=="--once":
ONCE = True
elif sys.argv[i]=="--force":
FORCE = True
else:
# Check if scenario exists
scenario = sys.argv[i]
if not os.path.exists(scenario):
print "Error: file " + scenario + " does not exist"
sys.exit(1)
scenarios.append(scenario)
print "Scenario %s added" % (scenario)
i = i + 1
if len(scenarios) < 1:
print "Error: scenario is required"
sys.exit(1)
# Current date
utc = time.gmtime(None)
day = utc.tm_mday
# Loop foreva
while True:
argv = []
# Anything changed recently?
argv.append("ccdash.py")
argv.append("status")
argv.append("-w")
argv.append("../..")
rc = ccdash.main(argv)
utc = time.gmtime(None)
if utc.tm_mday != day or rc != 0 or FORCE:
group = ""
if utc.tm_mday != day:
day = utc.tm_mday
group = "Nightly" + SUFFIX
elif rc != 0:
group = "Continuous" + SUFFIX
else:
group = "Experimental" + SUFFIX
if DELAY > 0:
print "Will run %s after %f s.." % (group, DELAY)
time.sleep(DELAY)
rc = run_scenarios(scenarios, group)
msg = str(datetime.datetime.now()) + \
": done running " + group + \
"tests, will check again in " + str(INTERVAL) + "s.."
if ONCE:
sys.exit(0)
else:
# Nothing changed
msg = str(datetime.datetime.now()) + \
": No update, will check again in " + str(INTERVAL) + "s.."
if ONCE:
sys.exit(1)
print msg
time.sleep(INTERVAL)

View File

@@ -0,0 +1,11 @@
#!/usr/bin/python
import sys
import ccdash
if __name__ == "__main__":
sys.argv[0] = "ccdash.py"
sys.argv.insert(1, "scenario")
rc = ccdash.main(sys.argv)
sys.exit(rc)

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" ?>
<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
<!-- *********************************************************
** This file contains scenario for APS and APS-Direct **
********************************************************* -->
<!-- ******************************
** APS **
****************************** -->
<Submit group="Experimental" build="$(OS)-$(S60TARGETNAME)-APS" >
<Update />
<!-- Configure config_site.h -->
<FileWrite file="pjlib/include/pj/config_site.h">
<![CDATA[
/* Written by ccdash */
#define PJMEDIA_AUDIO_DEV_HAS_SYMB_APS 1
#define PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA 0
#include <pj/config_site_sample.h>
]]>
</FileWrite>
<!-- Configure symbian_ua.mmp -->
<FileWrite file="build.symbian/symbian_ua.mmp" replace_begin="// =BEGIN" replace_end="// =END">
<![CDATA[
#define SND_HAS_APS 1
#define SND_HAS_VAS 0
#define SND_HAS_MDA 0
]]>
</FileWrite>
<!-- Configure symbian_ua_gui.mmp -->
<FileWrite file="pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp" replace_begin="// =BEGIN" replace_end="// =END">
<![CDATA[
#define SND_HAS_APS 1
#define SND_HAS_VAS 0
#define SND_HAS_MDA 0
]]>
</FileWrite>
<Configure cmd="cmd /c echo success" />
<Build wdir="build.symbian" cmd='cmd /C &quot;bldmake bldfiles &amp;&amp; abld reallyclean $(S60TARGET) &amp;&amp; abld build $(S60TARGET)&quot;' />
</Submit>
<!-- ******************************
** APS-Direct **
****************************** -->
<Submit group="Experimental" build="$(OS)-$(S60TARGETNAME)-APS-Direct" >
<Update />
<!-- Configure config_site.h -->
<FileWrite file="pjlib/include/pj/config_site.h">
<![CDATA[
/* Written by ccdash */
#define PJ_CONFIG_NOKIA_APS_DIRECT
#include <pj/config_site_sample.h>
]]>
</FileWrite>
<Configure cmd="cmd /c echo success" />
<Build wdir="build.symbian" cmd='cmd /C &quot;bldmake bldfiles &amp;&amp; abld reallyclean $(S60TARGET) &amp;&amp; abld build $(S60TARGET)&quot;' />
<!-- Restore symbian_ua.mmp -->
<FileWrite file="build.symbian/symbian_ua.mmp" replace_begin="// =BEGIN" replace_end="// =END">
<![CDATA[
#define SND_HAS_APS 0
#define SND_HAS_VAS 0
#define SND_HAS_MDA 1
]]>
</FileWrite>
<!-- Restore symbian_ua_gui.mmp -->
<FileWrite file="pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp" replace_begin="// =BEGIN" replace_end="// =END">
<![CDATA[
#define SND_HAS_APS 0
#define SND_HAS_VAS 0
#define SND_HAS_MDA 1
]]>
</FileWrite>
</Submit>
</Scenario>

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" ?>
<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
<!-- *********************************************************
** This file contains scenario for VAS and VAS-Direct **
********************************************************* -->
<!-- ******************************
** VAS **
****************************** -->
<Submit group="Experimental" build="$(OS)-$(S60TARGETNAME)-VAS1" >
<Update />
<!-- Configure config_site.h -->
<FileWrite file="pjlib/include/pj/config_site.h">
<![CDATA[
/* Written by ccdash */
#define PJMEDIA_AUDIO_DEV_HAS_SYMB_VAS 1
#define PJMEDIA_AUDIO_DEV_HAS_SYMB_APS 0
#define PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA 0
#include <pj/config_site_sample.h>
]]>
</FileWrite>
<!-- Configure symbian_ua.mmp -->
<FileWrite file="build.symbian/symbian_ua.mmp" replace_begin="// =BEGIN" replace_end="// =END">
<![CDATA[
#define SND_HAS_APS 0
#define SND_HAS_VAS 1
#define SND_HAS_MDA 0
]]>
</FileWrite>
<!-- Configure symbian_ua_gui.mmp -->
<FileWrite file="pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp" replace_begin="// =BEGIN" replace_end="// =END">
<![CDATA[
#define SND_HAS_APS 0
#define SND_HAS_VAS 1
#define SND_HAS_MDA 0
]]>
</FileWrite>
<Configure cmd="cmd /c echo success" />
<Build wdir="build.symbian" cmd='cmd /C &quot;bldmake bldfiles &amp;&amp; abld reallyclean $(S60TARGET) &amp;&amp; abld build $(S60TARGET)&quot;' />
</Submit>
<!-- ******************************
** VAS-Direct **
****************************** -->
<Submit group="Experimental" build="$(OS)-$(S60TARGETNAME)-VAS1-Direct" >
<Update />
<!-- Configure config_site.h -->
<FileWrite file="pjlib/include/pj/config_site.h">
<![CDATA[
/* Written by ccdash */
#define PJ_CONFIG_NOKIA_VAS_DIRECT
#include <pj/config_site_sample.h>
]]>
</FileWrite>
<Configure cmd="cmd /c echo success" />
<Build wdir="build.symbian" cmd='cmd /C &quot;bldmake bldfiles &amp;&amp; abld reallyclean $(S60TARGET) &amp;&amp; abld build $(S60TARGET)&quot;' />
<!-- Restore symbian_ua.mmp -->
<FileWrite file="build.symbian/symbian_ua.mmp" replace_begin="// =BEGIN" replace_end="// =END">
<![CDATA[
#define SND_HAS_APS 0
#define SND_HAS_VAS 0
#define SND_HAS_MDA 1
]]>
</FileWrite>
<!-- Restore symbian_ua_gui.mmp -->
<FileWrite file="pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp" replace_begin="// =BEGIN" replace_end="// =END">
<![CDATA[
#define SND_HAS_APS 0
#define SND_HAS_VAS 0
#define SND_HAS_MDA 1
]]>
</FileWrite>
</Submit>
</Scenario>

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" ?>
<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
<!-- Symbian S60 default -->
<Submit group="Experimental" build="$(OS)-$(S60TARGETNAME)-default" >
<Update disabled="1" />
<FileWrite file="pjlib/include/pj/config_site.h">
<![CDATA[
/* Written by ccdash */
#include <pj/config_site_sample.h>
#undef PJ_HAS_IPV6
#define PJ_HAS_IPV6 1
#undef PJMEDIA_HAS_G7221_CODEC
#define PJMEDIA_HAS_G7221_CODEC 1
]]>
</FileWrite>
<Configure cmd="cmd /c devices -setdefault $(S60DEVICE)" />
<Build wdir="build.symbian" cmd='cmd /C &quot;SET EPOCROOT=$(EPOCROOT)&amp;&amp; bldmake bldfiles &amp;&amp; abld reallyclean $(S60TARGET) &amp;&amp; abld build $(S60TARGET)&quot;' />
</Submit>
</Scenario>

View File

@@ -0,0 +1,33 @@
Variables:
-----------------------------
DISABLED = "$(DISABLED)"
GCC = "$(GCC)"
HOSTNAME = "$(HOSTNAME)"
OS = "$(OS)"
PJDIR = "$(PJDIR)"
SUFFIX = "$(SUFFIX)"
NOTEST = "$(NOTEST)"
S60 only:
------------------------------
S60TARGET = "$(S60TARGET)"
S60TARGETNAME = "$(S60TARGETNAME)"
S60DEVICE = "$(S60DEVICE)"
EPOCROOT = "$(EPOCROOT)"
VS only:
------------------------------
VS = "$(VS)"
VSTARGET = "$(VSTARGET)"
PJSUA-TESTS:
------------------------------
$(PJSUA-TESTS)
------------------------------
OTHER:
------------------------------
IPPROOT
IPPSAMPLES
IPPARCH
NOP (cmdline to do nothing)

View File

@@ -0,0 +1,59 @@
PJSIP CDASH AUTOMATED TESTS
--------------------------------
1. What is this
This directory contains the scripts to run the automated, Python based tests
of PJSIP source codes, across platforms, and submit the test results to a CDash
test monitoring dashboard.
Stuffs that are included in the test scope:
- configure (for GNU platforms, e.g. Linux, msys, and MacOS X)
- build
- standard unit tests (pjlib-test, pjsip-test, etc.)
- pjsua's Python based blackbox tests
2. Requirements
To run this test, you will need:
- Python (2.4 or later)
- curl (http://curl.haxx.se)
- a CDash server to receive test submissions (http://www.cdash.org)
- ccdash to submit the tests (http://trac.pjsip.org/ccdash)
3. Configuration
Create a Python configuration file by copying from "cfg_site_sample.py".
Save it as "cfg_site.py". You may create more than one configurations for your
site and save them as different files.
4. Running
To execute tests for GNU based targets:
$ python main.py cfg_gnu
To execute tests for MSVC based target:
$ python main.py cfg_msvc
To execute tests for Symbian target:
$ python main.py cfg_symbian
If you have a different site configuration file, you may specify it in the
arguments, e.g.:
$ python main.py cfg_gnu my_site_config
For more information you can also pass "-h" or "--help", e.g.:
$ python main.py cfg_gnu --help

View File

@@ -0,0 +1,501 @@
#
# builder.py - PJSIP test scenarios builder
#
# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
import ccdash
import os
import platform
import re
import subprocess
import sys
import time
class Operation:
"""\
The Operation class describes the individual ccdash operation to be
performed.
"""
# Types:
UPDATE = "update" # Update operation
CONFIGURE = "configure" # Configure operation
BUILD = "build" # Build operation
TEST = "test" # Unit test operation
def __init__(self, type, cmdline, name="", wdir=""):
self.type = type
self.cmdline = cmdline
self.name = name
self.wdir = wdir
if self.type==self.TEST and not self.name:
raise "name required for tests"
def encode(self, base_dir):
s = [self.type]
if self.type == self.TEST:
s.append(self.name)
if self.type != self.UPDATE:
s.append(self.cmdline)
s.append("-w")
if self.wdir:
s.append(base_dir + "/" + self.wdir)
else:
s.append(base_dir)
return s
#
# Update operation
#
update_ops = [Operation(Operation.UPDATE, "")]
#
# The standard library tests (e.g. pjlib-test, pjsip-test, etc.)
#
std_test_ops= [
Operation(Operation.TEST, "./pjlib-test$SUFFIX", name="pjlib test",
wdir="pjlib/bin"),
Operation(Operation.TEST, "./pjlib-util-test$SUFFIX",
name="pjlib-util test", wdir="pjlib-util/bin"),
Operation(Operation.TEST, "./pjnath-test$SUFFIX", name="pjnath test",
wdir="pjnath/bin"),
Operation(Operation.TEST, "./pjmedia-test$SUFFIX", name="pjmedia test",
wdir="pjmedia/bin"),
Operation(Operation.TEST, "./pjsip-test$SUFFIX", name="pjsip test",
wdir="pjsip/bin")
]
#
# These are pjsua Python based unit test operations
#
def build_pjsua_test_ops(pjsua_exe=""):
ops = []
if pjsua_exe:
exe = " -e ../../pjsip-apps/bin/" + pjsua_exe
else:
exe = ""
cwd = os.getcwd()
os.chdir("../pjsua")
os.system("python runall.py --list > list")
f = open("list", "r")
for e in f:
e = e.rstrip("\r\n ")
(mod,param) = e.split(None,2)
name = mod[4:mod.find(".py")] + "_" + \
param[param.find("/")+1:param.find(".py")]
ops.append(Operation(Operation.TEST, "python run.py" + exe + " " + \
e, name=name, wdir="tests/pjsua"))
f.close()
os.remove("list")
os.chdir(cwd)
return ops
#
# Get gcc version
#
def gcc_version(gcc):
proc = subprocess.Popen(gcc + " -v", stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, shell=True)
ver = ""
while True:
s = proc.stdout.readline()
if not s:
break
if s.find("gcc version") >= 0:
ver = s.split(None, 3)[2]
break
proc.wait()
return "gcc-" + ver
#
# Get Visual Studio version
#
def vs_get_version():
proc = subprocess.Popen("cl", stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
while True:
s = proc.stdout.readline()
if s=="":
break
pos = s.find("Version")
if pos > 0:
proc.wait()
s = s[pos+8:]
ver = s.split(None, 1)[0]
major = ver[0:2]
if major=="12":
return "vs6"
elif major=="13":
return "vs2003"
elif major=="14":
return "vs2005"
elif major=="15":
return "vs2008"
else:
return "vs-" + major
proc.wait()
return "vs-unknown"
#
# Test config
#
class BaseConfig:
def __init__(self, base_dir, url, site, group, options=None):
self.base_dir = base_dir
self.url = url
self.site = site
self.group = group
self.options = options
#
# Base class for test configurator
#
class TestBuilder:
def __init__(self, config, build_config_name="",
user_mak="", config_site="", exclude=[], not_exclude=[]):
self.config = config # BaseConfig instance
self.build_config_name = build_config_name # Optional build suffix
self.user_mak = user_mak # To be put in user.mak
self.config_site = config_site # To be put in config_s..
self.saved_user_mak = "" # To restore user.mak
self.saved_config_site = "" # To restore config_s..
self.exclude = exclude # List of exclude pattern
self.not_exclude = not_exclude # List of include pattern
self.ccdash_args = [] # ccdash cmd line
def stamp(self):
return time.strftime("%Y%m%d-%H%M", time.localtime())
def pre_action(self):
# Override user.mak
name = self.config.base_dir + "/user.mak"
if os.access(name, os.F_OK):
f = open(name, "r")
self.saved_user_mak = f.read()
f.close()
if True:
f = open(name, "w")
f.write(self.user_mak)
f.close()
# Override config_site.h
name = self.config.base_dir + "/pjlib/include/pj/config_site.h"
if os.access(name, os.F_OK):
f = open(name, "r")
self.saved_config_site= f.read()
f.close()
if True:
f = open(name, "wt")
f.write(self.config_site)
f.close()
def post_action(self):
# Restore user.mak
name = self.config.base_dir + "/user.mak"
f = open(name, "wt")
f.write(self.saved_user_mak)
f.close()
# Restore config_site.h
name = self.config.base_dir + "/pjlib/include/pj/config_site.h"
f = open(name, "wt")
f.write(self.saved_config_site)
f.close()
def build_tests(self):
# This should be overridden by subclasses
pass
def execute(self):
if len(self.ccdash_args)==0:
self.build_tests()
self.pre_action()
mandatory_op = ["update", "configure", "build"]
counter = 0
for a in self.ccdash_args:
# Check if this test is in exclusion list
fullcmd = " ".join(a)
excluded = False
included = False
for pat in self.exclude:
if pat and re.search(pat, fullcmd) != None:
excluded = True
break
if excluded:
for pat in self.not_exclude:
if pat and re.search(pat, fullcmd) != None:
included = True
break
if excluded and not included:
if len(fullcmd)>60:
fullcmd = fullcmd[0:60] + ".."
print "Skipping '%s'" % (fullcmd)
continue
b = ["ccdash.py"]
b.extend(a)
a = b
#print a
try:
rc = ccdash.main(a)
except Exception, e:
errmsg = str(e)
print "**** Error: ccdash got exception %s ****" % errmsg
rc = -1
except:
print "**** Error: ccdash got unknown exception ****"
rc = -1
if rc!=0 and a[1] in mandatory_op:
print "Stopping because of error.."
break
counter = counter + 1
self.post_action()
#
# GNU test configurator
#
class GNUTestBuilder(TestBuilder):
"""\
This class creates list of tests suitable for GNU targets.
"""
def __init__(self, config, build_config_name="", user_mak="", \
config_site="", cross_compile="", exclude=[], not_exclude=[]):
"""\
Parameters:
config - BaseConfig instance
build_config_name - Optional name to be added as suffix to the build
name. Sample: "min-size", "O4", "TLS", etc.
user_mak - Contents to be put on user.mak
config_site - Contents to be put on config_site.h
cross_compile - Optional cross-compile prefix. Must include the
trailing dash, e.g. "arm-unknown-linux-"
exclude - List of regular expression patterns for tests
that will be excluded from the run
not_exclude - List of regular expression patterns for tests
that will be run regardless of whether they
match the excluded pattern.
"""
TestBuilder.__init__(self, config, build_config_name=build_config_name,
user_mak=user_mak, config_site=config_site,
exclude=exclude, not_exclude=not_exclude)
self.cross_compile = cross_compile
if self.cross_compile and self.cross_compile[-1] != '-':
self.cross_compile.append("-")
def build_tests(self):
if self.cross_compile:
suffix = "-" + self.cross_compile[0:-1]
build_name = self.cross_compile + \
gcc_version(self.cross_compile + "gcc")
else:
proc = subprocess.Popen("sh "+self.config.base_dir+"/config.guess",
shell=True, stdout=subprocess.PIPE)
plat = proc.stdout.readline().rstrip(" \r\n")
build_name = plat + "-"+gcc_version(self.cross_compile + "gcc")
suffix = "-" + plat
if self.build_config_name:
build_name = build_name + "-" + self.build_config_name
cmds = []
cmds.extend(update_ops)
cmds.append(Operation(Operation.CONFIGURE, "sh ./configure"))
if sys.platform=="win32":
# Don't build python module on Mingw
cmds.append(Operation(Operation.BUILD,
"sh -c 'make distclean && make dep && make'"))
else:
cmds.append(Operation(Operation.BUILD,
"sh -c 'make distclean && make dep && make" + \
" && cd pjsip-apps/src/python && " + \
"python setup.py clean build'"))
cmds.extend(std_test_ops)
cmds.extend(build_pjsua_test_ops())
self.ccdash_args = []
for c in cmds:
c.cmdline = c.cmdline.replace("$SUFFIX", suffix)
args = c.encode(self.config.base_dir)
args.extend(["-U", self.config.url,
"-S", self.config.site,
"-T", self.stamp(),
"-B", build_name,
"-G", self.config.group])
args.extend(self.config.options)
self.ccdash_args.append(args)
#
# MSVC test configurator
#
class MSVCTestBuilder(TestBuilder):
"""\
This class creates list of tests suitable for Visual Studio builds.
You need to set the MSVC environment variables (typically by calling
vcvars32.bat) prior to running this class.
"""
def __init__(self, config, target="Release|Win32", build_config_name="",
config_site="", exclude=[], not_exclude=[]):
"""\
Parameters:
config - BaseConfig instance
target - Visual Studio build configuration to build.
Sample: "Debug|Win32", "Release|Win32".
build_config_name - Optional name to be added as suffix to the build
name. Sample: "Debug", "Release", "IPv6", etc.
config_site - Contents to be put on config_site.h
exclude - List of regular expression patterns for tests
that will be excluded from the run
not_exclude - List of regular expression patterns for tests
that will be run regardless of whether they
match the excluded pattern.
"""
TestBuilder.__init__(self, config, build_config_name=build_config_name,
config_site=config_site, exclude=exclude,
not_exclude=not_exclude)
self.target = target.lower()
def build_tests(self):
(vsbuild,sys) = self.target.split("|",2)
build_name = sys + "-" + vs_get_version() + "-" + vsbuild
if self.build_config_name:
build_name = build_name + "-" + self.build_config_name
vccmd = "vcbuild.exe /nologo /nohtmllog /nocolor /rebuild " + \
"pjproject-vs8.sln " + " \"" + self.target + "\""
suffix = "-i386-win32-vc8-" + vsbuild
pjsua = "pjsua_vc8"
if vsbuild=="debug":
pjsua = pjsua + "d"
cmds = []
cmds.extend(update_ops)
cmds.append(Operation(Operation.CONFIGURE, "CMD /C echo Nothing to do"))
cmds.append(Operation(Operation.BUILD, vccmd))
cmds.extend(std_test_ops)
cmds.extend(build_pjsua_test_ops(pjsua))
self.ccdash_args = []
for c in cmds:
c.cmdline = c.cmdline.replace("$SUFFIX", suffix)
args = c.encode(self.config.base_dir)
args.extend(["-U", self.config.url,
"-S", self.config.site,
"-T", self.stamp(),
"-B", build_name,
"-G", self.config.group])
args.extend(self.config.options)
self.ccdash_args.append(args)
#
# Symbian test configurator
#
class SymbianTestBuilder(TestBuilder):
"""\
This class creates list of tests suitable for Symbian builds. You need to
set the command line build settings prior to running this class (typically
that involves setting the EPOCROOT variable and current device).
"""
def __init__(self, config, target="gcce urel", build_config_name="",
config_site="", exclude=[], not_exclude=[]):
"""\
Parameters:
config - BaseConfig instance
target - Symbian target to build. Default is "gcce urel".
build_config_name - Optional name to be added as suffix to the build
name. Sample: "APS", "VAS", etc.
config_site - Contents to be put on config_site.h
exclude - List of regular expression patterns for tests
that will be excluded from the run
not_exclude - List of regular expression patterns for tests
that will be run regardless of whether they
match the excluded pattern.
"""
TestBuilder.__init__(self, config, build_config_name=build_config_name,
config_site=config_site, exclude=exclude,
not_exclude=not_exclude)
self.target = target.lower()
def build_tests(self):
# Check that EPOCROOT is set
if not "EPOCROOT" in os.environ:
print "Error: EPOCROOT environment variable is not set"
sys.exit(1)
epocroot = os.environ["EPOCROOT"]
# EPOCROOT must have trailing backslash
if epocroot[-1] != "\\":
epocroot = epocroot + "\\"
os.environ["EPOCROOT"] = epocroot
sdk1 = epocroot.split("\\")[-2]
# Check that correct device is set
proc = subprocess.Popen("devices", stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, shell=True)
sdk2 = ""
while True:
line = proc.stdout.readline()
if line.find("- default") > 0:
sdk2 = line.split(":",1)[0]
break
proc.wait()
if sdk1 != sdk2:
print "Error: default SDK in device doesn't match EPOCROOT"
print "Default device SDK =", sdk2
print "EPOCROOT SDK =", sdk1
sys.exit(1)
build_name = sdk2.replace("_", "-") + "-" + \
self.target.replace(" ", "-")
if self.build_config_name:
build_name = build_name + "-" + self.build_config_name
cmdline = "cmd /C \"cd build.symbian && bldmake bldfiles && abld build %s\"" % (self.target)
cmds = []
cmds.extend(update_ops)
cmds.append(Operation(Operation.CONFIGURE, "CMD /C echo Nothing to do"))
cmds.extend([Operation(Operation.BUILD, cmdline)])
self.ccdash_args = []
suffix = ""
for c in cmds:
c.cmdline = c.cmdline.replace("$SUFFIX", suffix)
args = c.encode(self.config.base_dir)
args.extend(["-U", self.config.url,
"-S", self.config.site,
"-T", self.stamp(),
"-B", build_name,
"-G", self.config.group])
args.extend(self.config.options)
self.ccdash_args.append(args)

View File

@@ -0,0 +1,73 @@
#
# cfg_gnu.py - GNU target configurator
#
# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
import builder
import os
import sys
# Each configurator must export this function
def create_builder(args):
usage = """\
Usage:
main.py cfg_gnu [-h|--help] [cfg_site]
Arguments:
cfg_site: site configuration module. If not specified, "cfg_site"
is implied
-h, --help Show this help screen
"""
# (optional) args format:
# site configuration module. If not specified, "cfg_site" is implied
cfg_site = "cfg_site"
for arg in args:
if arg=="-h" or arg=="--help":
print usage
sys.exit(0)
elif arg[0]=="-":
print usage
sys.exit(1)
else:
cfg_site = arg
if os.access(cfg_site+".py", os.F_OK) == False:
print "Error: file '%s.py' doesn't exist." % (cfg_site)
sys.exit(1)
cfg_site = __import__(cfg_site)
test_cfg = builder.BaseConfig(cfg_site.BASE_DIR, \
cfg_site.URL, \
cfg_site.SITE_NAME, \
cfg_site.GROUP, \
cfg_site.OPTIONS)
config_site = "#define PJ_TODO(x)\n" + cfg_site.CONFIG_SITE
user_mak = "export CFLAGS+=-Wall\n" + cfg_site.USER_MAK
builders = [
builder.GNUTestBuilder(test_cfg, build_config_name="default",
user_mak=user_mak,
config_site=config_site,
exclude=cfg_site.EXCLUDE,
not_exclude=cfg_site.NOT_EXCLUDE)
]
return builders

View File

@@ -0,0 +1,82 @@
#
# cfg_msvc.py - MSVC/Visual Studio target configurator
#
# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
import builder
import os
import sys
# Each configurator must export this function
def create_builder(args):
usage = """\
Usage:
main.py cfg_msvc [-h|--help] [-t|--target TARGET] [cfg_site]
Arguments:
cfg_site: site configuration module. If not specified, "cfg_site"
is implied
-t,--target TARGET: Visual Studio build configuration to build. Default is
"Release|Win32". Sample values: "Debug|Win32"
-h, --help Show this help screen
"""
cfg_site = "cfg_site"
target = "Release|Win32"
in_option = ""
for arg in args:
if in_option=="-t":
target = arg
in_option = ""
elif arg=="--target" or arg=="-t":
in_option = "-t"
elif arg=="-h" or arg=="--help":
print usage
sys.exit(0)
elif arg[0]=="-":
print usage
sys.exit(1)
else:
cfg_site = arg
if os.access(cfg_site+".py", os.F_OK) == False:
print "Error: file '%s.py' doesn't exist." % (cfg_site)
sys.exit(1)
cfg_site = __import__(cfg_site)
test_cfg = builder.BaseConfig(cfg_site.BASE_DIR, \
cfg_site.URL, \
cfg_site.SITE_NAME, \
cfg_site.GROUP, \
cfg_site.OPTIONS)
config_site = "#define PJ_TODO(x)\n" + cfg_site.CONFIG_SITE
user_mak = cfg_site.USER_MAK
builders = [
builder.MSVCTestBuilder(test_cfg,
target=target,
build_config_name="default",
config_site=config_site,
exclude=cfg_site.EXCLUDE,
not_exclude=cfg_site.NOT_EXCLUDE)
]
return builders

View File

@@ -0,0 +1,50 @@
#
# cfg_site_sample.py - Sample site configuration
#
# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
import builder
# Your site name
SITE_NAME="Newham3"
# The URL where tests will be submitted to
URL = "http://192.168.0.2/dash/submit.php?project=PJSIP"
# Test group
GROUP = "Experimental"
# PJSIP base directory
BASE_DIR = "/root/project/pjproject"
# List of additional ccdash options
#OPTIONS = ["-o", "out.xml", "-y"]
OPTIONS = []
# What's the content of config_site.h
CONFIG_SITE = ""
# What's the content of user.mak
USER_MAK = ""
# List of regular expression of test patterns to be excluded
EXCLUDE = []
# List of regular expression of test patterns to be included (even
# if they match EXCLUDE patterns)
NOT_EXCLUDE = []
#"configure", "update", "build.*make", "build", "run.py mod_run.*100_simple"]

View File

@@ -0,0 +1,86 @@
#
# cfg_symbian.py - Symbian target configurator
#
# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
import builder
import os
import sys
# Each configurator must export this function
def create_builder(args):
usage = """\
Usage:
main.py cfg_symbian [-h|--help] [-t|--target TARGET] [cfg_site]
Arguments:
cfg_site: site configuration module. If not specified, "cfg_site"
is implied
-t,--target TARGET: Symbian target to build. Default is "gcce urel".
Other values:
"winscw udeb", "gcce udeb", etc.
-h, --help Show this help screen
"""
cfg_site = "cfg_site"
target = "gcce urel"
in_option = ""
for arg in args:
if in_option=="-t":
target = arg
in_option = ""
elif arg=="--target" or arg=="-t":
in_option = "-t"
elif arg=="--help" or arg=="-h":
print usage
sys.exit(0)
elif arg[0]=="-":
print usage
sys.exit(1)
else:
cfg_site = arg
if os.access(cfg_site+".py", os.F_OK) == False:
print "Error: file '%s.py' doesn't exist." % (cfg_site)
sys.exit(1)
cfg_site = __import__(cfg_site)
test_cfg = builder.BaseConfig(cfg_site.BASE_DIR, \
cfg_site.URL, \
cfg_site.SITE_NAME, \
cfg_site.GROUP, \
cfg_site.OPTIONS)
config_site1 = """\
#define PJ_TODO(x)
#include <pj/config_site_sample.h>
"""
config_Site = config_site1 + cfg_site.CONFIG_SITE
builders = [
builder.SymbianTestBuilder(test_cfg,
target=target,
build_config_name="default",
config_site=config_site1,
exclude=cfg_site.EXCLUDE,
not_exclude=cfg_site.NOT_EXCLUDE)
]
return builders

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,42 @@
#!/bin/env python
#
# main.py - main entry for PJSIP's CDash tests
#
# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
import sys
if len(sys.argv)==1:
print "Usage: main.py cfg_file [cfg_site]"
print "Example:"
print " main.py cfg_gnu"
print " main.py cfg_gnu custom_cfg_site"
sys.exit(1)
args = []
args.extend(sys.argv)
args.remove(args[1])
args.remove(args[0])
cfg_file = __import__(sys.argv[1])
builders = cfg_file.create_builder(args)
for builder in builders:
builder.execute()

View File

@@ -0,0 +1,44 @@
@echo off
rem ***
rem ************** VS 2005 **************
rem ***
set OLD_PATH=%PATH%
set OLD_INCLUDE=%INCLUDE%
set OLD_LIB=%LIB%
set OLD_LIBPATH=%LIBPATH%
call "C:\Program Files\Microsoft Visual Studio 8\VC\bin\vcvars32.bat" x86
python main.py cfg_msvc -t "Debug|Win32"
python main.py cfg_msvc -t "Release|Win32"
set PATH=%OLD_PATH%
set INCLUDE=%OLD_INCLUDE%
set LIB=%OLD_LIB%
set LIBPATH=%OLD_LIBPATH%
rem ***
rem ************** S60 3rd FP1 **************
rem ***
set EPOCROOT=\symbian\9.2\S60_3rd_FP1\
devices -setdefault @S60_3rd_FP1:com.nokia.s60
python main.py cfg_symbian -t "winscw udeb"
python main.py cfg_symbian -t "gcce udeb"
python main.py cfg_symbian -t "gcce urel"
rem ***
rem ************** Mingw **************
rem ***
set MSYSTEM=MINGW32
set DISPLAY=
C:\msys\1.0\bin\sh -c "python main.py cfg_gnu"
rem ***
rem ************** Linux **************
rem ***
set PATH=%PATH%;c:\msys\1.0\bin
set HOME=C:\msys\1.0\home\Administrator
C:\mingw\bin\ssh test@192.168.0.12 "cd project/pjproject/tests/cdash && python main.py cfg_gnu"

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

View File

@@ -0,0 +1,4 @@
# $Id$
# Specify if host has sound device, or test should be performed using sound device
HAS_SND_DEV = 0

View File

@@ -0,0 +1,107 @@
# $Id$
import random
import config_site
DEFAULT_ECHO = True
DEFAULT_TRACE = True
DEFAULT_START_SIP_PORT = 50000
# 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 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
sip_port=0, # SIP port
have_reg=False, # Have registration?
have_publish=False, # Have publish?
echo_enabled=DEFAULT_ECHO,
trace_enabled=DEFAULT_TRACE,
enable_buffer = False):
# Instance name
self.name = name
# Give random sip_port if it's not specified
if sip_port==0:
self.sip_port = random.randint(DEFAULT_START_SIP_PORT, 65534)
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

View File

@@ -0,0 +1,62 @@
# $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 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"

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

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

View File

@@ -0,0 +1,226 @@
# $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])
# Check media flow between ua1 and ua2
def check_media(ua1, ua2):
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)
# Caller making call
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)
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
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()
# Test that media is okay
time.sleep(0.3)
check_media(caller, callee)
check_media(callee, caller)
# Hold call by caller
caller.send("H")
caller.expect("INVITE sip:")
callee.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.5)
caller.send("v")
caller.expect("INVITE sip:")
callee.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()
# 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
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)
callee.send("v")
callee.expect("INVITE sip:")
caller.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()
# 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)
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()
# Test that media is okay
time.sleep(0.1)
check_media(caller, callee)
check_media(callee, caller)
# UPDATE (by callee)
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()
# 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
caller.send("Cp")
caller.expect("Enter codec")
caller.send("* 0")
caller.send("Cp")
caller.expect("Enter codec")
caller.send("pcmu 120")
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)
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)
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)
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

View File

@@ -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

View File

@@ -0,0 +1,167 @@
# $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
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\ncd 4 0\ncc 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\ncd 4 0\ncc 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

View File

@@ -0,0 +1,125 @@
# $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
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
u2.send("+b")
u2.send(uri1)
u2.expect("Subscription state changed NULL --> SENT")
u2.expect("Presence subscription.*is ACCEPTED")
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":
u1.send(">")
u1.send(acc1)
u1.expect("Current account changed")
if acc2!="-1":
u2.send(">")
u2.send(acc2)
u2.expect("Current account changed")
# Synchronize stdout
u1.sync_stdout()
u2.sync_stdout()
# u2 toggles online status
u2.send("t")
u1.expect(uri2 + ".*status.*Offline")
u2.expect("offline")
# Synchronize stdout
u1.sync_stdout()
u2.sync_stdout()
# u1 toggles online status
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
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
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

View File

@@ -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)

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

View File

@@ -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)

View File

@@ -0,0 +1,289 @@
# $Id$
import sys
import imp
import re
import os
import subprocess
import random
import time
import getopt
import inc_const as const
import inc_cfg as inc
# 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:
proc = None
echo = False
trace_enabled = False
name = ""
inst_param = None
rh = re.compile(const.DESTROYED)
ra = re.compile(const.ASSERT, re.I)
rr = re.compile(const.STDOUT_REFRESH)
t0 = time.time()
def __init__(self, inst_param):
self.inst_param = inst_param
self.name = inst_param.name
self.echo = inst_param.echo_enabled
self.trace_enabled = inst_param.trace_enabled
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)
def send(self, cmd):
self.trace("send " + cmd)
self.proc.stdin.writelines(cmd + "\n")
self.proc.stdin.flush()
def expect(self, pattern, raise_on_error=True, title=""):
self.trace("expect " + pattern)
r = re.compile(pattern, re.I)
refresh_cnt = 0
while True:
line = self.proc.stdout.readline()
if line == "":
raise inc.TestError(self.name + ": Premature EOF")
# Print the line if echo is ON
if self.echo:
print self.name + ": " + line,
# Trap assertion error
if self.ra.search(line) != None:
if raise_on_error:
raise inc.TestError(self.name + ": " + line)
else:
return None
# Count stdout refresh text.
if self.rr.search(line) != None:
refresh_cnt = refresh_cnt+1
if refresh_cnt >= 6:
self.trace("Timed-out!")
if raise_on_error:
raise inc.TestError(self.name + " " + title + ": Timeout expecting pattern: \"" + pattern + "\"")
else:
return None # timeout
# Search for expected text
if r.search(line) != None:
return line
def sync_stdout(self):
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.proc.communicate()
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:
p.send("q")
p.send("q")
except:
pass
is_err = False
try:
ret = p.expect(const.DESTROYED, False)
if not ret:
is_err = True
except:
is_err = True
if is_err:
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)
# Wait until registration completes
if inst_param.have_reg:
p.expect(inst_param.uri+".*registration success")
# Synchronize stdout
p.send("")
p.expect(const.PROMPT)
p.send("echo 1")
p.send("echo 1")
p.expect("echo 1")
# add running instance
script.test.process.append(p)
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)
# Shutdown all instances
time.sleep(2)
for p in script.test.process:
# Unregister if we have_reg to make sure that next tests
# won't wail
if p.inst_param.have_reg:
p.send("ru")
p.expect(p.inst_param.uri+".*unregistration success")
p.send("q")
p.send("q")
time.sleep(0.5)
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)

View File

@@ -0,0 +1,178 @@
# $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", # temporarily disabled until #1267 done
"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
]
# 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)
# Filter-out excluded tests
for pat in excluded_tests:
tests = [t for t in tests if t.find(pat)==-1]
resume_script=""
shell_cmd=""
# 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 " --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 " 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(1)
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.find(".py")]
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(1)
else:
sys.argv.pop(0)
sys.stderr.write("Error: argument value required")
sys.exit(1)
# Generate arguments for run.py
argv_st = " ".join(sys.argv)
# Init vars
fails_cnt = 0
tests_cnt = 0
# Re-create "logs" directory
try:
shutil.rmtree("logs")
except:
print "Warning: failed in removing directory 'logs'"
try:
os.mkdir("logs")
except:
print "Warning: failed in creating directory 'logs'"
# 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 %d/%d: %s..." % (tests_cnt+1, total_cnt, cmdline)
sys.stdout.write(msg)
sys.stdout.flush()
ret = os.system(cmdline + " > output.log")
t1 = time.time()
if ret != 0:
dur = int(t1 - t0)
print " failed!! [" + str(dur) + "s]"
logname = re.search(".*\s+(.*)", t).group(1)
logname = re.sub("[\\\/]", "_", logname)
logname = re.sub("\.py$", ".log", logname)
logname = "logs/" + logname
shutil.move("output.log", logname)
print "Please see '" + logname + "' for the test log."
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"

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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", enable_buffer=True),
InstanceParam("caller", "--null-audio --use-ice --max-calls=1", enable_buffer=True)
]
)

View File

@@ -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),
]
)

View File

@@ -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),
]
)

View File

@@ -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", enable_buffer=True),
InstanceParam("caller", "--null-audio --use-ice --max-calls=1", enable_buffer=True)
]
)

View File

@@ -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", enable_buffer=True),
InstanceParam("caller", "--null-audio --use-ice --max-calls=1 --ice-no-rtcp", enable_buffer=True)
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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")
]
)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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")
]
)

View File

@@ -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),
]
)

Some files were not shown because too many files have changed in this diff Show More