示例#1
0
    def coverage_stop(self, features, marker):
        """
        Stop the coverage measurement
        and create report
        """
        self.coverage.stop()
        self.coverage.combine()
        self.coverage.save()
        self.coverage.report(file=sys.stdout)

        if world.config.cover_html:
            self.coverage.html_report(directory=world.config.cover_html)

        if world.config.cover_xml:
            self.coverage.xml_report(outfile=world.config.cover_xml)

        if world.config.cover_min_percentage:
            report = StringIO()
            self.coverage.report(file=report)
            match = re.search(r'^TOTAL\s+(.*)$', report.getvalue(), re.MULTILINE)
            if not match:
                raise RadishError('Failed to find total percentage in coverage report')

            total_percentage = int(match.groups()[0].split()[-1][:-1])
            if total_percentage < int(world.config.cover_min_percentage):
                raise RadishError('Failed to reach minimum expected coverage of {0}% (reached: {1}%)'.format(
                    world.config.cover_min_percentage, total_percentage))
示例#2
0
    def __new__(
        mcs,
        name: str,
        bases: Tuple[Type],
        classdict: Dict[str, Any],
    ):
        resources = {
            attr: value
            for attr, value in classdict.items()
            if isinstance(value, _ResourceDescriptor)
        }

        for left, right in combinations(resources.values(), 2):
            if left.db == right.db and left.prefix == right.prefix:
                raise RadishError(
                    "There are namespace conflicts in the specified resources. Please "
                    f"provide explicit prefix parameters. Resources: {left}, {right}"
                )

        for attr in resources:
            del classdict[attr]
        if "_meta" in classdict:
            raise RadishError(
                "'_meta' is a reserved class property for `Interface` classes")
        cls: InterfaceMeta = cast(InterfaceMeta,
                                  type.__new__(mcs, name, bases, classdict))
        cls._meta = {"resources": resources}
        return cls
示例#3
0
    def serialize(self, instance: Model) -> bytes:
        """Serialize a model instance to be stored in Redis.

        :raises: :exc:`~radish.exceptions.RadishError` if the model instance
            is of an incorrect type.
        """
        if not type(instance) is self.model:
            if not isinstance(instance, self.model):
                raise RadishError(
                    "Instance type {type(instance)} does not match resource schema. "
                    f"Accepts {self.model}.")
            raise RadishError(
                f"Subclasses of {self.model} are not supported, as they will not "
                "be deserialized correctly.")

        return instance.json().encode("utf-8")
示例#4
0
    def __init__(self):
        try:
            from lxml import etree
        except ImportError:
            raise RadishError('if you want to use the JUnit xml writer you have to "pip install radish-bdd[junit-xml]"')

        after.all(self.generate_junit_xml)
示例#5
0
    def _validate(self):
        """
            Checks if the step is valid to run or not
        """

        if not self.definition_func or not callable(self.definition_func):
            raise RadishError(
                "The step '{0}' does not have a step definition".format(
                    self.sentence))
示例#6
0
    def failure_inspector(self, step):
        """
            Starts a python shell after a step failed
        """
        if step.state is not Step.State.FAILED:
            return

        try:
            from IPython import embed
        except ImportError as e:
            raise RadishError(
                "Cannot import IPython embed function: {0}".format(e))

        embed()
示例#7
0
    def process_user_data(self):
        """
            Process the user data
        """
        if self._cli_user_data:
            for pair in self._cli_user_data:
                try:
                    key, value = map(str.strip,
                                     self._kv_regex.split(pair, maxsplit=1))
                except ValueError as e:
                    msg = "-u/--user-data: User data is invalid. Expecting: 'key=value' Got: '{0}'"
                    raise RadishError(msg.format(pair))

                # Allowing all keys and values, even if empty
                world.config.user_data[key] = value
示例#8
0
    def failure_inspector(self, step):
        """
            Starts a python shell after a step failed
        """
        if step.state is not Step.State.FAILED:
            return

        try:
            from IPython import embed
        except ImportError as e:
            raise RadishError(
                'if you want to use the failure inspector extension you have to "pip install radish-bdd[ipython-debugger]"'
            )

        embed()
示例#9
0
    def __init__(self):
        try:
            from coverage import Coverage
        except ImportError:
            raise RadishError(
                'if you want to use the code coverage you have to "pip install radish-bdd[coverage]"'
            )

        before.all(self.coverage_start)
        after.all(self.coverage_stop)

        if world.config.cover_packages:
            self.cover_packages = world.config.cover_packages.split(",")
        else:
            self.cover_packages = []

        self.coverage = None
        self.modules_on_init = set(sys.modules.keys())
示例#10
0
    def __call__(self, **filter_kwargs) -> Callable[[Model], bool]:
        bad_kwargs = set(filter_kwargs) - set(self.target_model.__fields__)
        if bad_kwargs:
            raise RadishError(
                f"Invalid filter fields for {self.target_model}: {bad_kwargs}."
            )

        field_filters = {
            attr: value if callable(value) else equals(value)
            for attr, value in filter_kwargs.items()
        }

        def filter_func(instance: Model):
            return all(
                field_filter(getattr(instance, attr))
                for attr, field_filter in field_filters.items())

        return filter_func
示例#11
0
    async def save(self,
                   *instances: Model,
                   allow_update: bool = True,
                   expire: SupportsFloat = None) -> None:
        """Store one or more model instances in the Redis cache.

        .. code:: python

            await redis.users.save(User(id=1, name="bob"), User(id=2, name="frank"))

        :param instances: The set of model instances to store in the cache.
        :param allow_update: Whether to allow updates to existing records.
        :param expire: The number of seconds in which to expire te records.
        """
        if not allow_update:
            existing: List[bool] = await asyncio.gather(*[
                self.connection.exists(self.descriptor.get_key(instance))
                for instance in instances
            ])
            if any(existing):
                already_exists: List[Model] = [
                    instance for instance, exists in zip(instances, existing)
                    if exists
                ]
                raise RadishError(
                    f"Records for {repr(already_exists)} already exists")
        serialized_instances = [(self.descriptor.get_key(instance),
                                 self.descriptor.serialize(instance))
                                for instance in instances]
        await asyncio.gather(*[
            self.connection.set(key,
                                data,
                                pexpire=int(float(expire) *
                                            1000) if expire else None)
            for key, data in serialized_instances
        ])
示例#12
0
    def generate_ccjson(self, features, marker):
        """
            Generates the cucumber json
        """

        if not features:
            raise RadishError(
                "No features given to generate cucumber json file")

        duration = timedelta()
        for feature in features:
            if feature.state in [Step.State.PASSED, Step.State.FAILED]:
                duration += feature.duration

        ccjson = []
        for feature in features:
            if not feature.has_to_run(world.config.scenarios):
                continue
            feature_description = "\n".join(feature.description)
            feature_json = {
                "uri": feature.path,
                "type": "feature",
                "keyword": feature.keyword,
                "id": str(feature.id),
                "name": feature.sentence,
                "line": feature.line,
                "description": feature_description,
                "tags": [],
                "elements": []
            }
            for i, j in enumerate(feature.tags):
                feature_json["tags"].append({
                    "name":
                    "@" + j.name,
                    "line":
                    feature.line - len(feature.tags) + i
                })
            for scenario in (
                    s for s in feature.all_scenarios
                    if not isinstance(s, (ScenarioOutline, ScenarioLoop))):
                if not scenario.has_to_run(world.config.scenarios):
                    continue
                scenario_json = {
                    "keyword": scenario.keyword,
                    "type": "scenario",
                    "id": str(scenario.id),
                    "name": scenario.sentence,
                    "line": scenario.line,
                    "description": "",
                    "steps": [],
                    "tags": []
                }
                start_line_no = scenario.line - len(scenario.tags)
                for i, tag in enumerate(scenario.tags):
                    scenario_json["tags"].append({
                        "name": "@" + tag.name,
                        "line": start_line_no + i
                    })
                for step in scenario.all_steps:
                    # round duration to 10 decimal points, to avoid it being
                    # printed in scientific notation
                    duration = "%.10f" % step.duration.total_seconds() \
                                if step.starttime and step.endtime else "0.0"
                    step_json = {
                        "keyword": step.sentence.split()[0],
                        "name": step.sentence,
                        "line": step.line,
                        "result": {
                            "status": step.state,
                            "duration": duration
                        }
                    }
                    if step.state is Step.State.FAILED:
                        step_json["result"][
                            "error_message"] = step.failure.reason
                    if step.state is Step.State.UNTESTED:
                        step_json["result"]["status"] = "skipped"
                    scenario_json["steps"].append(step_json)
                feature_json["elements"].append(scenario_json)
            ccjson.append(feature_json)

        with open(world.config.cucumber_json, "w+") as f:
            content = json.dumps(ccjson, indent=4, sort_keys=True)
            f.write(content)
示例#13
0
    def generate_junit_xml(self, features, marker):
        """
            Generates the junit xml
        """
        from lxml import etree

        if not features:
            raise RadishError("No features given to generate JUnit xml file")

        duration = timedelta()
        for feature in features:
            if feature.state in [Step.State.PASSED, Step.State.FAILED]:
                duration += feature.duration

        testsuites_element = etree.Element(
            "testsuites", time="%.3f" % duration.total_seconds()
        )

        for feature in features:

            if not feature.has_to_run(world.config.scenarios):
                continue

            testsuite_states = {"failures": 0, "errors": 0, "skipped": 0, "tests": 0}

            for scenario in (
                s
                for s in feature.all_scenarios
                if not isinstance(s, (ScenarioOutline, ScenarioLoop))
            ):
                if not scenario.has_to_run(world.config.scenarios):
                    continue

                testsuite_states["tests"] += 1
                if scenario.state in [
                    Step.State.UNTESTED,
                    Step.State.PENDING,
                    Step.State.SKIPPED,
                ]:
                    testsuite_states["skipped"] += 1
                if scenario.state is Step.State.FAILED:
                    testsuite_states["failures"] += 1

            testsuite_element = etree.Element(
                "testsuite",
                name=feature.sentence,
                failures=str(testsuite_states["failures"]),
                errors=str(testsuite_states["errors"]),
                skipped=str(testsuite_states["skipped"]),
                tests=str(testsuite_states["tests"]),
                time="%.3f" % feature.duration.total_seconds(),
            )

            for scenario in (
                s
                for s in feature.all_scenarios
                if not isinstance(s, (ScenarioOutline, ScenarioLoop))
            ):
                if not scenario.has_to_run(world.config.scenarios):
                    continue

                testcase_element = etree.Element(
                    "testcase",
                    classname=feature.sentence,
                    name=scenario.sentence,
                    time="%.3f" % scenario.duration.total_seconds(),
                )

                if scenario.state in [
                    Step.State.UNTESTED,
                    Step.State.PENDING,
                    Step.State.SKIPPED,
                ]:
                    skipped_element = etree.Element("skipped")
                    testcase_element.append(skipped_element)

                if scenario.state is Step.State.FAILED:
                    steps_sentence = []
                    for step in scenario.all_steps:
                        step_element = self._get_element_from_model("step", step)
                        steps_sentence.append(step.sentence)
                        if step.state is Step.State.FAILED:
                            failure_element = etree.Element(
                                "failure", type=step.failure.name, message=step.sentence
                            )
                            failure_element.text = etree.CDATA(
                                "%s\n\n%s"
                                % (
                                    "\n".join(steps_sentence),
                                    self._strip_ansi(step.failure.traceback),
                                )
                            )
                            testcase_element.append(failure_element)

                testsuite_element.append(testcase_element)

            testsuites_element.append(testsuite_element)

        with open(world.config.junit_xml, "w+") as f:
            content = etree.tostring(
                testsuites_element,
                pretty_print=True,
                xml_declaration=True,
                encoding="utf-8",
            )
            try:
                if not isinstance(content, str):
                    content = content.decode("utf-8")
            except Exception:
                pass
            finally:
                f.write(content)
示例#14
0
    def generate_bdd_xml(self, features, marker):
        """
            Generates the bdd xml
        """
        from lxml import etree
        if not features:
            raise RadishError("No features given to generate BDD xml file")

        duration = timedelta()
        for feature in features:
            if feature.state in [Step.State.PASSED, Step.State.FAILED]:
                duration += feature.duration

        testrun_element = etree.Element(
            "testrun",
            starttime=utils.datetime_to_str(features[0].starttime),
            endtime=utils.datetime_to_str(features[-1].endtime),
            duration=str(duration.total_seconds()),
            agent="{0}@{1}".format(getuser(), gethostname()))

        for feature in features:
            if not feature.has_to_run(world.config.scenarios):
                continue

            feature_element = self._get_element_from_model("feature", feature)

            description_element = etree.Element("description")
            description_element.text = etree.CDATA("\n".join(
                feature.description))

            tags_element = etree.Element('tags')

            for tag in feature.tags:
                tag_element = etree.Element('tag')
                tag_element.text = tag.name
                tags_element.append(tag_element)

            scenarios_element = etree.Element("scenarios")

            for scenario in (
                    s for s in feature.all_scenarios
                    if not isinstance(s, (ScenarioOutline, ScenarioLoop))):
                if not scenario.has_to_run(world.config.scenarios):
                    continue
                scenario_element = self._get_element_from_model(
                    "scenario", scenario)

                scenario_tags_element = etree.Element('tags')
                scenario_element.append(scenario_tags_element)

                for tag in scenario.tags:
                    tag_element = etree.Element('tag')
                    tag_element.text = tag.name
                    if tag.arg:
                        tag_element.text += '({0})'.format(tag.arg)
                    scenario_tags_element.append(tag_element)

                for step in scenario.all_steps:
                    step_element = self._get_element_from_model("step", step)
                    if step.state is Step.State.FAILED:
                        failure_element = etree.Element(
                            "failure",
                            type=step.failure.name,
                            message=step.failure.reason)
                        failure_element.text = etree.CDATA(
                            self._strip_ansi(step.failure.traceback))
                        step_element.append(failure_element)
                    scenario_element.append(step_element)
                scenarios_element.append(scenario_element)
            feature_element.append(description_element)
            feature_element.append(tags_element)
            feature_element.append(scenarios_element)
            testrun_element.append(feature_element)

        with open(world.config.bdd_xml, "w+") as f:
            content = etree.tostring(testrun_element,
                                     pretty_print=True,
                                     xml_declaration=True,
                                     encoding="utf-8")
            try:
                if not isinstance(content, str):
                    content = content.decode("utf-8")
            except Exception:
                pass
            finally:
                f.write(content)
示例#15
0
 async def __aenter__(self):
     if self._connection:
         raise RadishError("Already connected to redis!")
     self._connection = await self._connection_factory()
     return self
示例#16
0
 def connection(self) -> Redis:
     if not self._connection:
         raise RadishError("Connection to redis has not been initialised.")
     return self._connection