- FastAPI backend with build queue, WebSocket logs, task management - Vue 3 frontend with build/config/history views - Xcode project build automation with IPA export - Fix: initialize build_dir before try block to ensure cleanup on early failure
161 lines
5.1 KiB
Python
161 lines
5.1 KiB
Python
"""边界情况测试"""
|
||
import json
|
||
import pytest
|
||
|
||
|
||
def test_invalid_json_body(client, tmp_config):
|
||
"""无效 JSON 请求体"""
|
||
resp = client.post(
|
||
"/api/tasks",
|
||
content="not json",
|
||
headers={"Content-Type": "application/json"},
|
||
)
|
||
assert resp.status_code == 422
|
||
|
||
|
||
def test_missing_required_fields(client, tmp_config):
|
||
"""缺少必填字段"""
|
||
resp = client.post("/api/tasks", json={"app_id": "1"})
|
||
assert resp.status_code == 422
|
||
|
||
|
||
def test_empty_app_id(client, tmp_config):
|
||
"""空 app_id"""
|
||
resp = client.post("/api/tasks", json={
|
||
"app_id": "",
|
||
"build_type": "Ad_Hoc",
|
||
"scheme_id": "1",
|
||
})
|
||
assert resp.status_code == 400
|
||
|
||
|
||
def test_server_name_with_special_chars(client, tmp_config):
|
||
"""服务器名称包含特殊字符"""
|
||
resp = client.post("/api/config/servers", json={
|
||
"name": "环境/测试",
|
||
"api": "https://test.com",
|
||
})
|
||
assert resp.status_code == 200
|
||
|
||
|
||
def test_branch_name_with_slash(client, tmp_config):
|
||
"""分支名包含斜杠"""
|
||
resp = client.post("/api/config/branches", json={"name": "feature/my-branch"})
|
||
assert resp.status_code == 200
|
||
assert "feature/my-branch" in client.get("/api/config/branches").json()
|
||
|
||
|
||
def test_branch_name_with_space(client, tmp_config):
|
||
"""分支名包含空格(应被 trim)"""
|
||
resp = client.post("/api/config/branches", json={"name": " "})
|
||
assert resp.status_code == 400
|
||
|
||
|
||
def test_config_backup_on_save(client, tmp_config):
|
||
"""保存配置时自动备份"""
|
||
# 先写一次产生文件
|
||
client.put("/api/config", json={"apps": {}, "schemes": {}, "branches": ["main"]})
|
||
|
||
# 再写一次,应该产生 .bak 文件
|
||
client.put("/api/config", json={"apps": {"1": {"name": "test"}}, "schemes": {}, "branches": ["main"]})
|
||
|
||
backup = tmp_config.with_suffix(".json.bak")
|
||
assert backup.exists()
|
||
|
||
|
||
def test_sequential_config_writes(client, tmp_config):
|
||
"""顺序多次写入配置"""
|
||
for i in range(5):
|
||
resp = client.post("/api/config/branches", json={"name": f"branch-{i}"})
|
||
assert resp.status_code == 200
|
||
|
||
branches = client.get("/api/config/branches").json()
|
||
for i in range(5):
|
||
assert f"branch-{i}" in branches
|
||
|
||
|
||
def test_task_status_filter(client, tmp_config):
|
||
"""按状态过滤任务"""
|
||
from unittest.mock import patch, AsyncMock
|
||
|
||
with patch("backend.services.build_queue.build_queue") as mock_queue:
|
||
mock_queue.submit = AsyncMock()
|
||
client.post("/api/tasks", json={
|
||
"app_id": "1", "build_type": "Ad_Hoc", "scheme_id": "1",
|
||
})
|
||
|
||
# 过滤 pending
|
||
resp = client.get("/api/tasks?status=pending")
|
||
assert resp.status_code == 200
|
||
assert len(resp.json()) >= 1
|
||
|
||
# 过滤 running(应该没有)
|
||
resp = client.get("/api/tasks?status=running")
|
||
assert len(resp.json()) == 0
|
||
|
||
|
||
def test_task_pagination(client, tmp_config):
|
||
"""任务分页"""
|
||
from unittest.mock import patch, AsyncMock
|
||
|
||
with patch("backend.services.build_queue.build_queue") as mock_queue:
|
||
mock_queue.submit = AsyncMock()
|
||
for _ in range(5):
|
||
client.post("/api/tasks", json={
|
||
"app_id": "1", "build_type": "Ad_Hoc", "scheme_id": "1",
|
||
})
|
||
|
||
resp = client.get("/api/tasks?limit=2&offset=0")
|
||
assert len(resp.json()) == 2
|
||
|
||
resp = client.get("/api/tasks?limit=2&offset=2")
|
||
assert len(resp.json()) == 2
|
||
|
||
|
||
def test_delete_server_not_in_use(client, tmp_config):
|
||
"""删除未被使用的服务器"""
|
||
# 先添加一个不被使用的服务器
|
||
client.post("/api/config/servers", json={"name": "临时环境", "api": "https://tmp.com"})
|
||
resp = client.delete("/api/config/servers/临时环境")
|
||
assert resp.status_code == 200
|
||
|
||
|
||
def test_update_full_config_replaces_all(client, tmp_config):
|
||
"""整体替换配置"""
|
||
new_config = {
|
||
"apps": {"99": {"name": "新App"}},
|
||
"schemes": {},
|
||
"servers": {},
|
||
"branches": ["release"],
|
||
}
|
||
resp = client.put("/api/config", json=new_config)
|
||
assert resp.status_code == 200
|
||
|
||
config = client.get("/api/config").json()
|
||
assert "99" in config["apps"]
|
||
assert config["branches"] == ["release"]
|
||
|
||
|
||
def test_scheme_id_auto_increment(client, tmp_config):
|
||
"""Scheme ID 自动递增"""
|
||
client.post("/api/config/schemes", json={"name": "sch2", "ossFloder": "f2"})
|
||
client.post("/api/config/schemes", json={"name": "sch3", "ossFloder": "f3"})
|
||
schemes = client.get("/api/config/schemes").json()
|
||
assert "2" in schemes
|
||
assert "3" in schemes
|
||
|
||
|
||
def test_build_settings_validation(client, tmp_config):
|
||
"""打包设置更新"""
|
||
# 更新为有效值
|
||
resp = client.put("/api/config/build", json={"max_concurrent_builds": 3})
|
||
assert resp.status_code == 200
|
||
assert client.get("/api/config/build").json()["max_concurrent_builds"] == 3
|
||
|
||
# 更新部分字段
|
||
resp = client.put("/api/config/build", json={"build_dir_retention_hours": 48})
|
||
assert resp.status_code == 200
|
||
settings = client.get("/api/config/build").json()
|
||
assert settings["build_dir_retention_hours"] == 48
|
||
assert settings["max_concurrent_builds"] == 3 # 未修改的保持不变
|