testing/mozbase/mozprocess/tests/test_mozprocess.py

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:11a42d767970
1 #!/usr/bin/env python
2
3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 # You can obtain one at http://mozilla.org/MPL/2.0/.
6
7 import optparse
8 import os
9 import subprocess
10 import sys
11 import unittest
12 from mozprocess import processhandler
13 from time import sleep
14
15 here = os.path.dirname(os.path.abspath(__file__))
16
17 def make_proclaunch(aDir):
18 """
19 Makes the proclaunch executable.
20 Params:
21 aDir - the directory in which to issue the make commands
22 Returns:
23 the path to the proclaunch executable that is generated
24 """
25
26 if sys.platform == "win32":
27 exepath = os.path.join(aDir, "proclaunch.exe")
28 else:
29 exepath = os.path.join(aDir, "proclaunch")
30
31 # remove the launcher, if it already exists
32 # otherwise, if the make fails you may not notice
33 if os.path.exists(exepath):
34 os.remove(exepath)
35
36 # Ideally make should take care of both calls through recursion, but since it doesn't,
37 # on windows anyway (to file?), let's just call out both targets explicitly.
38 for command in [["make", "-C", "iniparser"],
39 ["make"]]:
40 process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=aDir)
41 stdout, stderr = process.communicate()
42 if process.returncode:
43 # SomethingBadHappen; print all the things
44 print "%s: exit %d" % (command, process.returncode)
45 print "stdout:\n%s" % stdout
46 print "stderr:\n%s" % stderr
47 raise subprocess.CalledProcessError(process.returncode, command, stdout)
48
49 # ensure the launcher now exists
50 if not os.path.exists(exepath):
51 raise AssertionError("proclaunch executable '%s' does not exist (sys.platform=%s)" % (exepath, sys.platform))
52 return exepath
53
54 def check_for_process(processName):
55 """
56 Use to determine if process of the given name is still running.
57
58 Returns:
59 detected -- True if process is detected to exist, False otherwise
60 output -- if process exists, stdout of the process, '' otherwise
61 """
62 # TODO: replace with
63 # https://github.com/mozilla/mozbase/blob/master/mozprocess/mozprocess/pid.py
64 # which should be augmented from talos
65 # see https://bugzilla.mozilla.org/show_bug.cgi?id=705864
66 output = ''
67 if sys.platform == "win32":
68 # On windows we use tasklist
69 p1 = subprocess.Popen(["tasklist"], stdout=subprocess.PIPE)
70 output = p1.communicate()[0]
71 detected = False
72 for line in output.splitlines():
73 if processName in line:
74 detected = True
75 break
76 else:
77 p1 = subprocess.Popen(["ps", "-ef"], stdout=subprocess.PIPE)
78 p2 = subprocess.Popen(["grep", processName], stdin=p1.stdout, stdout=subprocess.PIPE)
79 p1.stdout.close()
80 output = p2.communicate()[0]
81 detected = False
82 for line in output.splitlines():
83 if "grep %s" % processName in line:
84 continue
85 elif processName in line and not 'defunct' in line:
86 detected = True
87 break
88
89 return detected, output
90
91
92 class ProcTest(unittest.TestCase):
93
94 # whether to remove created files on exit
95 cleanup = os.environ.get('CLEANUP', 'true').lower() in ('1', 'true')
96
97 @classmethod
98 def setUpClass(cls):
99 cls.proclaunch = make_proclaunch(here)
100
101 @classmethod
102 def tearDownClass(cls):
103 del cls.proclaunch
104 if not cls.cleanup:
105 return
106 files = [('proclaunch',),
107 ('proclaunch.exe',),
108 ('iniparser', 'dictionary.o'),
109 ('iniparser', 'iniparser.lib'),
110 ('iniparser', 'iniparser.o'),
111 ('iniparser', 'libiniparser.a'),
112 ('iniparser', 'libiniparser.so.0'),
113 ]
114 files = [os.path.join(here, *path) for path in files]
115 errors = []
116 for path in files:
117 if os.path.exists(path):
118 try:
119 os.remove(path)
120 except OSError as e:
121 errors.append(str(e))
122 if errors:
123 raise OSError("Error(s) encountered tearing down %s.%s:\n%s" % (cls.__module__, cls.__name__, '\n'.join(errors)))
124
125 def test_process_normal_finish(self):
126 """Process is started, runs to completion while we wait for it"""
127
128 p = processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"],
129 cwd=here)
130 p.run()
131 p.wait()
132
133 detected, output = check_for_process(self.proclaunch)
134 self.determine_status(detected,
135 output,
136 p.proc.returncode,
137 p.didTimeout)
138
139 def test_commandline_no_args(self):
140 """Command line is reported correctly when no arguments are specified"""
141 p = processhandler.ProcessHandler(self.proclaunch, cwd=here)
142 self.assertEqual(p.commandline, self.proclaunch)
143
144 def test_commandline_overspecified(self):
145 """Command line raises an exception when the arguments are specified ambiguously"""
146 err = None
147 try:
148 p = processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"],
149 args=["1", "2", "3"],
150 cwd=here)
151 except TypeError, e:
152 err = e
153
154 self.assertTrue(err)
155
156 def test_commandline_from_list(self):
157 """Command line is reported correctly when command and arguments are specified in a list"""
158 p = processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"],
159 cwd=here)
160 self.assertEqual(p.commandline, self.proclaunch + ' process_normal_finish.ini')
161
162 def test_commandline_over_specified(self):
163 """Command line raises an exception when the arguments are specified ambiguously"""
164 err = None
165 try:
166 p = processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"],
167 args=["1", "2", "3"],
168 cwd=here)
169 except TypeError, e:
170 err = e
171
172 self.assertTrue(err)
173
174 def test_commandline_from_args(self):
175 """Command line is reported correctly when arguments are specified in a dedicated list"""
176 p = processhandler.ProcessHandler(self.proclaunch,
177 args=["1", "2", "3"],
178 cwd=here)
179 self.assertEqual(p.commandline, self.proclaunch + ' 1 2 3')
180
181 def test_process_wait(self):
182 """Process is started runs to completion while we wait indefinitely"""
183
184 p = processhandler.ProcessHandler([self.proclaunch,
185 "process_waittimeout_10s.ini"],
186 cwd=here)
187 p.run()
188 p.wait()
189
190 detected, output = check_for_process(self.proclaunch)
191 self.determine_status(detected,
192 output,
193 p.proc.returncode,
194 p.didTimeout)
195
196 def test_process_timeout(self):
197 """ Process is started, runs but we time out waiting on it
198 to complete
199 """
200 p = processhandler.ProcessHandler([self.proclaunch, "process_waittimeout.ini"],
201 cwd=here)
202 p.run(timeout=10)
203 p.wait()
204
205 detected, output = check_for_process(self.proclaunch)
206 self.determine_status(detected,
207 output,
208 p.proc.returncode,
209 p.didTimeout,
210 False,
211 ['returncode', 'didtimeout'])
212
213 def test_process_timeout_no_kill(self):
214 """ Process is started, runs but we time out waiting on it
215 to complete. Process should not be killed.
216 """
217 p = None
218 def timeout_handler():
219 self.assertEqual(p.proc.poll(), None)
220 p.kill()
221 p = processhandler.ProcessHandler([self.proclaunch, "process_waittimeout.ini"],
222 cwd=here,
223 onTimeout=(timeout_handler,),
224 kill_on_timeout=False)
225 p.run(timeout=1)
226 p.wait()
227 self.assertTrue(p.didTimeout)
228
229 detected, output = check_for_process(self.proclaunch)
230 self.determine_status(detected,
231 output,
232 p.proc.returncode,
233 p.didTimeout,
234 False,
235 ['returncode', 'didtimeout'])
236
237 def test_process_waittimeout(self):
238 """
239 Process is started, then wait is called and times out.
240 Process is still running and didn't timeout
241 """
242 p = processhandler.ProcessHandler([self.proclaunch,
243 "process_waittimeout_10s.ini"],
244 cwd=here)
245
246 p.run()
247 p.wait(timeout=5)
248
249 detected, output = check_for_process(self.proclaunch)
250 self.determine_status(detected,
251 output,
252 p.proc.returncode,
253 p.didTimeout,
254 True,
255 ())
256
257 def test_process_waitnotimeout(self):
258 """ Process is started, runs to completion before our wait times out
259 """
260 p = processhandler.ProcessHandler([self.proclaunch,
261 "process_waittimeout_10s.ini"],
262 cwd=here)
263 p.run(timeout=30)
264 p.wait()
265
266 detected, output = check_for_process(self.proclaunch)
267 self.determine_status(detected,
268 output,
269 p.proc.returncode,
270 p.didTimeout)
271
272 def test_process_kill(self):
273 """Process is started, we kill it"""
274
275 p = processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"],
276 cwd=here)
277 p.run()
278 p.kill()
279
280 detected, output = check_for_process(self.proclaunch)
281 self.determine_status(detected,
282 output,
283 p.proc.returncode,
284 p.didTimeout)
285
286 def test_process_output_twice(self):
287 """
288 Process is started, then processOutput is called a second time explicitly
289 """
290 p = processhandler.ProcessHandler([self.proclaunch,
291 "process_waittimeout_10s.ini"],
292 cwd=here)
293
294 p.run()
295 p.processOutput(timeout=5)
296 p.wait()
297
298 detected, output = check_for_process(self.proclaunch)
299 self.determine_status(detected,
300 output,
301 p.proc.returncode,
302 p.didTimeout,
303 False,
304 ())
305
306 def determine_status(self,
307 detected=False,
308 output='',
309 returncode=0,
310 didtimeout=False,
311 isalive=False,
312 expectedfail=()):
313 """
314 Use to determine if the situation has failed.
315 Parameters:
316 detected -- value from check_for_process to determine if the process is detected
317 output -- string of data from detected process, can be ''
318 returncode -- return code from process, defaults to 0
319 didtimeout -- True if process timed out, defaults to False
320 isalive -- Use True to indicate we pass if the process exists; however, by default
321 the test will pass if the process does not exist (isalive == False)
322 expectedfail -- Defaults to [], used to indicate a list of fields that are expected to fail
323 """
324 if 'returncode' in expectedfail:
325 self.assertTrue(returncode, "Detected an unexpected return code of: %s" % returncode)
326 elif not isalive:
327 self.assertTrue(returncode == 0, "Detected non-zero return code of: %d" % returncode)
328
329 if 'didtimeout' in expectedfail:
330 self.assertTrue(didtimeout, "Detected that process didn't time out")
331 else:
332 self.assertTrue(not didtimeout, "Detected that process timed out")
333
334 if isalive:
335 self.assertTrue(detected, "Detected process is not running, process output: %s" % output)
336 else:
337 self.assertTrue(not detected, "Detected process is still running, process output: %s" % output)
338
339 if __name__ == '__main__':
340 unittest.main()

mercurial