From d9e954ac87506d27cdb8ecdd55b4f51827dc6776 Mon Sep 17 00:00:00 2001 From: kzangeli Date: Fri, 29 May 2026 14:28:46 +0200 Subject: [PATCH 1/2] HttpCtrl: document why set_stub_reply auto-serialises conditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conditional body-serialisation itself landed on develop via 59f9d26e: if not isinstance(body, (str, bytes)) and body is not None: body = json.dumps(body) response = Response(int(status), None, body, None, None) This commit adds the explanatory comment above it, recording *why* the guard exists, so a future reader doesn't "simplify" it back to an unconditional `json.dumps(body)`. The vendored 0.3.1 fork wrapped every body in `json.dumps()` — presumably to fix the opposite bug (dict bodies served raw to the wire — see MR !273 / D010_01_aux). But callers that already pass a serialised JSON *string* (e.g. via `Convert JSON To String` in JsonUtils.resource) then got their body double-encoded: a Python str of `'[{"id":"X"}]'` became the wire body `'"[{\\"id\\":\\"X\\"}]"'` — a JSON string wrapping the intended array. The broker's response parser saw a String where it expected an Array and the merge silently failed. The conditional handles both callers; the comment explains that trade-off. Verified when the fix originally landed: D011_02_exc_01 (which was failing as "missing $.speed") passes, and the distops sub-suite showed ~9 tests flipping FAIL→PASS. --- libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py b/libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py index a4c1658f..bc7c5454 100755 --- a/libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py +++ b/libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py @@ -1118,6 +1118,13 @@ class Server: raise AssertionError(message_error) criteria = HttpStubCriteria(method=method, url=url) + # Auto-serialise non-string bodies (e.g. Python dicts / lists) so callers + # can pass either a Python data structure OR an already-serialised JSON + # string. The previous unconditional `json.dumps(body)` double-encoded + # string bodies — a stub body of `'[{"id":"X"}]'` (e.g. from + # `Convert JSON To String`) was sent on the wire as + # `'"[{\\"id\\":\\"X\\"}]"'` and parsed by the client as a string, not + # an array. if not isinstance(body, (str, bytes)) and body is not None: body = json.dumps(body) response = Response(int(status), None, body, None, None) -- GitLab From 66ee0524129f291bc66fe8fc8af74a7255e05007 Mon Sep 17 00:00:00 2001 From: kzangeli Date: Mon, 1 Jun 2026 10:51:26 +0200 Subject: [PATCH 2/2] HttpCtrl: document set_stub_reply body now accepts dict/list too Per review on !282 (orihuelab): the function's docstring still claimed body was `string|bytes` only, but the new conditional auto-serialise also accepts a Python dict/list (or any json.dumps-able object), and None. Update the docstring to reflect the actual contract. No behaviour change. Co-Authored-By: Claude Opus 4.7 --- libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py b/libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py index bc7c5454..b396fcc2 100755 --- a/libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py +++ b/libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py @@ -1090,7 +1090,10 @@ class Server: `status` [in] (int|string): HTTP status code for response that is used by server stub. - `body` [in] (string|bytes): Response body that is used by server stub. + `body` [in] (string|bytes|None or any JSON-serialisable Python object): Response body that is used by server stub. + A `str` or `bytes` body is sent on the wire as-is — useful when the caller has already serialised + JSON (e.g. via `Convert JSON To String`). Any other non-`None` value is run through `json.dumps()` + so callers can also pass a Python `dict` / `list` directly. `None` sends an empty body. Example how to set stub to reply automatically to request `POST` `/api/v1/request` by status `200`. -- GitLab