Skip to content

Commit 0b5264b

Browse files
authored
Merge pull request #117 from OpenTestSolar/bugfix/pytest-fix-inject-header-bug
修复注入请求头问题
2 parents e244c5d + 224eea3 commit 0b5264b

4 files changed

Lines changed: 32 additions & 9 deletions

File tree

‎pytest/pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "testsolar-pytestx"
3-
version = "0.1.76"
3+
version = "0.1.77"
44
description = "Pytest tool for TestSolar"
55
authors = [
66
{name = "asiazhang2002", email = "asiazhang2002@gmail.com"},

‎pytest/src/testsolar_pytestx/header_injection.py‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77

88
import threading
9+
import urllib.parse
910
from typing import Optional, Callable, Any, Dict
1011

1112
from loguru import logger
@@ -33,6 +34,16 @@ def set_current_test_nodeid(nodeid: Optional[str]) -> None:
3334

3435

3536
# ============ Header 注入逻辑 ============
37+
def _encode_nodeid(nodeid: str) -> str:
38+
"""对nodeid进行URL编码,确保HTTP头部值只含ASCII字符。
39+
40+
HTTP头部值要求latin-1编码,含中文等非ASCII字符的用例名会导致
41+
UnicodeEncodeError,故注入前统一percent-encode。接收方可用
42+
urllib.parse.unquote还原原始用例名。
43+
"""
44+
return urllib.parse.quote(nodeid, safe="")
45+
46+
3647
def _inject_header_to_dict(headers: Optional[Dict[str, Any]], nodeid: str) -> Dict[str, Any]:
3748
"""
3849
向请求头字典注入X-Testsolar-Testcase
@@ -53,7 +64,7 @@ def _inject_header_to_dict(headers: Optional[Dict[str, Any]], nodeid: str) -> Di
5364
# 创建副本避免修改原始dict
5465
headers = headers.copy()
5566

56-
headers["X-Testsolar-Testcase"] = nodeid
67+
headers["X-Testsolar-Testcase"] = _encode_nodeid(nodeid)
5768
return headers
5869

5970

@@ -119,11 +130,11 @@ def _patched_httplib_request(
119130
if nodeid:
120131
# httplib的headers参数默认是{}而不是None
121132
if final_headers is None:
122-
final_headers = {"X-Testsolar-Testcase": nodeid}
133+
final_headers = {"X-Testsolar-Testcase": _encode_nodeid(nodeid)}
123134
else:
124135
# 创建副本避免修改原始headers
125136
new_headers = dict(final_headers)
126-
new_headers["X-Testsolar-Testcase"] = nodeid
137+
new_headers["X-Testsolar-Testcase"] = _encode_nodeid(nodeid)
127138
final_headers = new_headers
128139

129140
return _original_httplib_request(self, method, url, body, final_headers, **kwargs)

‎pytest/tests/test_header_injection.py‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Tests for header_injection module."""
22

33
import threading
4+
import urllib.parse
45
from typing import Any, Dict, Optional
56
from unittest import mock
67

@@ -78,12 +79,12 @@ class TestInjectHeaderToDict:
7879
def test_inject_header_to_none_headers(self) -> None:
7980
"""Test injecting header when headers is None."""
8081
result = _inject_header_to_dict(None, "test::nodeid")
81-
assert result == {"X-Testsolar-Testcase": "test::nodeid"}
82+
assert result == {"X-Testsolar-Testcase": "test%3A%3Anodeid"}
8283

8384
def test_inject_header_to_empty_dict(self) -> None:
8485
"""Test injecting header to empty dict."""
8586
result = _inject_header_to_dict({}, "test::nodeid")
86-
assert result == {"X-Testsolar-Testcase": "test::nodeid"}
87+
assert result == {"X-Testsolar-Testcase": "test%3A%3Anodeid"}
8788

8889
def test_inject_header_to_existing_dict(self) -> None:
8990
"""Test injecting header to dict with existing headers."""
@@ -92,11 +93,22 @@ def test_inject_header_to_existing_dict(self) -> None:
9293

9394
assert result == {
9495
"Content-Type": "application/json",
95-
"X-Testsolar-Testcase": "test::nodeid",
96+
"X-Testsolar-Testcase": "test%3A%3Anodeid",
9697
}
9798
# Original should not be modified
9899
assert "X-Testsolar-Testcase" not in original
99100

101+
def test_inject_header_encodes_non_ascii_nodeid(self) -> None:
102+
"""含中文等非ASCII字符的nodeid需被percent-encode,避免latin-1编码错误。"""
103+
nodeid = "test_features.py::test_重启运行中实例"
104+
result = _inject_header_to_dict(None, nodeid)
105+
106+
encoded = result["X-Testsolar-Testcase"]
107+
# 注入值必须可被latin-1编码(HTTP头部要求),否则抛UnicodeEncodeError
108+
assert isinstance(encoded.encode("latin-1"), bytes)
109+
# 接收方unquote可还原原始用例名
110+
assert urllib.parse.unquote(encoded) == nodeid
111+
100112
def test_inject_header_does_not_modify_original(self) -> None:
101113
"""Test that original headers dict is not modified."""
102114
original: Dict[str, str] = {"Authorization": "Bearer token"}
@@ -166,7 +178,7 @@ def test_requests_header_injection(self) -> None:
166178
if mock_send.called:
167179
request = mock_send.call_args[0][0]
168180
assert "X-Testsolar-Testcase" in request.headers
169-
assert request.headers["X-Testsolar-Testcase"] == "test_file.py::test_case"
181+
assert request.headers["X-Testsolar-Testcase"] == "test_file.py%3A%3Atest_case"
170182

171183
def test_requests_no_injection_when_nodeid_not_set(self) -> None:
172184
"""Test that requests does not inject header when nodeid is not set."""

‎pytest/testtool.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ schemaVersion: 1.0
22
name: pytest
33
nameZh: pytest自动化测试
44
lang: python
5-
version: '0.1.76'
5+
version: '0.1.77'
66
langType: INTERPRETED
77
description: |-
88
pytest是一个成熟的全功能Python测试工具,可以帮助您编写更好的程序。此测试工具允许您在TestSolar上运行pytest。

0 commit comments

Comments
 (0)