fix: 一键同步模型接口同步修复并携带上游 base_url,防止 sub2api 账号 base_url 被清空或置为默认值

This commit is contained in:
liumangmang
2026-07-02 16:56:45 +08:00
parent 59be00bd11
commit 4645460ff9
2 changed files with 94 additions and 26 deletions
+53 -16
View File
@@ -43,6 +43,9 @@ def test_sync_upstream_models_workflow(db_session, monkeypatch):
up = Upstream(id=10, name="Upstream A", base_url="http://upstream-a")
db_session.add(up)
up_empty = Upstream(id=11, name="Upstream Empty", base_url="")
db_session.add(up_empty)
db_session.commit()
# 2. 插入本地导入的 Key 记录
@@ -90,7 +93,7 @@ def test_sync_upstream_models_workflow(db_session, monkeypatch):
imported_website_id=w.id,
imported_account_id="1004",
)
# k5: 属于本站,但同步接口返回空模型(应当标记为 failed,且不覆盖
# k5: 属于本站,但同步接口返回空模型(应当标记为 failed,但应先安全修复 base_url
k5 = UpstreamGeneratedKey(
id=105,
upstream_id=up.id,
@@ -101,7 +104,7 @@ def test_sync_upstream_models_workflow(db_session, monkeypatch):
imported_website_id=w.id,
imported_account_id="1005",
)
# k6: 属于本站,但同步接口抛错(应当标记为 failed,且不覆盖
# k6: 属于本站,但同步接口抛错(应当标记为 failed,但应先安全修复 base_url
k6 = UpstreamGeneratedKey(
id=106,
upstream_id=up.id,
@@ -112,7 +115,18 @@ def test_sync_upstream_models_workflow(db_session, monkeypatch):
imported_website_id=w.id,
imported_account_id="1006",
)
db_session.add_all([k1, k2, k3, k4, k5, k6])
# k7: 属于本站,但对应上游 base_url 为空(应当直接标记为 failed 且不调用同步和写回)
k7 = UpstreamGeneratedKey(
id=107,
upstream_id=up_empty.id,
group_id="g1",
key_name="key-107",
key_value="val-107",
status="active",
imported_website_id=w.id,
imported_account_id="1007",
)
db_session.add_all([k1, k2, k3, k4, k5, k6, k7])
db_session.commit()
# Mock Sub2Api 客户端
@@ -131,10 +145,11 @@ def test_sync_upstream_models_workflow(db_session, monkeypatch):
def list_accounts(self):
return [
{"id": 1001, "name": "acc-1001", "credentials": {"api_key": "k1", "model_mapping": {"old": "old"}}},
{"id": 1001, "name": "acc-1001", "credentials": {"api_key": "k1", "model_mapping": {"old": "old"}, "base_url": "http://default-base-url"}},
{"id": "abc", "name": "acc-abc", "credentials": {}},
{"id": 1005, "name": "acc-1005", "credentials": {"api_key": "k5"}},
{"id": 1006, "name": "acc-1006", "credentials": {"api_key": "k6"}},
{"id": 1007, "name": "acc-1007", "credentials": {"api_key": "k7"}},
]
def extract_id(self, val):
@@ -160,25 +175,31 @@ def test_sync_upstream_models_workflow(db_session, monkeypatch):
# 验证总体结果
assert res.success is False # 存在 failed 账号,success 应该为 False
assert "成功 1 个" in res.message
assert "失败 2" in res.message
assert "失败 3" in res.message
assert "跳过 2 个" in res.message
items = res.items
assert len(items) == 5
assert len(items) == 6
# 1001 成功
# 1001 成功 (修复 Base URL 并同步)
item_1001 = next(i for i in items if i.account_id == "1001")
assert item_1001.status == "success"
assert item_1001.model_count == 2
assert item_1001.models == ["gpt-3.5-turbo", "gpt-4"]
assert "已修复 Base URL" in item_1001.message
# 1001 的 update 应当只传递增量的 model_mapping,防止敏感字段丢失
assert len(update_calls) == 1
assert update_calls[0][0] == "1001"
assert "api_key" not in update_calls[0][1]["credentials"]
assert update_calls[0][1]["credentials"]["model_mapping"] == {
"gpt-3.5-turbo": "gpt-3.5-turbo",
"gpt-4": "gpt-4"
# 1001 的两次 update 调用检测
calls_1001 = [call for call in update_calls if call[0] == "1001"]
assert len(calls_1001) == 2
# 第一次安全修复:只传递 base_url
assert calls_1001[0][1]["credentials"] == {"base_url": "http://upstream-a"}
# 第二次同步成功写入:传递 base_url + model_mapping
assert calls_1001[1][1]["credentials"] == {
"base_url": "http://upstream-a",
"model_mapping": {
"gpt-3.5-turbo": "gpt-3.5-turbo",
"gpt-4": "gpt-4"
}
}
# abc 跳过
@@ -191,15 +212,31 @@ def test_sync_upstream_models_workflow(db_session, monkeypatch):
assert item_1004.status == "skipped"
assert "不存在" in item_1004.message
# 1005 失败 (空模型)
# 1005 失败 (空模型,但也应当执行了第一次安全修复的 update_account)
item_1005 = next(i for i in items if i.account_id == "1005")
assert item_1005.status == "failed"
assert "已修复 Base URL" in item_1005.message
assert "为空" in item_1005.message
calls_1005 = [call for call in update_calls if call[0] == "1005"]
assert len(calls_1005) == 1
assert calls_1005[0][1]["credentials"] == {"base_url": "http://upstream-a"}
# 1006 失败 (抛错)
# 1006 失败 (抛错,但应当执行了第一次安全修复的 update_account)
item_1006 = next(i for i in items if i.account_id == "1006")
assert item_1006.status == "failed"
assert "已修复 Base URL" in item_1006.message
assert "Network Error" in item_1006.message
calls_1006 = [call for call in update_calls if call[0] == "1006"]
assert len(calls_1006) == 1
assert calls_1006[0][1]["credentials"] == {"base_url": "http://upstream-a"}
# 1007 失败 (上游 base_url 为空,不应当调用 update_account 且不调用同步模型)
item_1007 = next(i for i in items if i.account_id == "1007")
assert item_1007.status == "failed"
assert "base_url 为空" in item_1007.message
calls_1007 = [call for call in update_calls if call[0] == "1007"]
assert len(calls_1007) == 0
assert "1007" not in sync_calls
assert closed_count == 1