Source code for kitty.data.report

# Copyright (C) 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
#
# This file is part of Kitty.
#
# Kitty is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# Kitty is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Kitty.  If not, see <http://www.gnu.org/licenses/>.
'''
This module defines the :class:`~kitty.data.report.Report` class
'''


[docs]class Report(object): ''' This class represent a report for a single test. This report may contain subreports from nested entities. :example: In this example, the report, generated by the controller, indicates failure. :: report = Report('Controller') report.add('generation time', 0) report.failed('target does not respond') ''' PASSED = 'passed' FAILED = 'failed' ERROR = 'error' allowed_statuses = [PASSED, FAILED, ERROR] reserved_keys = { 'status': 'set_status(status), success(), failed(reason) or error(reason)', 'failed': 'failed(reason)' }
[docs] def __init__(self, name, default_failed=False): ''' :param name: name of the report (or the issuer) :param default_failed: is the default status of the report failed (default: False) ''' self._data_fields = {} self._sub_reports = {} self._name = name self._default_failed = default_failed self.clear()
[docs] def clear(self): ''' Set the report to its defaults. This will clear the report, keeping only the name and setting the failure status to the default. ''' self._data_fields = {} self._sub_reports = {} self.set_status(Report.FAILED if self._default_failed else Report.PASSED) self.add('name', self._name) self.add('sub_reports', [])
[docs] def get_name(self): ''' :return: the name of the report ''' return self.get('name')
[docs] def passed(self): ''' Set the report status to PASSED ''' self.set_status(Report.PASSED) if 'reason' in self._data_fields: del self._data_fields['reason']
[docs] def success(self): ''' Set the report status to PASSED. .. deprecated:: 0.6.7 use :func:`~kitty.data.report.Report.passed` ''' self.passed()
[docs] def failed(self, reason=None): ''' Set the test status to Report.FAILED, and set the failure reason :param reason: failure reason (default: None) ''' self.set_status(Report.FAILED) if reason: self.add('reason', reason)
[docs] def error(self, reason=None): ''' Set the test status to Report.ERROR, and set the error reason :param reason: error reason (default: None) ''' self.set_status(Report.ERROR) if reason: self.add('reason', reason)
[docs] def set_status(self, new_status): ''' Set the status of the report. :param new_status: the new status of the report (either PASSED, FAILED or ERROR) ''' if new_status not in Report.allowed_statuses: raise Exception('status must be one of: %s' % (', '.join(Report.allowed_statuses))) self._data_fields['status'] = new_status.lower()
[docs] def add(self, key, value): ''' Add an entry to the report :param key: entry's key :param value: the actual value :example: :: my_report.add('retry count', 3) ''' if key in self.reserved_keys: raise Exception('You cannot add the key %s directly, use %s' % (key, self.reserved_keys[key])) if isinstance(value, Report): self._sub_reports[key] = value self._data_fields['sub_reports'].append(key) else: self._data_fields[key] = value
[docs] def get(self, key): ''' Get a value for a given key :param key: entry's key :return: corresponding value ''' if key in self._data_fields: return self._data_fields[key] if key in self._sub_reports: return self._sub_reports[key] return None
[docs] def to_dict(self, encoding='base64'): ''' Return a dictionary version of the report :param encoding: required encoding for the string values (default: 'base64') :rtype: dictionary :return: dictionary representation of the report ''' res = {} for k, v in self._data_fields.items(): if isinstance(v, unicode): v = v.encode('utf-8') if isinstance(v, str): v = v.encode(encoding)[:-1] res[k] = v for k, v in self._sub_reports.items(): res[k] = v.to_dict(encoding) return res
@classmethod def _decode(cls, val, encoding): if isinstance(val, str): val = val.decode(encoding) return val @classmethod
[docs] def from_dict(cls, d, encoding='base64'): ''' Construct a ``Report`` object from dictionary. :type d: dictionary :param d: dictionary representing the report :param encoding: encoding of strings in the dictionary (default: 'base64') :return: Report object ''' report = Report(Report._decode(d['name'], encoding)) report.set_status(Report._decode(d['status'], encoding)) sub_reports = Report._decode(d['sub_reports'], encoding) del d['sub_reports'] for k, v in d.items(): if k in sub_reports: report.add(k, Report.from_dict(v)) else: if k.lower() == 'status': report.set_status(Report._decode(v, encoding)) else: report.add(k, Report._decode(v, encoding)) return report
[docs] def get_status(self): ''' Get the status of the report and its sub-reports. :rtype: str :return: report status ('passed', 'failed' or 'error') ''' status = self.get('status') if status == Report.PASSED: for sr_name in self._sub_reports: sr = self._sub_reports[sr_name] sr_status = sr.get_status() reason = sr.get('reason') if sr_status == Report.ERROR: self.error(reason) break if sr_status == Report.FAILED: self.failed(reason) break status = self.get('status') return status
[docs] def is_failed(self): ''' .. deprecated:: 0.6.7 use :func:`~kitty.data.report.Report.get_status` ''' raise NotImplementedError('API was changed, use get_status instead')