Skip to content

Commit 416407c

Browse files
committed
add vcr test
1 parent 1a2ea3d commit 416407c

2 files changed

Lines changed: 50 additions & 23 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
interactions:
2+
- request:
3+
body: '{"api_version": 1, "input": {"text": "result \u2014 excellent"}, "metadata":
4+
null, "parent": "", "project_name": "test-project", "slug": "test-fn", "stream":
5+
false, "tags": null}'
6+
headers:
7+
Accept:
8+
- application/json
9+
Accept-Encoding:
10+
- gzip, deflate
11+
Connection:
12+
- keep-alive
13+
Content-Type:
14+
- application/json
15+
User-Agent:
16+
- python-requests/2.32.5
17+
method: POST
18+
uri: https://proxy.braintrust.ai/function/invoke
19+
response:
20+
body:
21+
string: '{"output": "result \u2014 excellent"}'
22+
headers:
23+
Content-Type:
24+
- application/json; charset=utf-8
25+
status:
26+
code: 200
27+
message: OK
28+
version: 1
29+

py/src/braintrust/functions/test_invoke.py

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import pytest
77
from braintrust.functions.invoke import init_function, invoke
8-
from braintrust.logger import _internal_get_global_state, _internal_reset_global_state
8+
from braintrust.logger import TEST_API_KEY, _internal_get_global_state, _internal_reset_global_state
99

1010

1111
class TestInitFunction:
@@ -118,33 +118,31 @@ def test_invoke_serializes_google_messages():
118118
assert isinstance(parsed, dict) and parsed
119119

120120

121-
def test_invoke_encodes_body_as_utf8_bytes():
121+
@pytest.mark.vcr
122+
def test_invoke_encodes_body_as_utf8_bytes(monkeypatch):
122123
"""Regression test for BT-4620: non-Latin-1 Unicode must not be corrupted.
123124
124125
When invoke() serializes the request body via bt_dumps() and passes it to
125126
requests.post(data=...), the body must be UTF-8 encoded bytes — not a str.
126127
Passing a str causes requests to re-encode with Latin-1, which raises
127128
UnicodeEncodeError (or silently corrupts data) for characters outside U+007F.
128-
"""
129-
em_dash = "\u2014" # — (U+2014) is outside Latin-1; triggers the bug when body is str
130-
mock_resp = MagicMock()
131-
mock_resp.status_code = 200
132-
mock_resp.json.return_value = {}
133-
mock_conn = MagicMock()
134-
mock_conn.post.return_value = mock_resp
135129
136-
with (
137-
patch("braintrust.functions.invoke.login"),
138-
patch("braintrust.functions.invoke.proxy_conn", return_value=mock_conn),
139-
):
140-
invoke(project_name="test-project", slug="test-fn", input={"text": f"result {em_dash} excellent"})
141-
142-
kwargs = mock_conn.post.call_args.kwargs
143-
data = kwargs["data"]
130+
Uses TEST_API_KEY to skip the HTTP login entirely, so the cassette only needs
131+
to capture the single POST to /function/invoke. BRAINTRUST_PROXY_URL is
132+
cleared so the proxy URL is always the predictable test stub value
133+
(https://proxy.braintrust.ai) regardless of the local environment.
134+
"""
135+
# Prevent local env overrides from changing the proxy URL used in the cassette.
136+
monkeypatch.delenv("BRAINTRUST_PROXY_URL", raising=False)
137+
monkeypatch.delenv("BRAINTRUST_API_URL", raising=False)
138+
_internal_reset_global_state()
144139

145-
assert isinstance(data, bytes), "body must be bytes so requests does not Latin-1 encode it"
146-
# Round-trip through UTF-8 decode + JSON parse to confirm the em dash survives intact.
147-
# bt_dumps may use JSON \uXXXX escapes (stdlib) or raw UTF-8 bytes (orjson) — both are valid.
148-
parsed = json.loads(data.decode("utf-8"))
149-
assert parsed["input"]["text"] == f"result {em_dash} excellent", "em dash must survive serialization"
150-
assert kwargs.get("headers", {}).get("Content-Type") == "application/json"
140+
em_dash = "\u2014" # — (U+2014) is outside Latin-1; triggers the bug when body is str
141+
result = invoke(
142+
project_name="test-project",
143+
slug="test-fn",
144+
input={"text": f"result {em_dash} excellent"},
145+
parent="", # skip span-parent lookup; no extra HTTP call needed
146+
api_key=TEST_API_KEY,
147+
)
148+
assert result["output"] == f"result {em_dash} excellent"

0 commit comments

Comments
 (0)