test_ok1/py/test/tkinter/backend.py

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