initial commit

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

No files matched your search

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