""" The LLVM Compiler Infrastructure This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details. """ from __future__ import print_function from __future__ import absolute_import # System modules import importlib import socket import sys # Third-party modules # LLDB modules # Ignore method count on DTOs. # pylint: disable=too-few-public-methods class FormatterConfig(object): """Provides formatter configuration info to create_results_formatter().""" def __init__(self): self.filename = None self.port = None self.formatter_name = None self.formatter_options = None # Ignore method count on DTOs. # pylint: disable=too-few-public-methods class CreatedFormatter(object): """Provides transfer object for returns from create_results_formatter().""" def __init__(self, formatter, cleanup_func): self.formatter = formatter self.cleanup_func = cleanup_func def create_results_formatter(config): """Sets up a test results formatter. @param config an instance of FormatterConfig that indicates how to setup the ResultsFormatter. @return an instance of CreatedFormatter. """ def create_socket(port): """Creates a socket to the localhost on the given port. @param port the port number of the listening port on the localhost. @return (socket object, socket closing function) """ def socket_closer(open_sock): """Close down an opened socket properly.""" open_sock.shutdown(socket.SHUT_RDWR) open_sock.close() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(("localhost", port)) # Wait for the ack from the listener side. # This is needed to prevent a race condition # in the main dosep.py processing loop: we # can't allow a worker queue thread to die # that has outstanding messages to a listener # socket before the listener socket asyncore # listener socket gets spun up; otherwise, # we lose the test result info. read_bytes = sock.recv(1) if read_bytes is None or (len(read_bytes) < 1) or (read_bytes != b'*'): raise Exception( "listening socket did not respond with ack byte: response={}".format(read_bytes)) return sock, lambda: socket_closer(sock) default_formatter_name = None results_file_object = None cleanup_func = None file_is_stream = False if config.filename: # Open the results file for writing. if config.filename == 'stdout': results_file_object = sys.stdout cleanup_func = None elif config.filename == 'stderr': results_file_object = sys.stderr cleanup_func = None else: results_file_object = open(config.filename, "w") cleanup_func = results_file_object.close default_formatter_name = ( "lldbsuite.test_event.formatter.xunit.XunitFormatter") elif config.port: # Connect to the specified localhost port. results_file_object, cleanup_func = create_socket(config.port) default_formatter_name = ( "lldbsuite.test_event.formatter.pickled.RawPickledFormatter") file_is_stream = True # If we have a results formatter name specified and we didn't specify # a results file, we should use stdout. if config.formatter_name is not None and results_file_object is None: # Use stdout. results_file_object = sys.stdout cleanup_func = None if results_file_object: # We care about the formatter. Choose user-specified or, if # none specified, use the default for the output type. if config.formatter_name: formatter_name = config.formatter_name else: formatter_name = default_formatter_name # Create an instance of the class. # First figure out the package/module. components = formatter_name.split(".") module = importlib.import_module(".".join(components[:-1])) # Create the class name we need to load. cls = getattr(module, components[-1]) # Handle formatter options for the results formatter class. formatter_arg_parser = cls.arg_parser() if config.formatter_options and len(config.formatter_options) > 0: command_line_options = config.formatter_options else: command_line_options = [] formatter_options = formatter_arg_parser.parse_args( command_line_options) # Create the TestResultsFormatter given the processed options. results_formatter_object = cls( results_file_object, formatter_options, file_is_stream) def shutdown_formatter(): """Shuts down the formatter when it is no longer needed.""" # Tell the formatter to write out anything it may have # been saving until the very end (e.g. xUnit results # can't complete its output until this point). results_formatter_object.send_terminate_as_needed() # And now close out the output file-like object. if cleanup_func is not None: cleanup_func() return CreatedFormatter( results_formatter_object, shutdown_formatter) else: return None