Пример #1
0
 def test_with_kwargs(self):
     assert (str(
         py.FunctionCall("f",
                         named_args={
                             "a": py.Literal(2),
                             "bc": py.Literal("x")
                         })) == "f(a=2, bc='x')")
Пример #2
0
def locust_classes(scenarios: Sequence[Scenario]) -> List[py.Class]:
    """
    Transforms scenarios into all Python classes needed by Locust (TaskSet and
    Locust classes).

    The only missing parts before a fully functional locustfile are:
    - integrating all necessary set-up/tear-down statements:
        - Python imports,
        - apply global plugins,
        - etc.
    - serializing everything via transformer.python.
    """
    classes = []
    for scenario in scenarios:
        taskset = locust_taskset(scenario)
        locust_class = py.Class(
            name=f"LocustFor{taskset.name}",
            superclasses=["HttpLocust"],
            statements=[
                py.Assignment("task_set", py.Symbol(taskset.name)),
                py.Assignment("weight", py.Literal(scenario.weight)),
                py.Assignment("min_wait", py.Literal(LOCUST_MIN_WAIT_DELAY)),
                py.Assignment("max_wait", py.Literal(LOCUST_MAX_WAIT_DELAY)),
            ],
        )
        classes.append(taskset)
        classes.append(locust_class)
    return classes
Пример #3
0
def lreq_to_expr(lr: LocustRequest) -> py.FunctionCall:
    # TODO: Remove me once LocustRequest no longer exists.
    #   See https://github.com/zalando-incubator/Transformer/issues/11.
    url = _peel_off_repr(lr.url)
    name = _peel_off_repr(lr.name) if lr.name else url

    args: Dict[str, py.Expression] = OrderedDict(
        url=url,
        name=name,
        timeout=py.Literal(TIMEOUT),
        allow_redirects=py.Literal(False),
    )
    if lr.headers:
        args["headers"] = py.Literal(lr.headers)
    if lr.method is HttpMethod.POST:
        if lr.post_data:
            rpd = RequestsPostData.from_har_post_data(lr.post_data)
            args.update(rpd.as_kwargs())
    elif lr.method in (HttpMethod.PUT, HttpMethod.PATCH):
        if lr.post_data:
            rpd = RequestsPostData.from_har_post_data(lr.post_data)
            args.update(rpd.as_kwargs())

        args.setdefault("params", py.Literal([]))
        cast(py.Literal, args["params"]).value.extend(
            _params_from_name_value_dicts(
                [dataclasses.asdict(q) for q in lr.query]))
    elif lr.method not in NOOP_HTTP_METHODS:
        raise ValueError(f"unsupported HTTP method: {lr.method!r}")

    method = lr.method.name.lower()
    return py.FunctionCall(name=f"self.client.{method}", named_args=args)
Пример #4
0
 def test_lines_with_nested_body(self, level: int):
     x = py.Line.INDENT_UNIT
     f = py.Function(
         "func",
         params=[],
         statements=[
             py.Assignment("a", py.Literal(2)),
             py.IfElse(
                 [(py.Literal(True), [py.Assignment("b", py.Literal(3))])],
                 [
                     py.Assignment("b", py.Literal(4)),
                     py.Assignment("c", py.Literal(1)),
                 ],
             ),
         ],
     )
     assert [str(l) for l in f.lines(level)] == [
         x * level + "def func():",
         x * (level + 1) + "a = 2",
         x * (level + 1) + "if True:",
         x * (level + 2) + "b = 3",
         x * (level + 1) + "else:",
         x * (level + 2) + "b = 4",
         x * (level + 2) + "c = 1",
     ]
Пример #5
0
 def test_lines_for_single_if(self, level: int):
     x = py.Line.INDENT_UNIT
     assert [
         str(l) for l in py.IfElse([(
             py.BinaryOp(py.Symbol("t"), "is", py.Literal(None)),
             [py.Assignment("t", py.Literal(1))],
         )]).lines(level)
     ] == [x * level + "if t is None:", x * (level + 1) + "t = 1"]
Пример #6
0
 def test_with_positional_and_kwargs(self):
     assert (str(
         py.FunctionCall(
             "m.f",
             [py.Literal(True),
              py.FunctionCall("g", [py.Symbol("f")])],
             {
                 "a": py.Literal(2),
                 "bc": py.Literal("x")
             },
         )) == "m.f(True, g(f), a=2, bc='x')")
Пример #7
0
 def test_nested(self):
     assert (str(
         py.BinaryOp(
             py.Literal(2),
             "+",
             py.BinaryOp(
                 py.BinaryOp(py.Literal(3), "-", py.Literal(4)),
                 "*",
                 py.Literal(5),
             ),
         )) == "2 + ((3 - 4) * 5)")
Пример #8
0
 def test_it_accepts_both_params_and_text(self, mime: str, kwarg, val):
     expected_fields = {
         "params": py.Literal([(b"n", b"v")]),
         kwarg: py.Literal(val),
     }
     assert RequestsPostData.from_har_post_data(
         {
             "mimeType": mime,
             "text": "{}",
             "params": [{"name": "n", "value": "v"}],
         }
     ) == RequestsPostData(**expected_fields)
Пример #9
0
 def test_it_supports_fstring_urls(self):
     url = "http://abc.{tld}"
     r = LocustRequest(method=HttpMethod.GET, url=f"f'{url}'", headers={"a": "b"})
     assert lreq_to_expr(r) == py.FunctionCall(
         name="self.client.get",
         named_args={
             "url": py.FString(url),
             "name": py.FString(url),
             "headers": py.Literal({"a": "b"}),
             "timeout": py.Literal(TIMEOUT),
             "allow_redirects": py.Literal(False),
         },
     )
Пример #10
0
 def test_class_with_fields(self, level: int):
     c = py.Class(
         "A",
         statements=[
             py.Assignment("a", py.Literal(2)),
             py.Assignment("b", py.Literal(3)),
         ],
     )
     x = py.Line.INDENT_UNIT
     assert [str(l) for l in c.lines(level)] == [
         x * level + "class A:",
         x * (level + 1) + "a = 2",
         x * (level + 1) + "b = 3",
     ]
Пример #11
0
def _from_har_post_data(post_data: dict) -> RequestsPostData:
    mime_k = "mimeType"
    try:
        mime: str = post_data[mime_k]
    except KeyError:
        raise ValueError(f"missing {mime_k!r} field") from None

    rpd = RequestsPostData()

    # The "text" and "params" fields are supposed to be mutually
    # exclusive (according to the HAR spec) but nobody respects that.
    # Often, both text and params are provided for x-www-form-urlencoded.
    text_k, params_k = "text", "params"
    if text_k not in post_data and params_k not in post_data:
        raise ValueError(f"should contain {text_k!r} or {params_k!r}")

    _extract_text(mime, post_data, text_k, rpd)

    try:
        params = _params_from_post_data(params_k, post_data)
        if params is not None:
            rpd.params = py.Literal(params)
    except (KeyError, UnicodeEncodeError, TypeError) as err:
        raise ValueError("unreadable params field") from err

    return rpd
Пример #12
0
def _peel_off_repr(s: str) -> py.Literal:
    """
    Reverse the effect of LocustRequest's repr() calls on url and name.
    """
    if s.startswith("f"):
        return py.FString(eval(s[1:], {}, {}))
    return py.Literal(eval(s, {}, {}))
Пример #13
0
 def test_init_with_no_condition_raises_error(self):
     with pytest.raises(ValueError):
         py.IfElse([])
     with pytest.raises(ValueError):
         py.IfElse([], else_block=[])
     with pytest.raises(ValueError):
         py.IfElse([], else_block=[py.Assignment("a", py.Literal(2))])
Пример #14
0
    def test_wraps_int_into_literal(self):
        def f(x: int) -> py.Literal:
            return py.Literal(x * 2)

        ev = py.ExpressionView(name="hello", target=lambda: 7, converter=f)
        assert ev.converter(ev.target()) == py.Literal(14)
        assert str(ev) == "14"
Пример #15
0
def _extract_text(mime: str, post_data: dict, text_k: str,
                  rpd: RequestsPostData) -> None:
    text = post_data.get(text_k)
    if mime == JSON_MIME_TYPE:
        if text is None:
            raise ValueError(
                f"missing {text_k!r} field for {JSON_MIME_TYPE} content")
        try:
            rpd.json = py.Literal(json.loads(text))
        except JSONDecodeError as err:
            raise ValueError(f"unreadable JSON from field {text_k!r}") from err
    elif text is not None:  # Probably application/x-www-form-urlencoded.
        try:
            rpd.data = py.Literal(text.encode())
        except UnicodeEncodeError as err:
            raise ValueError(
                f"cannot encode the {text_k!r} field in UTF-8") from err
Пример #16
0
 def test_repr(self):
     cond = py.Literal(True)
     if_true = [(cond, [py.Assignment("x", py.Symbol("a"))])]
     stmt = py.IfElse(condition_blocks=if_true, comments=["hi"])
     assert (
         repr(stmt) ==
         f"IfElse(condition_blocks={if_true!r}, else_block=None, comments=['hi'])"
     )
Пример #17
0
 def test_it_supports_urlencoded_post_requests(self):
     url = "http://abc.de"
     r = LocustRequest.from_request(
         Request(
             timestamp=MagicMock(),
             method=HttpMethod.POST,
             url=urlparse(url),
             har_entry={"entry": "data"},
             headers={"a": "b"},
             post_data={
                 "mimeType": "application/x-www-form-urlencoded",
                 "params": [{"name": "x", "value": "y"}],
                 "text": "z=7",
             },
         )
     )
     assert lreq_to_expr(r) == py.FunctionCall(
         name="self.client.post",
         named_args={
             "url": py.Literal(url),
             "name": py.Literal(url),
             "headers": py.Literal({"a": "b"}),
             "timeout": py.Literal(TIMEOUT),
             "allow_redirects": py.Literal(False),
             "data": py.Literal(b"z=7"),
             "params": py.Literal([(b"x", b"y")]),
         },
     )
Пример #18
0
 def test_it_supports_patch_requests_with_payload(self):
     url = "http://abc.de"
     r = LocustRequest.from_request(
         Request(
             timestamp=MagicMock(),
             method=HttpMethod.PATCH,
             url=urlparse(url),
             har_entry={"entry": "data"},
             headers={"a": "b"},
             query=[QueryPair("c", "d")],
             post_data={
                 "mimeType": "application/json",
                 "params": [{"name": "x", "value": "y"}],
                 "text": """{"z": 7}""",
             },
         )
     )
     assert lreq_to_expr(r) == py.FunctionCall(
         name="self.client.patch",
         named_args={
             "url": py.Literal(url),
             "name": py.Literal(url),
             "headers": py.Literal({"a": "b"}),
             "timeout": py.Literal(TIMEOUT),
             "allow_redirects": py.Literal(False),
             "json": py.Literal({"z": 7}),
             "params": py.Literal([(b"x", b"y"), (b"c", b"d")]),
         },
     )
Пример #19
0
 def test_it_supports_json_post_requests(self):
     url = "http://abc.de"
     r = Request(
         timestamp=MagicMock(),
         method=HttpMethod.POST,
         url=urlparse(url),
         har_entry={"entry": "data"},
         headers={"a": "b"},
         post_data={
             "mimeType": "application/json",
             "params": [{"name": "x", "value": "y"}],
             "text": """{"z": 7}""",
         },
     )
     assert req_to_expr(r) == py.FunctionCall(
         name="self.client.post",
         named_args={
             "url": py.Literal(url),
             "name": py.Literal(url),
             "headers": py.Literal({"a": "b"}),
             "timeout": py.Literal(TIMEOUT),
             "allow_redirects": py.Literal(False),
             "json": py.Literal({"z": 7}),
             "params": py.Literal([(b"x", b"y")]),
         },
     )
Пример #20
0
 def test_lines_for_if_elif_else_with_no_statements(self, level: int):
     x = py.Line.INDENT_UNIT
     assert [
         str(l) for l in py.IfElse(
             [
                 (py.BinaryOp(py.Symbol("t"), "is", py.Literal(None)), []),
                 (py.Literal(False), []),
                 (py.Literal(True), []),
             ],
             [],
         ).lines(level)
     ] == [
         x * level + "if t is None:",
         x * (level + 1) + "pass",
         x * level + "elif False:",
         x * (level + 1) + "pass",
         x * level + "elif True:",
         x * (level + 1) + "pass",
     ]
Пример #21
0
 def test_it_uses_the_custom_name_if_provided(self):
     url = "http://abc.de"
     name = "my-req"
     r = Request(
         name=name,
         timestamp=MagicMock(),
         method=HttpMethod.GET,
         url=urlparse(url),
         har_entry={"entry": "data"},
     )
     assert req_to_expr(r) == py.FunctionCall(
         name="self.client.get",
         named_args={
             "url": py.Literal(url),
             "name": py.Literal(name),
             "timeout": py.Literal(TIMEOUT),
             "allow_redirects": py.Literal(False),
         },
     )
Пример #22
0
 def test_with_a_class(self, level: int):
     c = py.Class("C",
                  superclasses=[],
                  statements=[py.Assignment("a: int", py.Literal(1))])
     d = py.Decoration("task", c)
     x = py.Line.INDENT_UNIT
     assert [str(l) for l in d.lines(level)] == [
         x * level + "@task",
         *[str(l) for l in c.lines(level)],
     ]
Пример #23
0
 def test_it_supports_empty_post_requests(self):
     url = "http://abc.de"
     r = Request(
         timestamp=MagicMock(),
         method=HttpMethod.POST,
         url=urlparse(url),
         har_entry={"entry": "data"},
         headers={"a": "b"},
         post_data=None,
     )
     assert req_to_expr(r) == py.FunctionCall(
         name="self.client.post",
         named_args={
             "url": py.Literal(url),
             "name": py.Literal(url),
             "headers": py.Literal({"a": "b"}),
             "timeout": py.Literal(TIMEOUT),
             "allow_redirects": py.Literal(False),
         },
     )
Пример #24
0
 def test_it_supports_get_requests(self):
     url = "http://abc.de"
     r = Request(
         timestamp=MagicMock(),
         method=HttpMethod.GET,
         url=urlparse(url),
         har_entry={"entry": "data"},
         headers={"a": "b"},
         query=[QueryPair("x", "y")],  # query is currently ignored for GET
     )
     assert req_to_expr(r) == py.FunctionCall(
         name="self.client.get",
         named_args={
             "url": py.Literal(url),
             "name": py.Literal(url),
             "headers": py.Literal({"a": "b"}),
             "timeout": py.Literal(TIMEOUT),
             "allow_redirects": py.Literal(False),
         },
     )
Пример #25
0
 def test_lines_with_hidden_comments(self, level: int):
     x = py.Line.INDENT_UNIT
     cond = py.Literal(True)
     if_true = py.Assignment("x", py.Symbol("a"), comments=["tx", "ty"])
     if_false = py.Assignment("x", py.Symbol("b"), comments=["fx", "fy"])
     stmt = py.IfElse([(cond, [if_true])], [if_false], comments=["1", "2"])
     assert [str(l) for l in stmt.lines(level, comments=False)] == [
         x * level + "if True:",
         *[str(l) for l in if_true.lines(level + 1, comments=False)],
         x * level + "else:",
         *[str(l) for l in if_false.lines(level + 1, comments=False)],
     ]
Пример #26
0
def req_to_expr(r: Request) -> py.FunctionCall:
    url = py.Literal(str(r.url.geturl()))
    args: Dict[str, py.Expression] = OrderedDict(
        url=url,
        name=py.Literal(r.name) if r.name else url,
        timeout=py.Literal(TIMEOUT),
        allow_redirects=py.Literal(False),
    )
    if r.headers:
        args["headers"] = py.Literal(r.headers)

    if r.method is HttpMethod.POST:
        if r.post_data:
            rpd = RequestsPostData.from_har_post_data(r.post_data)
            args.update(rpd.as_kwargs())
    elif r.method in (HttpMethod.PUT, HttpMethod.PATCH):
        if r.post_data:
            rpd = RequestsPostData.from_har_post_data(r.post_data)
            args.update(rpd.as_kwargs())

        args.setdefault("params", py.Literal([]))
        cast(py.Literal, args["params"]).value.extend(
            _params_from_name_value_dicts(
                [dataclasses.asdict(q) for q in r.query]))
    elif r.method not in NOOP_HTTP_METHODS:
        raise ValueError(f"unsupported HTTP method: {r.method!r}")

    method = r.method.name.lower()
    return py.FunctionCall(name=f"self.client.{method}", named_args=args)
Пример #27
0
 def test_lines_for_if_elif(self, level: int):
     x = py.Line.INDENT_UNIT
     assert [
         str(l) for l in py.IfElse([
             (
                 py.BinaryOp(py.Symbol("t"), "is", py.Literal(None)),
                 [py.Assignment("t", py.Literal(1))],
             ),
             (
                 py.Literal(False),
                 [
                     py.Assignment("t", py.Literal(2)),
                     py.Standalone(py.FunctionCall("f", [py.Symbol("t")])),
                 ],
             ),
         ]).lines(level)
     ] == [
         x * level + "if t is None:",
         x * (level + 1) + "t = 1",
         x * level + "elif False:",
         x * (level + 1) + "t = 2",
         x * (level + 1) + "f(t)",
     ]
Пример #28
0
def locust_imports() -> py.Program:
    is_post_1 = py.BinaryOp(py.Symbol("LOCUST_MAJOR_VERSION"), ">=", py.Literal(1),)
    imports_pre_1 = [
        py.Import(
            ["HttpLocust", "TaskSequence", "TaskSet", "seq_task", "task"],
            source="locust",
        )
    ]
    imports_post_1 = [
        py.Import(
            ["HttpUser", "SequentialTaskSet", "TaskSet", "task"], source="locust",
        ),
        py.Assignment("HttpLocust", py.Symbol("HttpUser")),
        py.Assignment("TaskSequence", py.Symbol("SequentialTaskSet")),
        py.Function("seq_task", ["_"], [py.Return(py.Symbol("task"))]),
    ]
    return [
        py.IfElse([(is_post_1, imports_post_1)], imports_pre_1),
    ]
Пример #29
0
 def test_it_supports_patch_requests_without_payload(self):
     url = "http://abc.de"
     r = Request(
         timestamp=MagicMock(),
         method=HttpMethod.PATCH,
         url=urlparse(url),
         har_entry={"entry": "data"},
         headers={"a": "b"},
         query=[QueryPair("c", "d")],
         post_data=None,
     )
     assert req_to_expr(r) == py.FunctionCall(
         name="self.client.patch",
         named_args={
             "url": py.Literal(url),
             "name": py.Literal(url),
             "headers": py.Literal({"a": "b"}),
             "timeout": py.Literal(TIMEOUT),
             "allow_redirects": py.Literal(False),
             "params": py.Literal([(b"c", b"d")]),
         },
     )
Пример #30
0
 def f(x: int) -> py.Literal:
     return py.Literal(x * 2)