160 lines
6.6 KiB
Python
160 lines
6.6 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import re
|
|
import time
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from .helpers import ReleaseApiClient
|
|
|
|
|
|
def _select_rule_set(client: ReleaseApiClient) -> dict[str, Any]:
|
|
preferred_rule_type = os.getenv("LEAUDIT_TEST_RULE_TYPE", "contract.entrust").strip()
|
|
rule_sets = ReleaseApiClient.json_data(client.get("/api/rule-sets"))
|
|
assert isinstance(rule_sets, list)
|
|
assert rule_sets, "当前环境没有规则集,无法测试版本管理"
|
|
|
|
for item in rule_sets:
|
|
if str(item.get("ruleType") or "") == preferred_rule_type and item.get("currentVersionId"):
|
|
return item
|
|
|
|
for item in rule_sets:
|
|
if item.get("currentVersionId"):
|
|
return item
|
|
|
|
pytest.skip("当前环境没有带 currentVersionId 的规则集,无法测试发布/回滚闭环")
|
|
|
|
|
|
def _set_metadata_version(yaml_text: str, version_no: str) -> str:
|
|
lines = yaml_text.splitlines()
|
|
metadata_index: int | None = None
|
|
version_pattern = re.compile(r"^(\s*)version\s*:")
|
|
|
|
for index, line in enumerate(lines):
|
|
if line.strip() == "metadata:":
|
|
metadata_index = index
|
|
continue
|
|
if metadata_index is None:
|
|
continue
|
|
if line and not line.startswith((" ", "\t")):
|
|
break
|
|
match = version_pattern.match(line)
|
|
if match:
|
|
lines[index] = f"{match.group(1)}version: '{version_no}'"
|
|
return "\n".join(lines) + ("\n" if yaml_text.endswith("\n") else "")
|
|
|
|
if metadata_index is None:
|
|
return f"metadata:\n version: '{version_no}'\n{yaml_text}"
|
|
|
|
lines.insert(metadata_index + 1, f" version: '{version_no}'")
|
|
return "\n".join(lines) + ("\n" if yaml_text.endswith("\n") else "")
|
|
|
|
|
|
def _rule_set_by_type(client: ReleaseApiClient, rule_type: str) -> dict[str, Any]:
|
|
rule_sets = ReleaseApiClient.json_data(client.get("/api/rule-sets"))
|
|
for item in rule_sets:
|
|
if str(item.get("ruleType") or "") == rule_type:
|
|
return item
|
|
raise AssertionError(f"规则集不存在: {rule_type}")
|
|
|
|
|
|
@pytest.mark.release
|
|
def test_g6_rule_detail_version_management_save_publish_and_rollback(admin_client: ReleaseApiClient) -> None:
|
|
"""覆盖规则配置详情页的版本管理闭环。
|
|
|
|
该用例会创建一个真实历史版本并短暂发布,最后回滚到执行前的 currentVersionId。
|
|
"""
|
|
|
|
target_rule_set = _select_rule_set(admin_client)
|
|
rule_type = str(target_rule_set["ruleType"])
|
|
original_rule_set_id = int(target_rule_set["id"])
|
|
original_current_version_id = int(target_rule_set["currentVersionId"])
|
|
original_tenant_code = str(target_rule_set.get("effectiveTenantCode") or "")
|
|
|
|
versions_before = ReleaseApiClient.json_data(admin_client.get(f"/api/rule-sets/{rule_type}/versions"))
|
|
assert isinstance(versions_before, list)
|
|
assert {int(item["ruleSetId"]) for item in versions_before} == {original_rule_set_id}
|
|
assert original_current_version_id in {int(item["id"]) for item in versions_before}
|
|
|
|
content = ReleaseApiClient.json_data(admin_client.get(f"/api/rule-sets/versions/{original_current_version_id}/content"))
|
|
assert int(content["ruleSetId"]) == original_rule_set_id
|
|
assert str(content["ruleType"]) == rule_type
|
|
assert str(content["yamlText"]).strip()
|
|
|
|
new_version_no = f"pytest-vm-{int(time.time())}"
|
|
yaml_text = _set_metadata_version(str(content["yamlText"]), new_version_no)
|
|
created_version_id: int | None = None
|
|
|
|
try:
|
|
created = ReleaseApiClient.json_data(
|
|
admin_client.post(
|
|
f"/api/rule-sets/{rule_type}/versions",
|
|
json={
|
|
"yamlText": yaml_text,
|
|
"changeNote": f"pytest rule detail version management smoke {new_version_no}",
|
|
},
|
|
expected_status=200,
|
|
)
|
|
)
|
|
created_version_id = int(created["id"])
|
|
assert int(created["ruleSetId"]) == original_rule_set_id
|
|
assert str(created["versionNo"]) == new_version_no
|
|
assert str(created["status"]) == "draft"
|
|
|
|
versions_after_create = ReleaseApiClient.json_data(admin_client.get(f"/api/rule-sets/{rule_type}/versions"))
|
|
assert created_version_id in {int(item["id"]) for item in versions_after_create}
|
|
assert {int(item["ruleSetId"]) for item in versions_after_create} == {original_rule_set_id}
|
|
|
|
published = ReleaseApiClient.json_data(
|
|
admin_client.post(
|
|
f"/api/rule-sets/{rule_type}/publish",
|
|
json={"versionId": created_version_id},
|
|
expected_status=200,
|
|
)
|
|
)
|
|
assert int(published["id"]) == created_version_id
|
|
assert int(published["ruleSetId"]) == original_rule_set_id
|
|
assert str(published["status"]) == "published"
|
|
|
|
current_after_publish = _rule_set_by_type(admin_client, rule_type)
|
|
assert int(current_after_publish["id"]) == original_rule_set_id
|
|
assert int(current_after_publish["currentVersionId"]) == created_version_id
|
|
assert str(current_after_publish.get("effectiveTenantCode") or "") == original_tenant_code
|
|
|
|
finally:
|
|
if created_version_id:
|
|
admin_client.post(
|
|
f"/api/rule-sets/{rule_type}/rollback",
|
|
json={"versionId": original_current_version_id},
|
|
expected_status=200,
|
|
)
|
|
|
|
restored = _rule_set_by_type(admin_client, rule_type)
|
|
assert int(restored["id"]) == original_rule_set_id
|
|
assert int(restored["currentVersionId"]) == original_current_version_id
|
|
assert str(restored.get("effectiveTenantCode") or "") == original_tenant_code
|
|
|
|
|
|
@pytest.mark.release
|
|
def test_g6_rule_detail_version_management_rejects_cross_rule_set_publish(admin_client: ReleaseApiClient) -> None:
|
|
"""发布接口必须拒绝把其他规则集的版本发布到当前规则类型。"""
|
|
|
|
rule_sets = ReleaseApiClient.json_data(admin_client.get("/api/rule-sets"))
|
|
candidates = [item for item in rule_sets if item.get("currentVersionId")]
|
|
if len(candidates) < 2:
|
|
pytest.skip("当前环境少于两个带 currentVersionId 的规则集,无法测试跨规则集发布拦截")
|
|
|
|
left = candidates[0]
|
|
right = next((item for item in candidates[1:] if str(item["ruleType"]) != str(left["ruleType"])), None)
|
|
if right is None:
|
|
pytest.skip("当前环境没有可用于跨规则类型发布拦截的第二个规则集")
|
|
|
|
response = admin_client.post(
|
|
f"/api/rule-sets/{left['ruleType']}/publish",
|
|
json={"versionId": int(right["currentVersionId"])},
|
|
expected_status=403,
|
|
)
|
|
assert "当前租户不能发布或回滚其他租户的规则版本" in response.text
|