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()
|
|
|