Skip to content

Commit ab60292

Browse files
xjkmfaxujing43
andauthored
【CI】 evil case (#3359)
* Add ci case for min token and max token * 【CI case】include total_tokens in the last packet of completion interface stream output * 边缘检测 ,攻击性测试 * 边缘检测 ,攻击性测试 * 边缘检测 ,攻击性测试 * 边缘检测 ,攻击性测试 --------- Co-authored-by: xujing43 <[email protected]>
1 parent cacc52b commit ab60292

File tree

1 file changed

+329
-0
lines changed

1 file changed

+329
-0
lines changed

test/ce/server/test_evil_cases.py

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,332 @@ def test_stop_seq_exceed_length():
122122
resp = send_request(URL, payload).json()
123123
assert resp.get("detail").get("object") == "error", "stop 超出长度应触发异常"
124124
assert "exceeds the limit stop_seqs_max_len" in resp.get("detail").get("message", ""), "未返回预期的报错信息"
125+
126+
127+
def test_multilingual_input():
128+
"""测试多语言混合输入是否能够被正确处理"""
129+
data = {
130+
"messages": [
131+
{
132+
"role": "user",
133+
"content": "这是一个包含多种语言的输入:Hello, 世界!Bonjour, le monde! Hola, el mundo! こんにちは、世界!"
134+
}
135+
],
136+
"stream": False,
137+
138+
}
139+
payload = build_request_payload(TEMPLATE, data)
140+
resp = send_request(URL, payload).json()
141+
142+
# 验证响应是否包含有效的回复
143+
assert "choices" in resp, "未收到有效的回复"
144+
assert len(resp["choices"]) > 0, "回复为空"
145+
assert "message" in resp["choices"][0], "回复中未包含消息内容"
146+
assert "content" in resp["choices"][0]["message"], "回复中未包含内容字段"
147+
# 验证模型是否能够正确处理多语言输入
148+
response_content = resp["choices"][0]["message"]["content"]
149+
assert response_content.strip() != "", "模型未生成任何内容"
150+
print("多语言混合输入测试通过!")
151+
152+
153+
154+
def test_too_long_input():
155+
"""测试超长输入是否被正确处理"""
156+
data = {
157+
"messages": [
158+
{
159+
"role": "user",
160+
"content": "a," * 200000 # 超过最大输入长度
161+
}
162+
],
163+
"stream": False
164+
}
165+
payload = build_request_payload(TEMPLATE, data)
166+
resp = send_request(URL, payload).json()
167+
assert resp["detail"].get("object") == "error", "超长输入未被识别为错误"
168+
assert "Input text is too long" in resp["detail"].get("message", ""), "未检测到最大长度限制错误"
169+
170+
171+
def test_empty_input():
172+
"""测试空输入是否被正确处理"""
173+
data = {
174+
"messages": [
175+
{
176+
"role": "user",
177+
"content": "" # 空输入
178+
}
179+
],
180+
"stream": False
181+
}
182+
payload = build_request_payload(TEMPLATE, data)
183+
resp = send_request(URL, payload).json()
184+
assert "error" not in resp.get("object"), "空输入被识别为错误"
185+
assert len(resp["choices"][0]["message"]["content"]) > 0, "内容为空时,回复为空"
186+
187+
188+
def test_prompt_only_spaces():
189+
"""messages content 为纯空格字符串,服务正常返回"""
190+
data = {
191+
"messages": [
192+
{
193+
"role": "user",
194+
"content": " ", # 纯空格
195+
}
196+
],
197+
"stream": False,
198+
"max_tokens": 10,
199+
}
200+
payload = build_request_payload(TEMPLATE, data)
201+
resp = send_request(URL, payload).json()
202+
assert resp.get("object") == "chat.completion", "应返回 chat.completion 对象"
203+
response_content = resp["choices"][0]["message"]["content"]
204+
assert len(response_content) > 0, "messages content为空,未正常生成回复"
205+
206+
207+
def test_illegal_characters():
208+
"""测试非法字符输入是否被正确处理"""
209+
data = {
210+
"messages": [
211+
{
212+
"role": "user",
213+
"content": "非洲的首都是?:\x00\x01\x02" # 非法字符
214+
}
215+
],
216+
"stream": False
217+
}
218+
payload = build_request_payload(TEMPLATE, data)
219+
resp = send_request(URL, payload).json()
220+
assert len(resp["choices"][0]["message"]["content"]) > 0, "非法字符输入影响模型回复"
221+
222+
223+
def test_sql_injection():
224+
"""测试 SQL 注入攻击是否被正确处理"""
225+
data = {
226+
"messages": [
227+
{
228+
"role": "user",
229+
"content": "SELECT * FROM users WHERE username = 'admin' OR '1'='1';" # SQL 注入攻击
230+
}
231+
],
232+
"stream": False,
233+
"max_tokens": 50,
234+
}
235+
payload = build_request_payload(TEMPLATE, data)
236+
resp = send_request(URL, payload).json()
237+
assert "message" in resp["choices"][0], "回复中未包含消息内容"
238+
assert "content" in resp["choices"][0]["message"], "回复中未包含内容字段"
239+
response_content = resp["choices"][0]["message"]["content"]
240+
assert len(response_content) > 0, "SQL 注入攻击影响模型回复"
241+
242+
243+
def test_xss_attack():
244+
"""测试 XSS 攻击是否被正确处理"""
245+
data = {
246+
"messages": [
247+
{
248+
"role": "user",
249+
"content": "<script>alert('XSS');</script>" # XSS 攻击
250+
}
251+
],
252+
"stream": False,
253+
"max_tokens": 50,
254+
}
255+
payload = build_request_payload(TEMPLATE, data)
256+
resp = send_request(URL, payload).json()
257+
assert "message" in resp["choices"][0], "回复中未包含消息内容"
258+
assert "content" in resp["choices"][0]["message"], "回复中未包含内容字段"
259+
response_content = resp["choices"][0]["message"]["content"]
260+
assert len(response_content) > 0, "XSS 攻击未被正确处理"
261+
262+
263+
def test_stop_empty_string():
264+
"""测试 stop 参数为空字符串时的行为"""
265+
data = {
266+
"stream": False,
267+
"messages": [
268+
{
269+
"role": "user",
270+
"content": "非洲的首都是?"
271+
}
272+
],
273+
"max_tokens": 10,
274+
"stop": "" # 空字符串
275+
}
276+
payload = build_request_payload(TEMPLATE, data)
277+
resp = send_request(URL, payload).json()
278+
assert resp.get("object") == "chat.completion", "应返回 chat.completion 对象"
279+
assert len(resp.get("choices", [])[0].get("message", {}).get("content", "")) > 0, "应生成有效文本"
280+
281+
282+
def test_stop_multiple_strings():
283+
"""测试 stop 参数为多个字符串时的行为"""
284+
data = {
285+
"stream": False,
286+
"messages": [
287+
{
288+
"role": "user",
289+
"content": "非洲的首都是?"
290+
}
291+
],
292+
"max_tokens": 50,
293+
"stop": ["。", "!", "?"] # 多个停止条件
294+
}
295+
payload = build_request_payload(TEMPLATE, data)
296+
resp = send_request(URL, payload).json()
297+
assert resp.get("object") == "chat.completion", "应返回 chat.completion 对象"
298+
generated_text = resp.get("choices")[0].get("message", {}).get("content", "")
299+
assert any(stop in generated_text for stop in data["stop"]), "生成文本应包含 stop 序列之一"
300+
301+
302+
def test_stop_with_special_characters():
303+
"""测试 stop 参数为包含特殊字符的字符串时的行为"""
304+
data = {
305+
"stream": False,
306+
"messages": [
307+
{
308+
"role": "user",
309+
"content": "非洲的首都是?"
310+
}
311+
],
312+
"max_tokens": 50,
313+
"stop": "!@#$%^&*()" # 包含特殊字符
314+
}
315+
payload = build_request_payload(TEMPLATE, data)
316+
resp = send_request(URL, payload).json()
317+
assert resp.get("object") == "chat.completion", "应返回 chat.completion 对象"
318+
generated_text = resp.get("choices")[0].get("message", {}).get("content", "")
319+
assert any(char in generated_text for char in data["stop"]), "生成文本应包含 stop 序列中的特殊字符之一"
320+
321+
322+
def test_stop_with_newlines():
323+
"""测试 stop 参数为包含换行符的字符串时的行为"""
324+
data = {
325+
"stream": False,
326+
"messages": [
327+
{
328+
"role": "user",
329+
"content": "非洲的首都是?"
330+
}
331+
],
332+
"max_tokens": 50,
333+
"stop": "\n\n" # 包含换行符
334+
}
335+
payload = build_request_payload(TEMPLATE, data)
336+
resp = send_request(URL, payload).json()
337+
assert resp.get("object") == "chat.completion", "应返回 chat.completion 对象"
338+
generated_text = resp.get("choices")[0].get("message", {}).get("content", "")
339+
assert data["stop"] in generated_text, "生成文本应包含 stop 序列"
340+
341+
342+
def test_model_empty():
343+
"""model 参数为空,不影响服务"""
344+
data = {
345+
"messages": [
346+
{
347+
"role": "user",
348+
"content": "非洲的首都是?",
349+
}
350+
],
351+
"stream": False,
352+
"max_tokens": 10,
353+
"model": "" # 空模型
354+
}
355+
payload = build_request_payload(TEMPLATE, data)
356+
resp = send_request(URL, payload).json()
357+
assert resp.get("object") == "chat.completion", "应返回 chat.completion 对象"
358+
response_content = resp["choices"][0]["message"]["content"]
359+
assert len(response_content) > 0, "模型名为空,未正常生成回复"
360+
361+
362+
def test_model_invalid():
363+
"""model 参数为不存在的模型,不影响服务"""
364+
data = {
365+
"messages": [
366+
{
367+
"role": "user",
368+
"content": "非洲的首都是?",
369+
}
370+
],
371+
"stream": False,
372+
"max_tokens": 10,
373+
"model": "non-existent-model" # 不存在的模型
374+
}
375+
payload = build_request_payload(TEMPLATE, data)
376+
resp = send_request(URL, payload).json()
377+
assert resp.get("object") == "chat.completion", "不存在的 model 应触发校验异常"
378+
assert "non-existent-model" in resp.get("model"), "未返回预期的 model 信息"
379+
assert len(resp.get("choices")[0].get("message").get("content")) > 0, "模型名为不存在的 model,未正常生成回复"
380+
381+
382+
def test_model_with_special_characters():
383+
"""model 参数为非法格式(例如包含特殊字符),不影响服务"""
384+
data = {
385+
"messages": [
386+
{
387+
"role": "user",
388+
"content": "非洲的首都是?",
389+
}
390+
],
391+
"stream": False,
392+
"max_tokens": 10,
393+
"model": "!@#" # 包含特殊字符
394+
}
395+
payload = build_request_payload(TEMPLATE, data)
396+
resp = send_request(URL, payload).json()
397+
assert resp.get("object") == "chat.completion", "不存在的 model 应触发校验异常"
398+
assert "!@#" in resp.get("model"), "未返回预期的 model 信息"
399+
assert len(resp.get("choices")[0].get("message").get("content")) > 0, "模型名为model 参数为非法格式,未正常生成回复"
400+
401+
402+
def test_max_tokens_negative():
403+
"""max_tokens 为负数,服务应报错"""
404+
data = {
405+
"messages": [
406+
{
407+
"role": "user",
408+
"content": "非洲的首都是?",
409+
}
410+
],
411+
"stream": False,
412+
"max_tokens": -10, # 负数
413+
}
414+
payload = build_request_payload(TEMPLATE, data)
415+
resp = send_request(URL, payload).json()
416+
assert resp.get("detail").get("object") == "error", "max_tokens < 0 未触发校验异常"
417+
assert 'max_tokens can be defined [1,' in resp.get("detail").get("message"), "未返回预期的 max_tokens 错误信息"
418+
419+
420+
def test_max_tokens_min():
421+
"""测试 max_tokens 达到异常值0 时的行为"""
422+
data = {
423+
"messages": [
424+
{
425+
"role": "user",
426+
"content": "非洲的首都是?",
427+
}
428+
],
429+
"stream": False,
430+
"max_tokens": 0, # 最小值
431+
}
432+
payload = build_request_payload(TEMPLATE, data)
433+
resp = send_request(URL, payload).json()
434+
assert resp.get('detail').get("object") == "error", "max_tokens未0时API未拦截住"
435+
assert "reasoning_max_tokens must be between max_tokens and 1" in resp.get('detail').get("message", ""), "未返回预期的 max_tokens 达到异常值0 的 错误信息"
436+
437+
438+
def test_max_tokens_non_integer():
439+
"""max_tokens 为非整数,服务应报错"""
440+
data = {
441+
"messages": [
442+
{
443+
"role": "user",
444+
"content": "非洲的首都是?",
445+
}
446+
],
447+
"stream": False,
448+
"max_tokens": 10.5, # 非整数
449+
}
450+
payload = build_request_payload(TEMPLATE, data)
451+
resp = send_request(URL, payload).json()
452+
assert resp.get('detail')[0].get("msg") == "Input should be a valid integer, got a number with a fractional part", "未返回预期的 max_tokens 为非整数的错误信息"
453+

0 commit comments

Comments
 (0)