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