Exemplo n.º 1
0
    def task_name(self) -> str:
        """
        Generates a simple name suitable for use as a Python function.
        """

        return "_".join((
            self.method.name,
            self.url.scheme,
            to_identifier(self.url.hostname),
            to_identifier(self.url.path),
            str(abs(hash(self))),
        ))
Exemplo n.º 2
0
    def task_name(self) -> str:
        """
        Generates a simple name to be used as
        :attr:`~transformer.task.Task2.name` by the :term:`task` of this request.
        """

        return "_".join((
            self.method.name,
            self.url.scheme,
            to_identifier(self.url.hostname),
            to_identifier(self.url.path),
            str(abs(hash(self))),
        ))
Exemplo n.º 3
0
    def from_har_file(
        cls,
        path: Path,
        plugins: Sequence[Plugin],
        ts_plugins: Sequence[Plugin],
        short_name: bool,
        blacklist: Blacklist,
    ) -> "Scenario":
        """
        Creates a Scenario given a HAR file.

        :raise SkippableScenarioError: if path is unreadable or not a HAR file
        """
        try:
            with path.open() as file:
                har = json.load(file)
            requests = Request.all_from_har(har)
            tasks = Task.from_requests(requests, blacklist)

            # TODO: Remove this when Contract.OnTaskSequence is removed.
            tasks = plug.apply(ts_plugins, tasks)

            # TODO: Remove Task-to-Task2 conversion once both are merged.
            tasks = tuple(
                plug.apply(plugins, Task2.from_task(t)) for t in tasks)

            return Scenario(
                name=to_identifier(
                    path.with_suffix("").name if short_name else str(path)),
                children=tuple(tasks),
                origin=path,
                weight=cls.weight_from_path(path),
            )
        except (OSError, json.JSONDecodeError, UnicodeDecodeError) as err:
            raise SkippableScenarioError(path, err)
Exemplo n.º 4
0
class TestToIdentifier:
    @given(text(min_size=1, max_size=3))
    @example("0")
    def test_its_output_can_always_be_used_as_python_identifier(self, s: str):
        exec(f"{to_identifier(s)} = 2")

    @given(text(), text())
    @example("x y", to_identifier("x y"))
    def test_it_has_no_collisions(self, a: str, b: str):
        assert a == b or to_identifier(a) != to_identifier(b)

    @given(
        from_regex(re.compile(r"[a-z_][a-z0-9_]*", re.IGNORECASE),
                   fullmatch=True))
    def test_it_does_not_add_suffix_when_not_necessary(self, input: str):
        assume(not DIGITS_SUFFIX_RX.search(input))
        assert to_identifier(input) == input

    def test_it_adds_prefix_to_inputs_starting_with_digit(self):
        assert to_identifier("0").startswith("_")
Exemplo n.º 5
0
 def test_it_adds_prefix_to_inputs_starting_with_digit(self):
     assert to_identifier("0").startswith("_")
Exemplo n.º 6
0
 def test_it_does_not_add_suffix_when_not_necessary(self, input: str):
     assume(not DIGITS_SUFFIX_RX.search(input))
     assert to_identifier(input) == input
Exemplo n.º 7
0
 def test_it_has_no_collisions(self, a: str, b: str):
     assert a == b or to_identifier(a) != to_identifier(b)
Exemplo n.º 8
0
    def from_dir(
        cls,
        path: Path,
        plugins: Sequence[Plugin],
        ts_plugins: Sequence[Plugin],
        short_name: bool,
        blacklist: Blacklist,
    ) -> "Scenario":
        """
        Makes a :class:`Scenario` out of the provided directory *path*.

        *path* must represent a "scenario directory", which contains at least
        one HAR file or another scenario directory.
        Symbolic link loops are not checked but forbidden!

        There may exist a weight file :file:`{path}.weight`.
        If so, its contents will be used as :attr:`weight` after calling
        :meth:`weight_from_path`.

        Errors are handled this way:

        #. If *path* itself cannot be transformed into a scenario,
           raise :exc:`SkippableScenarioError`.

        #. For each child of *path*, apply (1) but catch the exception and
           display a warning about skipping that child.
           (If all children are skipped, (1) applies to *path* itself.)

        Therefore:

        - If the directory contains weight files that don't match any HAR file or
          subdirectory, an error is emitted as this is probably a mistake.

        - If the directory contains files or directories that cannot be converted
          into scenarios (e.g. non-JSON files or :file:`.git` directories),
          a message is emitted and the file or subdirectory is skipped.

        :param path: path to the directory.
        :param plugins: list of :term:`OnScenario` plugins to apply.
        :param ts_plugins: deprecated -- for backward compatibility only.
        :param short_name: whether to simplify the resulting
            :class:`~locust.core.TaskSet` class name. If *short_name* is *False*,
            that class name is guaranteed to be unique across all TaskSets of the
            locustfile, but this is generally not necessary and results in less
            readable class names.
        :param blacklist: a sequence of urls to be blacklisted
        :raise SkippableScenarioError: if the directory contains dangling weight
            files or no sub-scenarios.
        """
        try:
            children = list(path.iterdir())
        except OSError as err:
            raise SkippableScenarioError(path, err)

        weight_files: Set[Path] = {
            child
            for child in children if child.suffix == WEIGHT_FILE_SUFFIX
        }

        scenarios: List[Scenario] = []
        for child in children:
            if child in weight_files:
                continue
            try:
                scenario = cls.from_path(
                    child,
                    plugins,
                    ts_plugins=ts_plugins,
                    short_name=True,
                    blacklist=blacklist,
                )
            except SkippableScenarioError as err:
                logging.warning(
                    "while searching for HAR files, skipping %s: %s", child,
                    err.reason)
            else:
                scenarios.append(scenario)

        cls._check_dangling_weights(path, scenarios, weight_files)
        if not scenarios:
            raise SkippableScenarioError(path,
                                         "no scenarios inside the directory")
        cls._check_name_collisions(path, scenarios)

        return Scenario(
            name=to_identifier(
                path.with_suffix("").name if short_name else str(path)),
            children=tuple(scenarios),
            origin=path,
            weight=cls.weight_from_path(path),
        )
Exemplo n.º 9
0
    def from_dir(
        cls,
        path: Path,
        plugins: Sequence[Plugin],
        ts_plugins: Sequence[Plugin],
        short_name: bool,
    ) -> "Scenario":
        """
        Makes a Scenario out of the provided directory path.

        The directory must be a "scenario directory", which means that it must
        contain at least one HAR file or another scenario directory.
        Symbolic link loops are not checked but forbidden!

        There may exist a weight file <path>.weight. If so, its contents will
        be used as weight for the Scenario by calling weight_from_path.

        Errors are handled this way:
        1. If path itself cannot be transformed into a scenario,
           raise SkippableScenarioError.
        2. For each child of path, apply (1) but catch the exception and display
           a warning about skipping this child. (If all children are skipped, (1)
           applies to path itself.)

        Therefore:
        - If the directory contains weight files that don't match any HAR file or
          subdirectory, an error will be emitted as this is probably a mistake.
        - If the directory contains files or directory that cannot be converted
          into scenarios (e.g. non-JSON files or .git directories), a message
          is emitted and the file or subdirectory is skipped.

        :raise SkippableScenarioError: if the directory contains dangling weight
            files or no sub-scenarios.
        """
        try:
            children = list(path.iterdir())
        except OSError as err:
            raise SkippableScenarioError(path, err)

        weight_files: Set[Path] = {
            child
            for child in children if child.suffix == WEIGHT_FILE_SUFFIX
        }

        scenarios: List[Scenario] = []
        for child in children:
            if child in weight_files:
                continue
            try:
                scenario = cls.from_path(child,
                                         plugins,
                                         ts_plugins=ts_plugins,
                                         short_name=True)
            except SkippableScenarioError as err:
                logging.warning(
                    "while searching for HAR files, skipping %s: %s", child,
                    err.reason)
            else:
                scenarios.append(scenario)

        cls._check_dangling_weights(path, scenarios, weight_files)
        if not scenarios:
            raise SkippableScenarioError(path,
                                         "no scenarios inside the directory")
        cls._check_name_collisions(path, scenarios)

        return Scenario(
            name=to_identifier(
                path.with_suffix("").name if short_name else str(path)),
            children=tuple(scenarios),
            origin=path,
            weight=cls.weight_from_path(path),
        )