|
|
@ -34,10 +34,12 @@ import multiprocessing |
|
|
|
import os |
|
|
|
import os |
|
|
|
import platform |
|
|
|
import platform |
|
|
|
import signal |
|
|
|
import signal |
|
|
|
|
|
|
|
import string |
|
|
|
import subprocess |
|
|
|
import subprocess |
|
|
|
import sys |
|
|
|
import sys |
|
|
|
import tempfile |
|
|
|
import tempfile |
|
|
|
import time |
|
|
|
import time |
|
|
|
|
|
|
|
import xml.etree.cElementTree as ET |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_DEFAULT_MAX_JOBS = 16 * multiprocessing.cpu_count() |
|
|
|
_DEFAULT_MAX_JOBS = 16 * multiprocessing.cpu_count() |
|
|
@ -159,7 +161,7 @@ class JobSpec(object): |
|
|
|
class Job(object): |
|
|
|
class Job(object): |
|
|
|
"""Manages one job.""" |
|
|
|
"""Manages one job.""" |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, spec, bin_hash, newline_on_success, travis): |
|
|
|
def __init__(self, spec, bin_hash, newline_on_success, travis, xml_report): |
|
|
|
self._spec = spec |
|
|
|
self._spec = spec |
|
|
|
self._bin_hash = bin_hash |
|
|
|
self._bin_hash = bin_hash |
|
|
|
self._tempfile = tempfile.TemporaryFile() |
|
|
|
self._tempfile = tempfile.TemporaryFile() |
|
|
@ -176,19 +178,27 @@ class Job(object): |
|
|
|
self._state = _RUNNING |
|
|
|
self._state = _RUNNING |
|
|
|
self._newline_on_success = newline_on_success |
|
|
|
self._newline_on_success = newline_on_success |
|
|
|
self._travis = travis |
|
|
|
self._travis = travis |
|
|
|
|
|
|
|
self._xml_test = ET.SubElement(xml_report, 'testcase', |
|
|
|
|
|
|
|
name=self._spec.shortname) if xml_report is not None else None |
|
|
|
message('START', spec.shortname, do_newline=self._travis) |
|
|
|
message('START', spec.shortname, do_newline=self._travis) |
|
|
|
|
|
|
|
|
|
|
|
def state(self, update_cache): |
|
|
|
def state(self, update_cache): |
|
|
|
"""Poll current state of the job. Prints messages at completion.""" |
|
|
|
"""Poll current state of the job. Prints messages at completion.""" |
|
|
|
if self._state == _RUNNING and self._process.poll() is not None: |
|
|
|
if self._state == _RUNNING and self._process.poll() is not None: |
|
|
|
elapsed = time.time() - self._start |
|
|
|
elapsed = time.time() - self._start |
|
|
|
|
|
|
|
self._tempfile.seek(0) |
|
|
|
|
|
|
|
stdout = self._tempfile.read() |
|
|
|
|
|
|
|
filtered_stdout = filter(lambda x: x in string.printable, stdout.decode(errors='ignore')) |
|
|
|
|
|
|
|
if self._xml_test is not None: |
|
|
|
|
|
|
|
self._xml_test.set('time', str(elapsed)) |
|
|
|
|
|
|
|
ET.SubElement(self._xml_test, 'system-out').text = filtered_stdout |
|
|
|
if self._process.returncode != 0: |
|
|
|
if self._process.returncode != 0: |
|
|
|
self._state = _FAILURE |
|
|
|
self._state = _FAILURE |
|
|
|
self._tempfile.seek(0) |
|
|
|
|
|
|
|
stdout = self._tempfile.read() |
|
|
|
|
|
|
|
message('FAILED', '%s [ret=%d, pid=%d]' % ( |
|
|
|
message('FAILED', '%s [ret=%d, pid=%d]' % ( |
|
|
|
self._spec.shortname, self._process.returncode, self._process.pid), |
|
|
|
self._spec.shortname, self._process.returncode, self._process.pid), |
|
|
|
stdout, do_newline=True) |
|
|
|
stdout, do_newline=True) |
|
|
|
|
|
|
|
if self._xml_test is not None: |
|
|
|
|
|
|
|
ET.SubElement(self._xml_test, 'failure', message='Failure').text |
|
|
|
else: |
|
|
|
else: |
|
|
|
self._state = _SUCCESS |
|
|
|
self._state = _SUCCESS |
|
|
|
message('PASSED', '%s [time=%.1fsec]' % (self._spec.shortname, elapsed), |
|
|
|
message('PASSED', '%s [time=%.1fsec]' % (self._spec.shortname, elapsed), |
|
|
@ -200,6 +210,9 @@ class Job(object): |
|
|
|
stdout = self._tempfile.read() |
|
|
|
stdout = self._tempfile.read() |
|
|
|
message('TIMEOUT', self._spec.shortname, stdout, do_newline=True) |
|
|
|
message('TIMEOUT', self._spec.shortname, stdout, do_newline=True) |
|
|
|
self.kill() |
|
|
|
self.kill() |
|
|
|
|
|
|
|
if self._xml_test is not None: |
|
|
|
|
|
|
|
ET.SubElement(self._xml_test, 'system-out').text = stdout |
|
|
|
|
|
|
|
ET.SubElement(self._xml_test, 'error', message='Timeout') |
|
|
|
return self._state |
|
|
|
return self._state |
|
|
|
|
|
|
|
|
|
|
|
def kill(self): |
|
|
|
def kill(self): |
|
|
@ -212,7 +225,7 @@ class Jobset(object): |
|
|
|
"""Manages one run of jobs.""" |
|
|
|
"""Manages one run of jobs.""" |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, check_cancelled, maxjobs, newline_on_success, travis, |
|
|
|
def __init__(self, check_cancelled, maxjobs, newline_on_success, travis, |
|
|
|
stop_on_failure, cache): |
|
|
|
stop_on_failure, cache, xml_report): |
|
|
|
self._running = set() |
|
|
|
self._running = set() |
|
|
|
self._check_cancelled = check_cancelled |
|
|
|
self._check_cancelled = check_cancelled |
|
|
|
self._cancelled = False |
|
|
|
self._cancelled = False |
|
|
@ -224,6 +237,7 @@ class Jobset(object): |
|
|
|
self._cache = cache |
|
|
|
self._cache = cache |
|
|
|
self._stop_on_failure = stop_on_failure |
|
|
|
self._stop_on_failure = stop_on_failure |
|
|
|
self._hashes = {} |
|
|
|
self._hashes = {} |
|
|
|
|
|
|
|
self._xml_report = xml_report |
|
|
|
|
|
|
|
|
|
|
|
def start(self, spec): |
|
|
|
def start(self, spec): |
|
|
|
"""Start a job. Return True on success, False on failure.""" |
|
|
|
"""Start a job. Return True on success, False on failure.""" |
|
|
@ -250,7 +264,8 @@ class Jobset(object): |
|
|
|
self._running.add(Job(spec, |
|
|
|
self._running.add(Job(spec, |
|
|
|
bin_hash, |
|
|
|
bin_hash, |
|
|
|
self._newline_on_success, |
|
|
|
self._newline_on_success, |
|
|
|
self._travis)) |
|
|
|
self._travis, |
|
|
|
|
|
|
|
self._xml_report)) |
|
|
|
except: |
|
|
|
except: |
|
|
|
message('FAILED', spec.shortname) |
|
|
|
message('FAILED', spec.shortname) |
|
|
|
self._cancelled = True |
|
|
|
self._cancelled = True |
|
|
@ -324,11 +339,13 @@ def run(cmdlines, |
|
|
|
travis=False, |
|
|
|
travis=False, |
|
|
|
infinite_runs=False, |
|
|
|
infinite_runs=False, |
|
|
|
stop_on_failure=False, |
|
|
|
stop_on_failure=False, |
|
|
|
cache=None): |
|
|
|
cache=None, |
|
|
|
|
|
|
|
xml_report=None): |
|
|
|
js = Jobset(check_cancelled, |
|
|
|
js = Jobset(check_cancelled, |
|
|
|
maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS, |
|
|
|
maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS, |
|
|
|
newline_on_success, travis, stop_on_failure, |
|
|
|
newline_on_success, travis, stop_on_failure, |
|
|
|
cache if cache is not None else NoCache()) |
|
|
|
cache if cache is not None else NoCache(), |
|
|
|
|
|
|
|
xml_report) |
|
|
|
for cmdline in cmdlines: |
|
|
|
for cmdline in cmdlines: |
|
|
|
if not js.start(cmdline): |
|
|
|
if not js.start(cmdline): |
|
|
|
break |
|
|
|
break |
|
|
|