|
5 | 5 |
|
6 | 6 | import pytest |
7 | 7 | 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 |
9 | 9 |
|
10 | 10 |
|
11 | 11 | class TestInitFunction: |
@@ -118,33 +118,31 @@ def test_invoke_serializes_google_messages(): |
118 | 118 | assert isinstance(parsed, dict) and parsed |
119 | 119 |
|
120 | 120 |
|
121 | | -def test_invoke_encodes_body_as_utf8_bytes(): |
| 121 | +@pytest.mark.vcr |
| 122 | +def test_invoke_encodes_body_as_utf8_bytes(monkeypatch): |
122 | 123 | """Regression test for BT-4620: non-Latin-1 Unicode must not be corrupted. |
123 | 124 |
|
124 | 125 | When invoke() serializes the request body via bt_dumps() and passes it to |
125 | 126 | requests.post(data=...), the body must be UTF-8 encoded bytes — not a str. |
126 | 127 | Passing a str causes requests to re-encode with Latin-1, which raises |
127 | 128 | 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 |
135 | 129 |
|
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() |
144 | 139 |
|
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