15 from __future__
import absolute_import
31 from tests
import _loader
32 from tests
import _result
36 """A context-managed file to redirect output to a byte array.
38 Use by invoking `start` (`__enter__`) and at some point invoking `stop`
39 (`__exit__`). At any point after the initial call to `start` call `output` to
40 get the current redirected output. Note that we don't currently use file
41 locking, so calling `output` between calls to `start` and `stop` may muddle
42 the result (you should only be doing this during a Python-handled interrupt as
43 a last ditch effort to provide output to the user).
46 _redirected_fd (int): File descriptor of file to redirect writes from.
47 _saved_fd (int): A copy of the original value of the redirected file
49 _into_file (TemporaryFile or None): File to which writes are redirected.
50 Only non-None when self is started.
59 """Get all output from the redirected-to file if it exists."""
67 """Start redirection of writes to the file descriptor."""
72 """Stop redirection of writes to the file descriptor."""
77 """Bypass the redirection and write directly to the original file.
80 value (str): What to write to the original file.
82 if six.PY3
and not isinstance(value, six.binary_type):
83 value = value.encode(
'ascii')
85 os.write(self._redirect_fd, value)
97 """Close any resources used by self not closed by stop()."""
101 class AugmentedCase(collections.namedtuple(
'AugmentedCase', [
'case',
'id'])):
102 """A test case with a guaranteed unique externally specified identifier.
105 case (unittest.TestCase): TestCase we're decorating with an additional
107 id (object): Any identifier that may be considered 'unique' for testing
114 return super(cls, AugmentedCase).
__new__(cls, case, id)
122 """Constructs the Runner object.
125 dedicated_threads: A bool indicates whether to spawn each unit test
126 in separate thread or not.
135 """See setuptools' test_runner setup argument for information."""
137 testcase_filter = os.getenv(
'GRPC_PYTHON_TESTRUNNER_FILTER')
139 for case
in _loader.iterate_suite_cases(suite):
140 if not testcase_filter
or case.id().startswith(testcase_filter):
141 filtered_cases.append(case)
148 case_id_by_case = dict((augmented_case.case, augmented_case.id)
149 for augmented_case
in augmented_cases)
150 result_out = moves.cStringIO()
152 result_out, id_map=
lambda case: case_id_by_case[case])
158 if signal_number == signal.SIGINT:
160 signal.signal(signal_number, signal.SIG_DFL)
162 def fault_handler(signal_number, frame):
163 stdout_pipe.write_bypass(
164 'Received fault signal {}\nstdout:\n{}\n\nstderr:{}\n'.
format(
165 signal_number, stdout_pipe.output(), stderr_pipe.output()))
168 def check_kill_self():
170 stdout_pipe.write_bypass(
'Stopping tests short...')
172 stdout_pipe.write_bypass(result_out.getvalue())
173 stdout_pipe.write_bypass(
'\ninterrupted stdout:\n{}\n'.
format(
174 stdout_pipe.output().
decode()))
175 stderr_pipe.write_bypass(
'\ninterrupted stderr:\n{}\n'.
format(
176 stderr_pipe.output().
decode()))
179 def try_set_handler(name, handler):
181 signal.signal(getattr(signal, name), handler)
182 except AttributeError:
185 try_set_handler(
'SIGINT', sigint_handler)
186 try_set_handler(
'SIGBUS', fault_handler)
187 try_set_handler(
'SIGABRT', fault_handler)
188 try_set_handler(
'SIGFPE', fault_handler)
189 try_set_handler(
'SIGILL', fault_handler)
192 try_set_handler(
'SIGPIPE', signal.SIG_IGN)
195 result.startTestRun()
196 for augmented_case
in augmented_cases:
198 if skipped_test
in augmented_case.case.id():
201 sys.stdout.write(
'Running {}\n'.
format(
202 augmented_case.case.id()))
206 case_thread = threading.Thread(
207 target=augmented_case.case.run, args=(result,))
209 with stdout_pipe, stderr_pipe:
212 while case_thread.is_alive():
220 result.set_output(augmented_case.case, stdout_pipe.output(),
221 stderr_pipe.output())
222 sys.stdout.write(result_out.getvalue())
224 result_out.truncate(0)
228 augmented_case.case.run(result)
234 sys.stdout.write(result_out.getvalue())
236 signal.signal(signal.SIGINT, signal.SIG_DFL)
237 with open(
'report.xml',
'wb')
as report_xml_file:
238 _result.jenkins_junit_xml(result).
write(report_xml_file)