def test_numbers(self): result = v2.StreamResultToBytes(BytesIO()) packet = [] self.assertRaises(Exception, result._write_number, -1, packet) # noqa self.assertEqual([], packet) result._write_number(0, packet) self.assertEqual([b'\x00'], packet) del packet[:] result._write_number(63, packet) self.assertEqual([b'\x3f'], packet) del packet[:] result._write_number(64, packet) self.assertEqual([b'\x40\x40'], packet) del packet[:] result._write_number(16383, packet) self.assertEqual([b'\x7f\xff'], packet) del packet[:] result._write_number(16384, packet) self.assertEqual([b'\x80\x40', b'\x00'], packet) del packet[:] result._write_number(4194303, packet) self.assertEqual([b'\xbf\xff', b'\xff'], packet) del packet[:] result._write_number(4194304, packet) self.assertEqual([b'\xc0\x40\x00\x00'], packet) del packet[:] result._write_number(1073741823, packet) self.assertEqual([b'\xff\xff\xff\xff'], packet) del packet[:] self.assertRaises( Exception, result._write_number, # noqa 1073741824, packet) self.assertEqual([], packet)
def test_remove_tag(self): reference = io.BytesIO() stream = v2.StreamResultToBytes(reference) stream.status(test_id='test', test_status='inprogress', test_tags=set(['foo'])) stream.status(test_id='test', test_status='success', test_tags=set(['foo'])) stream = v2.StreamResultToBytes(self.original) stream.status(test_id='test', test_status='inprogress', test_tags=set(['foo'])) stream.status(test_id='test', test_status='success', test_tags=set(['foo', 'bar'])) self.original.seek(0) self.assertEqual( 0, pysubunit.tag_stream(self.original, self.filtered, ["-bar"])) self.assertEqual(reference.getvalue(), self.filtered.getvalue())
def test_route_code_and_file_content(self): content = BytesIO() v2.StreamResultToBytes(content).status(route_code='0', mime_type='text/plain', file_name='bar', file_bytes=b'foo') self.check_event(content.getvalue(), test_id=None, file_name='bar', route_code='0', mime_type='text/plain', file_bytes=b'foo')
def test_default(self): byte_stream = compat.BytesIO() stream = v2.StreamResultToBytes(byte_stream) stream.status(test_id="foo", test_status="inprogress") stream.status(test_id="foo", test_status="skip") output = self.run_command([], byte_stream.getvalue()) events = doubles.StreamResult() v2.ByteStreamToStreamResult(compat.BytesIO(output)).run(events) self.assertEqual([ ('status', 'foo', 'inprogress'), ('status', 'foo', 'skip'), ], [event[:3] for event in events._events])
def _list(self, test): test_ids, errors = testtools_run.list_test(test) try: fileno = self.stream.fileno() except Exception: fileno = None if fileno is not None: stream = os.fdopen(fileno, 'wb', 0) else: stream = self.stream result = v2.StreamResultToBytes(stream) for test_id in test_ids: result.status(test_id=test_id, test_status='exists') return result, errors
def _make_result(output, options, predicate): """Make the result that we'll send the test outcomes to.""" fixup_expected_failures = set() for path in options.fixup_expected_failures or (): fixup_expected_failures.update(pysubunit.read_test_list(path)) return testtools.StreamToExtendedDecorator( test_results.TestResultFilter( testtools.ExtendedToStreamDecorator( v2.StreamResultToBytes(output)), filter_error=options.error, filter_failure=options.failure, filter_success=options.success, filter_skip=options.skip, filter_xfail=options.xfail, filter_predicate=predicate, fixup_expected_failures=fixup_expected_failures))
def tag_stream(original, filtered, tags): """Alter tags on a stream. :param original: The input stream. :param filtered: The output stream. :param tags: The tags to apply. As in a normal stream - a list of 'TAG' or '-TAG' commands. A 'TAG' command will add the tag to the output stream, and override any existing '-TAG' command in that stream. Specifically: * A global 'tags: TAG' will be added to the start of the stream. * Any tags commands with -TAG will have the -TAG removed. A '-TAG' command will remove the TAG command from the stream. Specifically: * A 'tags: -TAG' command will be added to the start of the stream. * Any 'tags: TAG' command will have 'TAG' removed from it. Additionally, any redundant tagging commands (adding a tag globally present, or removing a tag globally removed) are stripped as a by-product of the filtering. :return: 0 """ new_tags, gone_tags = tags_to_new_gone(tags) source = v2.ByteStreamToStreamResult(original, non_subunit_name='stdout') class Tagger(testtools.CopyStreamResult): def status(self, **kwargs): tags = kwargs.get('test_tags') if not tags: tags = set() tags.update(new_tags) tags.difference_update(gone_tags) if tags: kwargs['test_tags'] = tags else: kwargs['test_tags'] = None super(Tagger, self).status(**kwargs) output = Tagger([v2.StreamResultToBytes(filtered)]) source.run(output) return 0
def test_add_tag(self): # Literal values to avoid set sort-order dependencies. Python code show # derivation. # reference = BytesIO() # stream = subunit.StreamResultToBytes(reference) # stream.status( # test_id='test', test_status='inprogress', # test_tags=set(['quux', 'foo'])) # stream.status( # test_id='test', test_status='success', # test_tags=set(['bar', 'quux', 'foo'])) reference = [ (b'\xb3)\x82\x17\x04test\x02\x04quux\x03foo\x05\x97n\x86\xb3)' b'\x83\x1b\x04test\x03\x03bar\x04quux\x03fooqn\xab)'), (b'\xb3)\x82\x17\x04test\x02\x04quux\x03foo\x05\x97n\x86\xb3)' b'\x83\x1b\x04test\x03\x04quux\x03foo\x03bar\xaf\xbd\x9d\xd6'), (b'\xb3)\x82\x17\x04test\x02\x04quux\x03foo\x05\x97n\x86\xb3)' b'\x83\x1b\x04test\x03\x04quux\x03bar\x03foo\x03\x04b\r'), (b'\xb3)\x82\x17\x04test\x02\x04quux\x03foo\x05\x97n\x86\xb3)' b'\x83\x1b\x04test\x03\x03bar\x03foo\x04quux\xd2\x18\x1bC'), (b'\xb3)\x82\x17\x04test\x02\x03foo\x04quux\xa6\xe1\xde\xec\xb3)' b'\x83\x1b\x04test\x03\x03foo\x04quux\x03bar\x08\xc2X\x83'), (b'\xb3)\x82\x17\x04test\x02\x03foo\x04quux\xa6\xe1\xde\xec\xb3)' b'\x83\x1b\x04test\x03\x03bar\x03foo\x04quux\xd2\x18\x1bC'), (b'\xb3)\x82\x17\x04test\x02\x03foo\x04quux\xa6\xe1\xde\xec\xb3)' b'\x83\x1b\x04test\x03\x03foo\x03bar\x04quux:\x05e\x80') ] stream = v2.StreamResultToBytes(self.original) stream.status(test_id='test', test_status='inprogress', test_tags=set(['foo'])) stream.status(test_id='test', test_status='success', test_tags=set(['foo', 'bar'])) self.original.seek(0) self.assertEqual( 0, pysubunit.tag_stream(self.original, self.filtered, ["quux"])) self.assertThat(reference, matchers.Contains(self.filtered.getvalue()))
def test_tags(self): byte_stream = compat.BytesIO() stream = v2.StreamResultToBytes(byte_stream) stream.status(test_id="foo", test_status="inprogress", test_tags=set(["a"])) stream.status(test_id="foo", test_status="success", test_tags=set(["a"])) stream.status(test_id="bar", test_status="inprogress") stream.status(test_id="bar", test_status="inprogress") stream.status(test_id="baz", test_status="inprogress", test_tags=set(["a"])) stream.status(test_id="baz", test_status="success", test_tags=set(["a"])) output = self.run_command(['-s', '--with-tag', 'a'], byte_stream.getvalue()) events = doubles.StreamResult() v2.ByteStreamToStreamResult(compat.BytesIO(output)).run(events) ids = set(event[1] for event in events._events) self.assertEqual(set(['foo', 'baz']), ids)
def test_smoke(self): output = os.path.join( self.useFixture(fixtures.TempDir()).path, 'output') stdin = io.BytesIO() stdout = io.StringIO() writer = v2.StreamResultToBytes(stdin) writer.startTestRun() writer.status('foo', 'success', set(['tag']), file_name='fred', file_bytes=b'abcdefg', eof=True, mime_type='text/plain') writer.stopTestRun() stdin.seek(0) _to_disk.to_disk(['-d', output], stdin=stdin, stdout=stdout) self.expectThat( os.path.join(output, 'foo/test.json'), matchers.FileContains( '{"details": ["fred"], "id": "foo", "start": null, ' '"status": "success", "stop": null, "tags": ["tag"]}')) self.expectThat(os.path.join(output, 'foo/fred'), matchers.FileContains('abcdefg'))
def run_tests_from_stream(input_stream, result, passthrough_stream=None, forward_stream=None, protocol_version=1, passthrough_subunit=True): """Run tests from a subunit input stream through 'result'. Non-test events - top level file attachments - are expected to be dropped by v2 StreamResults at the present time (as all the analysis code is in ExtendedTestResult API's), so to implement passthrough_stream they are diverted and copied directly when that is set. :param input_stream: A stream containing subunit input. :param result: A TestResult that will receive the test events. NB: This should be an ExtendedTestResult for v1 and a StreamResult for v2. :param passthrough_stream: All non-subunit input received will be sent to this stream. If not provided, uses the ``TestProtocolServer`` default, which is ``sys.stdout``. :param forward_stream: All subunit input received will be forwarded to this stream. If not provided, uses the ``TestProtocolServer`` default, which is to not forward any input. Do not set this when transforming the stream - items would be double-reported. :param protocol_version: What version of the subunit protocol to expect. :param passthrough_subunit: If True, passthrough should be as subunit otherwise unwrap it. Only has effect when forward_stream is None. (when forwarding as subunit non-subunit input is always turned into subunit) """ if 1 == protocol_version: test = pysubunit.ProtocolTestCase(input_stream, passthrough=passthrough_stream, forward=forward_stream) elif 2 == protocol_version: # In all cases we encapsulate unknown inputs. if forward_stream is not None: # Send events to forward_stream as subunit. forward_result = v2.StreamResultToBytes(forward_stream) # If we're passing non-subunit through, copy: if passthrough_stream is None: # Not passing non-test events - split them off to nothing. router = testtools.StreamResultRouter(forward_result) router.add_rule(testtools.StreamResult(), 'test_id', test_id=None) result = testtools.CopyStreamResult([router, result]) else: # otherwise, copy all events to forward_result result = testtools.CopyStreamResult([forward_result, result]) elif passthrough_stream is not None: # Route non-test events to passthrough_stream, unwrapping them for # display. if not passthrough_subunit: passthrough_result = test_results.CatFiles(passthrough_stream) else: passthrough_result = v2.StreamResultToBytes(passthrough_stream) result = testtools.StreamResultRouter(result) result.add_rule(passthrough_result, 'test_id', test_id=None) test = v2.ByteStreamToStreamResult(input_stream, non_subunit_name='stdout') else: raise Exception("Unknown protocol version.") result.startTestRun() test.run(result) result.stopTestRun()
def TAP2SubUnit(tap, output_stream): """Filter a TAP pipe into a subunit pipe. This should be invoked once per TAP script, as TAP scripts get mapped to a single runnable case with multiple components. :param tap: A tap pipe/stream/file object - should emit unicode strings. :param subunit: A pipe/stream/file object to write subunit results to. :return: The exit code to exit with. """ output = v2.StreamResultToBytes(output_stream) UTF8_TEXT = 'text/plain; charset=UTF8' BEFORE_PLAN = 0 AFTER_PLAN = 1 SKIP_STREAM = 2 state = BEFORE_PLAN plan_start = 1 plan_stop = 0 # Test data for the next test to emit test_name = None log = [] result = None def missing_test(plan_start): output.status(test_id='test %d' % plan_start, test_status='fail', runnable=False, mime_type=UTF8_TEXT, eof=True, file_name="tap meta", file_bytes=b"test missing from TAP output") def _emit_test(): "write out a test" if test_name is None: return if log: log_bytes = b'\n'.join(log_line.encode('utf8') for log_line in log) mime_type = UTF8_TEXT file_name = 'tap comment' eof = True else: log_bytes = None mime_type = None file_name = None eof = True del log[:] output.status(test_id=test_name, test_status=result, file_bytes=log_bytes, mime_type=mime_type, eof=eof, file_name=file_name, runnable=False) for line in tap: if state == BEFORE_PLAN: match = re.match("(\d+)\.\.(\d+)\s*(?:\#\s+(.*))?\n", line) if match: state = AFTER_PLAN _, plan_stop, comment = match.groups() plan_stop = int(plan_stop) if plan_start > plan_stop and plan_stop == 0: # skipped file state = SKIP_STREAM output.status(test_id='file skip', test_status='skip', file_bytes=comment.encode('utf8'), eof=True, file_name='tap comment') continue # not a plan line, or have seen one before match = re.match( "(ok|not ok)(?:\s+(\d+)?)?(?:\s+([^#]*[^#\s]+)\s*)?(?:\s+#\s+" "(TODO|SKIP|skip|todo)(?:\s+(.*))?)?\n", line) if match: # new test, emit current one. _emit_test() hits = match.groups() status, number, description, directive, directive_comment = hits if status == 'ok': result = 'success' else: result = "fail" if description is None: description = '' else: description = ' ' + description if directive is not None: if directive.upper() == 'TODO': result = 'xfail' elif directive.upper() == 'SKIP': result = 'skip' if directive_comment is not None: log.append(directive_comment) if number is not None: number = int(number) while plan_start < number: missing_test(plan_start) plan_start += 1 test_name = "test %d%s" % (plan_start, description) plan_start += 1 continue match = re.match("Bail out\!(?:\s*(.*))?\n", line) if match: reason, = match.groups() if reason is None: extra = '' else: extra = ' %s' % reason _emit_test() test_name = "Bail out!%s" % extra result = "fail" state = SKIP_STREAM continue match = re.match("\#.*\n", line) if match: log.append(line[:-1]) continue # Should look at buffering status and binding this to the prior result. output.status(file_bytes=line.encode('utf8'), file_name='stdout', mime_type=UTF8_TEXT) _emit_test() while plan_start <= plan_stop: # record missed tests missing_test(plan_start) plan_start += 1 return 0
def _make_result(self): output = BytesIO() return v2.StreamResultToBytes(output), output
def _make_result(self): return v2.StreamResultToBytes(BytesIO())
def test_passthrough(self): output = self.run_command([], b'hi thar') byte_stream = compat.BytesIO() stream = v2.StreamResultToBytes(byte_stream) stream.status(file_name="stdout", file_bytes=b'hi thar') self.assertEqual(byte_stream.getvalue(), output)