Benny Prijono | 4b4adb3 | 2008-06-12 15:37:22 +0000 | [diff] [blame] | 1 | # $Id$
|
| 2 | import sys
|
| 3 | import imp
|
| 4 | import re
|
| 5 | import subprocess
|
| 6 | import time
|
| 7 |
|
| 8 | import inc_param as param
|
| 9 | import inc_const as const
|
| 10 |
|
| 11 | # Defaults
|
| 12 | G_ECHO=True
|
| 13 | G_TRACE=False
|
| 14 | G_EXE="..\\..\\bin\\pjsua_vc6d.exe"
|
| 15 |
|
| 16 | ###################################
|
| 17 | # TestError exception
|
| 18 | class TestError:
|
| 19 | desc = ""
|
| 20 | def __init__(self, desc):
|
| 21 | self.desc = desc
|
| 22 |
|
| 23 | ###################################
|
| 24 | # Poor man's 'expect'-like class
|
| 25 | class Expect:
|
| 26 | proc = None
|
| 27 | echo = False
|
| 28 | trace_enabled = False
|
| 29 | name = ""
|
| 30 | rh = re.compile(const.DESTROYED)
|
| 31 | ra = re.compile(const.ASSERT, re.I)
|
| 32 | rr = re.compile(const.STDOUT_REFRESH)
|
| 33 | def __init__(self, name, exe, args="", echo=G_ECHO, trace_enabled=G_TRACE):
|
| 34 | self.name = name
|
| 35 | self.echo = echo
|
| 36 | self.trace_enabled = trace_enabled
|
| 37 | fullcmd = exe + " " + args + " --stdout-refresh=5 --stdout-refresh-text=" + const.STDOUT_REFRESH
|
| 38 | self.trace("Popen " + fullcmd)
|
| 39 | self.proc = subprocess.Popen(fullcmd, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
|
| 40 | def send(self, cmd):
|
| 41 | self.trace("send " + cmd)
|
| 42 | self.proc.stdin.writelines(cmd + "\n")
|
| 43 | def expect(self, pattern, raise_on_error=True):
|
| 44 | self.trace("expect " + pattern)
|
| 45 | r = re.compile(pattern, re.I)
|
| 46 | refresh_cnt = 0
|
| 47 | while True:
|
| 48 | line = self.proc.stdout.readline()
|
| 49 | if line == "":
|
Benny Prijono | a8a144c | 2008-06-12 19:13:51 +0000 | [diff] [blame^] | 50 | raise TestError(self.name + ": Premature EOF")
|
Benny Prijono | 4b4adb3 | 2008-06-12 15:37:22 +0000 | [diff] [blame] | 51 | # Print the line if echo is ON
|
| 52 | if self.echo:
|
| 53 | print self.name + ": " + line,
|
| 54 | # Trap assertion error
|
| 55 | if self.ra.search(line) != None:
|
Benny Prijono | a8a144c | 2008-06-12 19:13:51 +0000 | [diff] [blame^] | 56 | if raise_on_error:
|
| 57 | raise TestError(self.name + ": " + line)
|
| 58 | else:
|
| 59 | return None
|
Benny Prijono | 4b4adb3 | 2008-06-12 15:37:22 +0000 | [diff] [blame] | 60 | # Count stdout refresh text.
|
| 61 | if self.rr.search(line) != None:
|
| 62 | refresh_cnt = refresh_cnt+1
|
| 63 | if refresh_cnt >= 6:
|
| 64 | self.trace("Timed-out!")
|
| 65 | if raise_on_error:
|
Benny Prijono | a8a144c | 2008-06-12 19:13:51 +0000 | [diff] [blame^] | 66 | raise TestError(self.name + ": Timeout expecting pattern: " + pattern)
|
Benny Prijono | 4b4adb3 | 2008-06-12 15:37:22 +0000 | [diff] [blame] | 67 | else:
|
| 68 | return None # timeout
|
| 69 | # Search for expected text
|
| 70 | if r.search(line) != None:
|
| 71 | return line
|
| 72 | def wait(self):
|
| 73 | self.trace("wait")
|
| 74 | self.proc.wait()
|
| 75 | def trace(self, s):
|
| 76 | if self.trace_enabled:
|
| 77 | print self.name + ": " + "====== " + s + " ======"
|
| 78 |
|
| 79 | #########################
|
| 80 | # Error handling
|
| 81 | def handle_error(errmsg, t):
|
| 82 | print "====== Caught error: " + errmsg + " ======"
|
| 83 | time.sleep(1)
|
| 84 | for p in t.process:
|
| 85 | p.send("q")
|
Benny Prijono | a8a144c | 2008-06-12 19:13:51 +0000 | [diff] [blame^] | 86 | p.expect(const.DESTROYED, False)
|
Benny Prijono | 4b4adb3 | 2008-06-12 15:37:22 +0000 | [diff] [blame] | 87 | p.wait()
|
| 88 | print "Test completed with error: " + errmsg
|
| 89 | sys.exit(1)
|
| 90 |
|
| 91 |
|
| 92 | #########################
|
| 93 | # MAIN
|
| 94 |
|
| 95 | if len(sys.argv)!=3:
|
| 96 | print "Usage: run.py MODULE CONFIG"
|
| 97 | print "Sample:"
|
| 98 | print " run.py mod_run.py scripts-run/100_simple.py"
|
| 99 | sys.exit(1)
|
| 100 |
|
| 101 |
|
| 102 | # Import the test script
|
| 103 | script = imp.load_source("script", sys.argv[1])
|
| 104 |
|
| 105 | # Validate
|
| 106 | if script.test == None:
|
| 107 | print "Error: no test defined"
|
| 108 | sys.exit(1)
|
| 109 |
|
| 110 | if len(script.test.run) == 0:
|
| 111 | print "Error: test doesn't contain pjsua run descriptions"
|
| 112 | sys.exit(1)
|
| 113 |
|
| 114 | # Instantiate pjsuas
|
| 115 | print "====== Running " + script.test.title + " ======"
|
| 116 | for run in script.test.run:
|
| 117 | try:
|
| 118 | p = Expect(run.name, G_EXE, args=run.args, echo=run.echo, trace_enabled=run.trace)
|
| 119 | # Wait until initialized
|
| 120 | p.expect(const.PROMPT)
|
| 121 | p.send("echo 1")
|
| 122 | p.send("echo 1")
|
Benny Prijono | a8a144c | 2008-06-12 19:13:51 +0000 | [diff] [blame^] | 123 | p.expect("echo 1")
|
Benny Prijono | 4b4adb3 | 2008-06-12 15:37:22 +0000 | [diff] [blame] | 124 | # add running instance
|
| 125 | script.test.process.append(p)
|
| 126 | # run initial script
|
| 127 | for cmd in run.cmds:
|
| 128 | if len(cmd) >= 3 and cmd[2]!="":
|
| 129 | print "====== " + cmd[2] + " ======"
|
| 130 | if len(cmd) >= 1 and cmd[0]!="":
|
| 131 | p.send(cmd[0])
|
| 132 | if len(cmd) >= 2 and cmd[1]!="":
|
| 133 | p.expect(cmd[1])
|
| 134 |
|
| 135 | except TestError, e:
|
| 136 | handle_error(e.desc, script.test)
|
| 137 |
|
| 138 | # Run the test function
|
| 139 | if script.test.test_func != None:
|
| 140 | try:
|
| 141 | script.test.test_func(script.test)
|
| 142 | except TestError, e:
|
| 143 | handle_error(e.desc, script.test)
|
| 144 |
|
| 145 | # Shutdown all instances
|
| 146 | time.sleep(2)
|
| 147 | for p in script.test.process:
|
| 148 | p.send("q")
|
| 149 | time.sleep(0.5)
|
Benny Prijono | a8a144c | 2008-06-12 19:13:51 +0000 | [diff] [blame^] | 150 | p.expect(const.DESTROYED, False)
|
Benny Prijono | 4b4adb3 | 2008-06-12 15:37:22 +0000 | [diff] [blame] | 151 | p.wait()
|
| 152 |
|
| 153 | # Done
|
| 154 | print "Test " + script.test.title + " completed successfully"
|
| 155 | sys.exit(0)
|
| 156 |
|