242 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			242 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			Python
		
	
	
	
'''Backend for running tests and creating a Repository of testreports.'''
 | 
						|
import py
 | 
						|
import repository
 | 
						|
import util
 | 
						|
import threading
 | 
						|
 | 
						|
Null = util.Null
 | 
						|
 | 
						|
class TestRepository(repository.Repository):
 | 
						|
    '''stores only TestReport'''
 | 
						|
    ReportClass = util.TestReport
 | 
						|
    failed_id = [repr(ReportClass.Status.Failed())]
 | 
						|
    skipped_id = [repr(ReportClass.Status.Skipped())]    
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        super(TestRepository, self).__init__()
 | 
						|
        self.add([], self.ReportClass())
 | 
						|
        failedreport = self.ReportClass()
 | 
						|
        failedreport.full_id = self.failed_id
 | 
						|
        failedreport.label = 'Failed Tests'
 | 
						|
        self.add(self.failed_id, failedreport)
 | 
						|
        skippedreport = self.ReportClass()
 | 
						|
        skippedreport.full_id = self.skipped_id
 | 
						|
        skippedreport.label = 'Skipped Tests'
 | 
						|
        self.add(self.skipped_id, skippedreport)
 | 
						|
 | 
						|
    def root_status(self):
 | 
						|
        root_status = self.ReportClass.Status.NotExecuted()
 | 
						|
        if len(self.keys()) > 2:
 | 
						|
            root_status = self.ReportClass.Status.Passed()
 | 
						|
        if len(self.find_children(self.skipped_id)):
 | 
						|
            root_status = self.ReportClass.Status.Skipped()
 | 
						|
        if len(self.find_children(self.failed_id)):
 | 
						|
            root_status = self.ReportClass.Status.Failed()
 | 
						|
        return root_status
 | 
						|
 | 
						|
    def delete_all(self, key):
 | 
						|
        super(TestRepository, self).delete_all(key)
 | 
						|
        new_repos = TestRepository()
 | 
						|
        for new_key in new_repos.keys():
 | 
						|
            if not self.haskey(new_key):
 | 
						|
                self.add(new_key, new_repos.find(new_key))
 | 
						|
 | 
						|
    def delete(self, key):
 | 
						|
        super(TestRepository, self).delete(key)
 | 
						|
        new_repos = TestRepository()
 | 
						|
        if new_repos.haskey(key):
 | 
						|
            self.add(key, new_repos.find(key))
 | 
						|
 | 
						|
    def add_report(self, report):
 | 
						|
        if not report.full_id:
 | 
						|
            self.add([], report)
 | 
						|
            return
 | 
						|
        if report.error_report:
 | 
						|
            if report.status == self.ReportClass.Status.Failed():
 | 
						|
                self.add(self.failed_id + [report.id], report)
 | 
						|
            elif report.status == self.ReportClass.Status.Skipped():
 | 
						|
                self.add(self.skipped_id + [report.id], report)
 | 
						|
        self.add(report.full_id, report)
 | 
						|
 | 
						|
    def add_report_from_channel(self, report_str):
 | 
						|
        report = self.ReportClass.fromChannel(report_str)
 | 
						|
        self.add_report(report)
 | 
						|
        return report.full_id[:]
 | 
						|
 | 
						|
 | 
						|
class ReportStore:
 | 
						|
    ReportClass = util.TestReport
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        self._reports = repository.OrderedDict()
 | 
						|
        self._repository = TestRepository()
 | 
						|
        self.root = self.ReportClass()
 | 
						|
        #self.add(self.ReportClass())
 | 
						|
 | 
						|
    def add(self, report):
 | 
						|
        if not self._check_root(report):
 | 
						|
            #print '/'.join(report.full_id)
 | 
						|
            self._reports[report.full_id] = report
 | 
						|
        self._repository.add_report(report)
 | 
						|
        
 | 
						|
    def _check_root(self, report):
 | 
						|
        if report.id == self.ReportClass.root_id:
 | 
						|
            self.root = report
 | 
						|
            return True
 | 
						|
        else:
 | 
						|
            self.root.status.update(report.status)
 | 
						|
        return False
 | 
						|
 | 
						|
    def add_report_from_channel(self, report_str):
 | 
						|
        report = self.ReportClass.fromChannel(report_str)
 | 
						|
        self.add(report)
 | 
						|
        return report.full_id[:]
 | 
						|
    
 | 
						|
    def get(self, **kwargs):
 | 
						|
        # ensure failed > skipped > passed_item
 | 
						|
        filter_dict = repository.OrderedDict()
 | 
						|
        filter_dict['failed'] = self._select_failed
 | 
						|
        filter_dict['skipped']= self._select_skipped
 | 
						|
        filter_dict['passed_item']= self._select_passed_item
 | 
						|
        filter_dict['id']= self._select_by_id
 | 
						|
        
 | 
						|
        if kwargs.get('id', None) == tuple():
 | 
						|
            return [self.root]
 | 
						|
 | 
						|
        selected_reports = []
 | 
						|
        functions = [filter_dict[name] for name in kwargs.keys()
 | 
						|
                     if filter_dict.has_key(name)]
 | 
						|
        for function in functions:
 | 
						|
            selected_reports.extend([rep for rep in self._reports.values()
 | 
						|
                                     if function(rep, **kwargs)])
 | 
						|
        return selected_reports
 | 
						|
 | 
						|
    def _select_failed(self, report, **kwargs):
 | 
						|
        if kwargs['failed']:
 | 
						|
            return report.status == self.ReportClass.Status.Failed() and report.error_report != ''
 | 
						|
        return False
 | 
						|
    
 | 
						|
    def _select_skipped(self, report, **kwargs):
 | 
						|
        if kwargs['skipped']:
 | 
						|
            return report.status == self.ReportClass.Status.Skipped()
 | 
						|
        return False
 | 
						|
    
 | 
						|
    def _select_passed_item(self, report, **kwargs):
 | 
						|
        if kwargs['passed_item']:
 | 
						|
            return report.status == self.ReportClass.Status.Passed() and report.is_item == True
 | 
						|
        return False
 | 
						|
    
 | 
						|
    def _select_by_id(self, report, **kwargs):
 | 
						|
        id = kwargs['id']
 | 
						|
        return report.full_id == id
 | 
						|
 | 
						|
class ReportBackend:
 | 
						|
 | 
						|
    def __init__(self, config = Null()):
 | 
						|
        self.reportstore = ReportStore()
 | 
						|
        self.channel = Null()
 | 
						|
        self.waitfinish_thread = Null()
 | 
						|
        self.queue = py.std.Queue.Queue()
 | 
						|
        self._message_callback = Null()
 | 
						|
        self._messages_callback = Null()
 | 
						|
        self.config = config
 | 
						|
 | 
						|
    def running(self):
 | 
						|
        '''are there tests running?'''
 | 
						|
        if self.channel:
 | 
						|
            return not self.channel.isclosed()
 | 
						|
        return False
 | 
						|
    running = property(running)
 | 
						|
 | 
						|
    def shutdown(self):
 | 
						|
        if self.running:
 | 
						|
            self.channel.close()
 | 
						|
        if self.waitfinish_thread.isAlive():
 | 
						|
            self.waitfinish_thread.join()
 | 
						|
 | 
						|
    def get_store(self):
 | 
						|
        return self.reportstore
 | 
						|
 | 
						|
    def set_message_callback(self, callback = Null()):
 | 
						|
        self._message_callback = callback
 | 
						|
 | 
						|
    def set_messages_callback(self, callback = Null()):
 | 
						|
        self._messages_callback = callback
 | 
						|
 | 
						|
    def update(self):
 | 
						|
        """Check if there is something new in the queue."""
 | 
						|
        changed_report_ids = []
 | 
						|
        while not self.queue.empty():
 | 
						|
            try:
 | 
						|
                report_str = self.queue.get(False)
 | 
						|
                id = report_str
 | 
						|
                if report_str is not None:
 | 
						|
                    id = self.reportstore.add_report_from_channel(report_str)
 | 
						|
                changed_report_ids.append(id)
 | 
						|
                self._message_callback(id)
 | 
						|
            except py.std.Queue.Empty:
 | 
						|
                pass
 | 
						|
        self._messages_callback(changed_report_ids)
 | 
						|
 | 
						|
    def debug_queue_put(self, item):
 | 
						|
        report = ReportStore.ReportClass.fromChannel(item)
 | 
						|
        print '/'.join(report.full_id)
 | 
						|
        self.queue.put(item)
 | 
						|
        
 | 
						|
    def start_tests(self, config = None, args = [], tests = []):
 | 
						|
        py.test.skip("XXX fix this or remove --tkinter")
 | 
						|
        if self.running:
 | 
						|
            return
 | 
						|
        if config is None:
 | 
						|
            config = self.config
 | 
						|
        self.testrepository = TestRepository()
 | 
						|
        self.reportstore = ReportStore()
 | 
						|
        self.gateway = py.execnet.PopenGateway(config.option.executable) 
 | 
						|
        #self.channel = self.gateway.newchannel(receiver = self.queue.put)
 | 
						|
        self.channel = self.gateway.remote_exec(source = '''
 | 
						|
        import py
 | 
						|
        from py.__.test.tkinter.backend import remote
 | 
						|
 | 
						|
        args, tests = channel.receive()
 | 
						|
        remote(channel, tests = tests, args = args)
 | 
						|
        # why?
 | 
						|
        channel.close()
 | 
						|
        ''')
 | 
						|
        self.channel.setcallback(self.queue.put)
 | 
						|
        self.channel.send((args, tests))
 | 
						|
        self.waitfinish_thread = threading.Thread(target = waitfinish, args = (self.channel,))
 | 
						|
        self.waitfinish_thread.start()
 | 
						|
 | 
						|
def waitfinish(channel):
 | 
						|
    try:
 | 
						|
        while 1:
 | 
						|
            try:
 | 
						|
                channel.waitclose(0.5)
 | 
						|
            except (IOError, py.error.Error):
 | 
						|
                continue
 | 
						|
            break
 | 
						|
    finally:
 | 
						|
        try:
 | 
						|
            channel.gateway.exit()
 | 
						|
        except EOFError:
 | 
						|
            # the gateway receiver callback will get woken up
 | 
						|
            # and see an EOFError exception
 | 
						|
            pass
 | 
						|
            
 | 
						|
            
 | 
						|
                
 | 
						|
def remote(channel, tests = [], args = []):
 | 
						|
    import py
 | 
						|
    from py.__.test.tkinter.reportsession import ReportSession
 | 
						|
    from py.__.test.terminal.remote import getfailureitems
 | 
						|
    
 | 
						|
    config = py.test.config._reparse(args)
 | 
						|
    if tests: 
 | 
						|
        cols = getfailureitems(tests)
 | 
						|
    else:
 | 
						|
        cols = config.args 
 | 
						|
    session = ReportSession(config = config, channel=channel) 
 | 
						|
    session.shouldclose = channel.isclosed
 | 
						|
    session.main()
 | 
						|
    
 |