diff options
Diffstat (limited to 'tests/pjsua')
-rw-r--r-- | tests/pjsua/mod_sipp.py | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/tests/pjsua/mod_sipp.py b/tests/pjsua/mod_sipp.py new file mode 100644 index 00000000..1c7e6320 --- /dev/null +++ b/tests/pjsua/mod_sipp.py @@ -0,0 +1,189 @@ +# $Id$ +import ctypes +import time +import imp +import sys +import os +import re +import subprocess +from inc_cfg import * + +# SIPp executable path and param +#SIPP_PATH = '"C:\\Program Files (x86)\\Sipp_3.2\\sipp.exe"' +SIPP_PATH = 'sipp' +SIPP_PARAM = "-i 127.0.0.1 -p 6000 -m 1 127.0.0.1" +SIPP_TIMEOUT = 10 +# 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" +SIPP_BG_MODE = True + +PJSUA_DEF_PARAM = "--null-audio --max-calls=1 --no-tcp" +PJSUA_INST_PARAM = [] +PJSUA_EXPECTS = [] + +# Get SIPp scenario (XML file) +SIPP_SCEN_XML = "" +if ARGS[1].endswith('.xml'): + SIPP_SCEN_XML = ARGS[1] +else: + exit(-99) + +# Init PJSUA test instance +if os.access(SIPP_SCEN_XML[:-4]+".py", os.R_OK): + # Load from configuration 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): + PJSUA_INST_PARAM.append(InstanceParam("pjsua"+str(ua_idx+1), ua_param, sip_port=5060+ua_idx*2)) + PJSUA_EXPECTS = cfg_file.PJSUA_EXPECTS +else: + # Just use the SIPp XML scenario + 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:6000" + else: + # auto answer when SIPp is as UAC + ua_param = PJSUA_DEF_PARAM + " --auto-answer=200" + PJSUA_INST_PARAM.append(InstanceParam("pjsua", ua_param, sip_port=5060)) + + + +# Start SIPp process, returning PID +def start_sipp(): + global SIPP_BG_MODE + sipp_proc = None + + # run SIPp + 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" + 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, universal_newlines=False) + else: + sipp_proc = subprocess.Popen(fullcmd) + + 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: + sipp.wait() + 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]) + + # If there is no PJSUA EXPECT scenario, must keep polling PJSUA stdout + # otherwise PJSUA process may stuck (due to stdout pipe buffer full?) + # Ideally the poll should be done contiunously until SIPp process is + # terminated. + if len(PJSUA_EXPECTS)==0: + import inc_const + ua[0].expect(inc_const.STDOUT_REFRESH, raise_on_error = False) + return "" + + ua_err_st = "" + while len(PJSUA_EXPECTS): + expect = PJSUA_EXPECTS.pop(0) + ua_idx = expect[0] + expect_st = expect[1] + send_cmd = expect[2] + # Handle exception in pjsua flow, to avoid zombie SIPp process + try: + if expect_st != "": + 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; + + return ua_err_st + + +# 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: + raise TestError("SIPp returned error " + str(sipp_ret_code)) + + +# Here where it all comes together +test = TestParam(SIPP_SCEN_XML[:-4], + PJSUA_INST_PARAM, + TEST_FUNC) |