Example #1
0
class SampleController(object):
    def __init__(self, log):
        self.current_sample = None  # todo: recreate it from plugin's template every transaction
        self.success_count = None
        self.log = log
        self.test_count = 0
        self.success_count = 0
        self.apiritif_extractor = ApiritifSampleExtractor()
        self.tran_mode = False  # it's regular test (without smart transaction) by default
        self.start_time = None
        self.end_time = None
        self.test_info = {}

    def beforeTest(self):
        self.current_sample = Sample(
            test_case=self.test_info["test_case"],
            test_suite=self.test_info["suite_name"],
            start_time=time.time(),
            status="SKIPPED")
        self.current_sample.extras.update({
            "file": self.test_info["test_file"],
            "full_name": self.test_info["test_fqn"],
            "description": self.test_info["description"]
        })
        module_fqn_parts = self.test_info["module_fqn"].split('.')
        for item in module_fqn_parts[:-1]:
            self.current_sample.path.append(PathComponent("package", item))
        self.current_sample.path.append(PathComponent("module", module_fqn_parts[-1]))

        if "." in self.test_info["class_method"]:  # TestClass.test_method
            class_name, method_name = self.test_info["class_method"].split('.')[:2]
            self.current_sample.path.extend([
                PathComponent("class", class_name),
                PathComponent("method", method_name)])
        else:  # test_func
            self.current_sample.path.append(PathComponent("func", self.test_info["class_method"]))

        self.log.debug("Test method path: %r", self.current_sample.path)

        self.test_count += 1

    def startTest(self):
        self.start_time = time.time()

    def stopTest(self, is_transaction=False):
        if self.tran_mode == is_transaction:
            self.end_time = time.time()

    def addError(self, assertion_name, error_msg, error_trace, is_transaction=False):
        if self.tran_mode == is_transaction:
            self.current_sample.add_assertion(assertion_name, {"args": [], "kwargs": {}})
            self.current_sample.set_assertion_failed(assertion_name, error_msg, error_trace)

    def addFailure(self, error, is_transaction=False):
        if self.tran_mode == is_transaction:
            assertion_name = error[0].__name__
            error_msg = str(error[1]).split('\n')[0]
            error_trace = get_trace(error)
            self.current_sample.add_assertion(assertion_name, {"args": [], "kwargs": {}})
            self.current_sample.set_assertion_failed(assertion_name, error_msg, error_trace)

    def addSuccess(self, is_transaction=False):
        if self.tran_mode == is_transaction:
            self.current_sample.status = "PASSED"
            self.success_count += 1

    def afterTest(self, is_transaction=False):
        if self.tran_mode == is_transaction:
            if self.end_time is None:
                self.end_time = time.time()
            self.current_sample.duration = self.end_time - self.current_sample.start_time

            samples_processed = self._process_apiritif_samples(self.current_sample)
            if not samples_processed:
                self._process_sample(self.current_sample)

            self.current_sample = None

    def _process_apiritif_samples(self, sample):
        samples = []

        # get list of events
        recording = apiritif.recorder.pop_events(from_ts=self.start_time, to_ts=self.end_time)

        try:
            if recording:
                # convert requests (events) to samples
                samples = self.apiritif_extractor.parse_recording(recording, sample)
        except BaseException as exc:
            self.log.debug("Couldn't parse recording: %s", traceback.format_exc())
            self.log.warning("Couldn't parse recording: %s", exc)

        for sample in samples:
            self._process_sample(sample)  # just write to disk

        return len(samples)

    def _process_sample(self, sample):
        writer.add(sample, self.test_count, self.success_count)
Example #2
0
class RecordingPlugin(object):
    def __init__(self, report_path):
        self._report_path = report_path
        self._report_fds = None
        self.test_count = 0
        self.failed_tests = 0
        self.passed_tests = 0
        self._sample = None
        self.start_time = None
        self.end_time = None
        self.apiritif_extractor = ApiritifSampleExtractor()

    def prepare(self):
        if self._report_fds is None:
            self._report_fds = open(self._report_path, 'w')

    def post_process(self):
        if self._report_fds is not None:
            self._report_fds.close()
            self._report_fds = None

    def _write_sample(self, sample):
        if self._report_fds is None:
            raise ValueError("Plugin wasn't prepared")

        self._report_fds.write("%s\n" % json.dumps(sample.to_dict()))
        self._report_fds.flush()

    def _write_stdout_report(self, label):
        report_pattern = "%s,Total:%d Passed:%d Failed:%d\n"
        sys.stdout.write(report_pattern % (label, self.test_count, self.passed_tests, self.failed_tests))
        sys.stdout.flush()

    def _fill_sample(self, report, call, item, status):
        filename, lineno, _ = report.location

        if self._sample is None:
            self._sample = Sample()
            self._sample.test_case = item.name
            self._sample.test_suite = item.module.__name__
            self._sample.start_time = call.start
            self._sample.extras = {"filename": filename, "lineno": lineno}

        self._sample.status = status
        self._sample.duration = time.time() - self._sample.start_time

        if call.excinfo is not None:
            self._sample.error_msg = call.excinfo.exconly().strip()
            self._sample.error_trace = "\n".join(traceback.format_tb(call.excinfo.tb)).strip()
            if call.excinfo.errisinstance(AssertionError):
                self._sample.add_assertion(call.excinfo.exconly())
                self._sample.set_assertion_failed(call.excinfo.exconly(), str(call.excinfo.value),
                                                  str(call.excinfo.getrepr(style="native")))

    def _report_sample(self, label):
        if self._sample.status == "PASSED":
            self.passed_tests += 1
        elif self._sample.status in ["BROKEN", "FAILED"]:
            self.failed_tests += 1

        samples_processed = self._process_apiritif_samples(self._sample, label)
        if not samples_processed:
            self._process_sample(self._sample, label)

        self._sample = None

    def _process_sample(self, sample, label):
        self._write_sample(sample)
        self._write_stdout_report(label)

    def _process_apiritif_samples(self, sample, label):
        samples_processed = 0

        recording = apiritif.recorder.pop_events(from_ts=self.start_time, to_ts=self.end_time)
        if not recording:
            return samples_processed

        try:
            samples = self.apiritif_extractor.parse_recording(recording, sample)
        except BaseException as exc:
            print("Warning: Couldn't parse recording: %s" % exc)
            samples = []

        for sample in samples:
            samples_processed += 1
            self._process_sample(sample, label)

        return samples_processed

    @pytest.mark.hookwrapper
    def pytest_runtest_makereport(self, item, call):
        outcome = (yield)
        report = outcome.get_result()
        filename, lineno, test_name = report.location
        if report.when == 'call':
            if report.passed:
                self._fill_sample(report, call, item, "PASSED")
            elif report.failed:
                self._fill_sample(report, call, item, "FAILED")
            elif report.skipped:
                self._fill_sample(report, call, item, "SKIPPED")
        elif report.when == 'setup':
            self.test_count += 1
            self.start_time = time.time()
            if report.failed:
                self._fill_sample(report, call, item, "BROKEN")
            elif report.skipped:
                self._fill_sample(report, call, item, "SKIPPED")
        elif report.when == 'teardown':
            if not report.passed:
                if self._sample.status not in ["FAILED", "BROKEN"]:
                    self._fill_sample(report, call, item, "BROKEN")
                else:
                    self._sample.status = "BROKEN"
            self.end_time = time.time()
            self._report_sample(test_name)
Example #3
0
class ApiritifPlugin(Plugin):
    """
    Saves test results in a format suitable for Taurus.
    :type sample_writer: LDJSONSampleWriter
    """

    name = 'apiritif'
    enabled = False

    def __init__(self, sample_writer):
        super(ApiritifPlugin, self).__init__()
        self.sample_writer = sample_writer
        self.test_count = 0
        self.success_count = 0
        self.current_sample = None
        self.apiritif_extractor = ApiritifSampleExtractor()
        self.start_time = None
        self.end_time = None

    def finalize(self, result):
        """
        After all tests
        """
        if not self.test_count:
            raise RuntimeError("Nothing to test.")

    def beforeTest(self, test):
        """
        before test run
        """
        addr = test.address(
        )  # file path, package.subpackage.module, class.method
        test_file, module_fqn, class_method = addr
        test_fqn = test.id()  # [package].module.class.method
        suite_name, case_name = test_fqn.split('.')[-2:]
        log.debug("Addr: %r", addr)
        log.debug("id: %r", test_fqn)

        if class_method is None:
            class_method = case_name

        self.current_sample = Sample(test_case=case_name,
                                     test_suite=suite_name,
                                     start_time=time.time(),
                                     status="SKIPPED")
        self.current_sample.extras.update({
            "file":
            test_file,
            "full_name":
            test_fqn,
            "description":
            test.shortDescription()
        })
        module_fqn_parts = module_fqn.split('.')
        for item in module_fqn_parts[:-1]:
            self.current_sample.path.append(PathComponent("package", item))
        self.current_sample.path.append(
            PathComponent("module", module_fqn_parts[-1]))

        if "." in class_method:  # TestClass.test_method
            class_name, method_name = class_method.split('.')[:2]
            self.current_sample.path.extend([
                PathComponent("class", class_name),
                PathComponent("method", method_name)
            ])
        else:  # test_func
            self.current_sample.path.append(PathComponent(
                "func", class_method))

        log.debug("Test method path: %r", self.current_sample.path)
        self.test_count += 1

    def startTest(self, test):
        self.start_time = time.time()

    def stopTest(self, test):
        self.end_time = time.time()

    def afterTest(self, test):
        """
        after the test has been run
        :param test:
        :return:
        """
        if self.end_time is None:
            self.end_time = time.time()
        self.current_sample.duration = self.end_time - self.current_sample.start_time

        samples_processed = self._process_apiritif_samples(self.current_sample)
        if not samples_processed:
            self._process_sample(self.current_sample)

        self.current_sample = None

    def _process_apiritif_samples(self, sample):
        samples_processed = 0

        recording = apiritif.recorder.pop_events(from_ts=self.start_time,
                                                 to_ts=self.end_time)
        if not recording:
            return samples_processed

        try:
            samples = self.apiritif_extractor.parse_recording(
                recording, sample)
        except BaseException as exc:
            log.debug("Couldn't parse recording: %s", traceback.format_exc())
            log.warning("Couldn't parse recording: %s", exc)
            samples = []

        for sample in samples:
            samples_processed += 1
            self._process_sample(sample)

        return samples_processed

    def _process_sample(self, sample):
        self.sample_writer.add(sample, self.test_count, self.success_count)

    def addError(self, test, error):
        """
        when a test raises an uncaught exception
        :param test:
        :param error:
        :return:
        """
        # test_dict will be None if startTest wasn't called (i.e. exception in setUp/setUpClass)
        # status=BROKEN
        if self.current_sample is not None:
            assertion_name = error[0].__name__
            error_msg = str(error[1]).split('\n')[0]
            error_trace = self._get_trace(error)
            self.current_sample.add_assertion(assertion_name)
            self.current_sample.set_assertion_failed(assertion_name, error_msg,
                                                     error_trace)

    @staticmethod
    def _get_trace(error):
        if sys.version > '3':
            # noinspection PyArgumentList
            exct, excv, trace = error
            if isinstance(excv, str):
                excv = exct(excv)
            lines = traceback.format_exception(exct, excv, trace, chain=True)
        else:
            lines = traceback.format_exception(*error)
        return ''.join(lines).rstrip()

    def addFailure(self, test, error):
        """
        when a test fails
        :param test:
        :param error:

        :return:
        """
        # status=FAILED
        assertion_name = error[0].__name__
        error_msg = str(error[1]).split('\n')[0]
        error_trace = self._get_trace(error)
        self.current_sample.add_assertion(assertion_name)
        self.current_sample.set_assertion_failed(assertion_name, error_msg,
                                                 error_trace)

    def addSkip(self, test):
        """
        when a test is skipped
        :param test:
        :return:
        """
        self.current_sample.status = "SKIPPED"

    def addSuccess(self, test):
        """
        when a test passes
        :param test:
        :return:
        """
        self.current_sample.status = "PASSED"
        self.success_count += 1
class RecordingPlugin(object):
    def __init__(self, report_path):
        self._report_path = report_path
        self._report_fds = None
        self.test_count = 0
        self.failed_tests = 0
        self.passed_tests = 0
        self._sample = None
        self.start_time = None
        self.end_time = None
        self.apiritif_extractor = ApiritifSampleExtractor()

    def prepare(self):
        if self._report_fds is None:
            self._report_fds = open(self._report_path, 'w')

    def post_process(self):
        if self._report_fds is not None:
            self._report_fds.close()
            self._report_fds = None

    def _write_sample(self, sample):
        if self._report_fds is None:
            raise ValueError("Plugin wasn't prepared")

        self._report_fds.write("%s\n" % json.dumps(sample.to_dict()))
        self._report_fds.flush()

    def _write_stdout_report(self, label):
        report_pattern = "%s,Total:%d Passed:%d Failed:%d\n"
        sys.stdout.write(
            report_pattern %
            (label, self.test_count, self.passed_tests, self.failed_tests))
        sys.stdout.flush()

    def _fill_sample(self, report, call, item, status):
        filename, lineno, _ = report.location

        if self._sample is None:
            self._sample = Sample()
            self._sample.test_case = item.name
            self._sample.test_suite = item.module.__name__
            self._sample.start_time = call.start
            self._sample.extras = {"filename": filename, "lineno": lineno}

        self._sample.status = status
        self._sample.duration = time.time() - self._sample.start_time

        if call.excinfo is not None:
            self._sample.error_msg = call.excinfo.exconly().strip()
            self._sample.error_trace = "\n".join(
                traceback.format_tb(call.excinfo.tb)).strip()
            if call.excinfo.errisinstance(AssertionError):
                self._sample.add_assertion(call.excinfo.exconly())
                self._sample.set_assertion_failed(
                    call.excinfo.exconly(), str(call.excinfo.value),
                    str(call.excinfo.getrepr(style="native")))

    def _report_sample(self, label):
        if self._sample.status == "PASSED":
            self.passed_tests += 1
        elif self._sample.status in ["BROKEN", "FAILED"]:
            self.failed_tests += 1

        samples_processed = self._process_apiritif_samples(self._sample, label)
        if not samples_processed:
            self._process_sample(self._sample, label)

        self._sample = None

    def _process_sample(self, sample, label):
        self._write_sample(sample)
        self._write_stdout_report(label)

    def _process_apiritif_samples(self, sample, label):
        samples_processed = 0

        recording = apiritif.recorder.pop_events(from_ts=self.start_time,
                                                 to_ts=self.end_time)
        if not recording:
            return samples_processed

        try:
            samples = self.apiritif_extractor.parse_recording(
                recording, sample)
        except BaseException as exc:
            print("Warning: Couldn't parse recording: %s" % exc)
            samples = []

        for sample in samples:
            samples_processed += 1
            self._process_sample(sample, label)

        return samples_processed

    @pytest.mark.hookwrapper
    def pytest_runtest_makereport(self, item, call):
        outcome = (yield)
        report = outcome.get_result()
        filename, lineno, test_name = report.location
        if report.when == 'call':
            if report.passed:
                self._fill_sample(report, call, item, "PASSED")
            elif report.failed:
                self._fill_sample(report, call, item, "FAILED")
            elif report.skipped:
                self._fill_sample(report, call, item, "SKIPPED")
        elif report.when == 'setup':
            self.test_count += 1
            self.start_time = time.time()
            if report.failed:
                self._fill_sample(report, call, item, "BROKEN")
            elif report.skipped:
                self._fill_sample(report, call, item, "SKIPPED")
        elif report.when == 'teardown':
            if not report.passed:
                if self._sample.status not in ["FAILED", "BROKEN"]:
                    self._fill_sample(report, call, item, "BROKEN")
                else:
                    self._sample.status = "BROKEN"
            self.end_time = time.time()
            self._report_sample(test_name)