summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2015-04-13 12:28:02 +0000
committerNanang Izzuddin <nanang@teluu.com>2015-04-13 12:28:02 +0000
commita37a581a5e1f22027081f41891f2bf9ca88d5998 (patch)
treedc9d574cb1ff016cbf418033cde9d7878fb05f41 /tests
parent3315769a569fd61f099a38094dde1cd3347a8963 (diff)
Re #1842:
- Updated python test driver run.py to perform stdout polling using a dedicated thread, this will increase the robustness of pattern matcing class "Expect" and remove the possibility of stucked pjsua (due to output buffer full when no stdout read polling is done). - Also updated other test driver and scenario accordingly. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@5067 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'tests')
-rw-r--r--tests/pjsua/mod_sipp.py8
-rw-r--r--tests/pjsua/run.py123
-rw-r--r--tests/pjsua/scripts-sipp/uas-reinv-with-less-media.py4
3 files changed, 98 insertions, 37 deletions
diff --git a/tests/pjsua/mod_sipp.py b/tests/pjsua/mod_sipp.py
index c705c966..25081086 100644
--- a/tests/pjsua/mod_sipp.py
+++ b/tests/pjsua/mod_sipp.py
@@ -40,7 +40,7 @@ else:
FDEVNULL = None
# SIPp executable path and param
-#SIPP_PATH = '"C:\\Program Files (x86)\\Sipp_3.2\\sipp.exe"'
+#SIPP_PATH = '"C:\\devs\\bin\\Sipp_3.2\\sipp.exe"'
SIPP_PATH = 'sipp'
SIPP_PORT = 6000
SIPP_PARAM = "-m 1 -i 127.0.0.1 -p " + str(SIPP_PORT)
@@ -224,8 +224,10 @@ def exec_pjsua_expects(t, sipp):
# PJSUA process may stuck.
# Ideally the poll should be done contiunously until SIPp process is
# terminated.
- for ua_idx in range(len(ua)):
- ua[ua_idx].expect(inc_const.STDOUT_REFRESH, raise_on_error = False)
+ # 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
diff --git a/tests/pjsua/run.py b/tests/pjsua/run.py
index 7eee316a..78e1b214 100644
--- a/tests/pjsua/run.py
+++ b/tests/pjsua/run.py
@@ -6,6 +6,8 @@ import os
import subprocess
import random
import time
+import threading
+import traceback
import getopt
import inc_const as const
@@ -109,59 +111,94 @@ G_EXE = G_EXE.rstrip("\n\r \t")
###################################
# Poor man's 'expect'-like class
-class Expect:
+class Expect(threading.Thread):
proc = None
echo = False
trace_enabled = False
- name = ""
inst_param = None
rh = re.compile(const.DESTROYED)
ra = re.compile(const.ASSERT, re.I)
rr = re.compile(const.STDOUT_REFRESH)
t0 = time.time()
+ 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
+
+ def run(self):
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() == 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)
self.proc.stdin.writelines(cmd + "\n")
self.proc.stdin.flush()
+
def expect(self, pattern, raise_on_error=True, title=""):
self.trace("expect " + pattern)
r = re.compile(pattern, re.I)
- refresh_cnt = 0
- while True:
- line = self.proc.stdout.readline()
- if line == "":
- raise inc.TestError(self.name + ": Premature EOF")
- # Print the line if echo is ON
- if self.echo:
- print self.name + ": " + line.rstrip()
- # Trap assertion error
- if self.ra.search(line) != None:
+ 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:
- raise inc.TestError(self.name + ": " + line)
- else:
- return None
- # Count stdout refresh text.
- if self.rr.search(line) != None:
- refresh_cnt = refresh_cnt+1
- if refresh_cnt >= 6:
+ if self.ra.search(line) != None:
+ self.lock.release()
+ raise inc.TestError(self.name + ": " + line)
+
+ self.output = '\n'.join(lines[found_at+1:]) 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 > 15:
self.trace("Timed-out!")
if raise_on_error:
raise inc.TestError(self.name + " " + title + ": Timeout expecting pattern: \"" + pattern + "\"")
- else:
- return None # timeout
- # Search for expected text
- if r.search(line) != None:
- return line
+ break
+ else:
+ time.sleep(0.01)
+ return None
+
def sync_stdout(self):
self.trace("sync_stdout")
@@ -171,6 +208,7 @@ class Expect:
def wait(self):
self.trace("wait")
+ self.join()
self.proc.communicate()
def trace(self, s):
@@ -206,6 +244,7 @@ def handle_error(errmsg, t, close_processes = True):
p.wait()
else:
p.wait()
+
print "Test completed with error: " + errmsg
sys.exit(1)
@@ -240,17 +279,32 @@ 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
+ while True:
+ try:
+ p.send("echo 1")
+ except:
+ time.sleep(0.1)
+ continue
+ break
+
+ # add running instance
+ script.test.process.append(p)
+
+for p in script.test.process:
+ try:
# Wait until registration completes
- if inst_param.have_reg:
- p.expect(inst_param.uri+".*registration success")
+ if p.inst_param.have_reg:
+ p.expect(p.inst_param.uri+".*registration success")
# Synchronize stdout
p.send("")
p.expect(const.PROMPT)
p.send("echo 1")
- p.send("echo 1")
p.expect("echo 1")
- # add running instance
- script.test.process.append(p)
except inc.TestError, e:
handle_error(e.desc, script.test)
@@ -261,9 +315,10 @@ if script.test.test_func != None:
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
-time.sleep(2)
for p in script.test.process:
# Unregister if we have_reg to make sure that next tests
# won't wail
@@ -271,9 +326,11 @@ for p in script.test.process:
p.send("ru")
p.expect(p.inst_param.uri+".*unregistration success")
p.send("q")
- p.send("q")
- time.sleep(0.5)
- p.expect(const.DESTROYED, False)
+
+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
diff --git a/tests/pjsua/scripts-sipp/uas-reinv-with-less-media.py b/tests/pjsua/scripts-sipp/uas-reinv-with-less-media.py
index 42b2b881..83ba3997 100644
--- a/tests/pjsua/scripts-sipp/uas-reinv-with-less-media.py
+++ b/tests/pjsua/scripts-sipp/uas-reinv-with-less-media.py
@@ -5,4 +5,6 @@ import inc_const as const
PJSUA = ["--null-audio --extra-audio --max-calls=1 $SIPP_URI"]
# Send hold after remote holds (double hold)
-PJSUA_EXPECTS = [[0, const.MEDIA_HOLD, "H"]]
+PJSUA_EXPECTS = [[0, const.MEDIA_HOLD, ""],
+ [0, "ACK sip:", "H"]
+ ]