143 lines
5.2 KiB
Python
143 lines
5.2 KiB
Python
"""候选状态与并发:CAS 定位、编辑后旧候选拒绝、并发采纳唯一成功。"""
|
||
|
||
import pytest
|
||
from pydantic import TypeAdapter
|
||
|
||
from muse.共享.错误 import Muse错误
|
||
from muse.正式变更.接口 import 作者动作
|
||
from muse.正文写作.接口 import 文本节点, 正文草稿, 段落
|
||
|
||
pytestmark = pytest.mark.数据库
|
||
|
||
|
||
def _建候选(环境, 命令: str, 文本: str, 预期版本: int = 0):
|
||
作者 = 环境["作者"]
|
||
候选 = (
|
||
环境["装配"]
|
||
.要求正文()
|
||
.创建人工候选(
|
||
作者,
|
||
命令,
|
||
"ch-1",
|
||
预期版本,
|
||
正文草稿((段落("p1", (文本节点(文本),)),)),
|
||
)
|
||
)
|
||
候选ID = next(
|
||
r["candidate_id"] for r in 候选["results"] if isinstance(r, dict) and "candidate_id" in r
|
||
)
|
||
候选行 = 环境["装配"].要求正文().读取候选(作者, 候选ID)
|
||
from muse.正文写作.接口 import 候选定位
|
||
|
||
定位 = 候选定位(
|
||
候选行["candidate_id"],
|
||
候选行["revision"],
|
||
候选行["candidate_hash"],
|
||
候选行["document_id"],
|
||
候选行["current_document_revision"],
|
||
)
|
||
审阅 = 环境["装配"].要求正文().打开候选审阅(作者, 定位)
|
||
return 定位, 审阅
|
||
|
||
|
||
def test_候选哈希不匹配采纳拒绝__16d013(章后环境, 章后工具):
|
||
环境 = 章后环境
|
||
from muse.正文写作.接口 import 候选定位
|
||
|
||
定位, 审阅 = _建候选(环境, "cas-cand-1", "林深在码头。")
|
||
坏定位 = 候选定位(
|
||
定位.candidate_id,
|
||
定位.candidate_revision,
|
||
"0" * 64,
|
||
定位.target_ref,
|
||
定位.expected_revision,
|
||
)
|
||
with pytest.raises(Muse错误) as 异常:
|
||
环境["装配"].要求正文().决定候选(
|
||
环境["作者"],
|
||
"cas-adopt-bad",
|
||
坏定位,
|
||
作者动作.采纳,
|
||
审阅["review_id"],
|
||
审阅["review_hash"],
|
||
("document",),
|
||
)
|
||
assert 异常.value.错误码 in {"REVISION_CONFLICT", "SCOPE_DENIED"}
|
||
|
||
|
||
def test_正文编辑后旧候选采纳拒绝但明确弃用允许__16d024(章后环境, 章后工具):
|
||
环境 = 章后环境
|
||
定位, 审阅 = _建候选(环境, "stale-cand-1", "候选版本的正文。")
|
||
# 正文前进一格:旧候选基线陈旧。
|
||
环境["剧本"].append(章后工具.抽取输出("编辑后的摘要。", []))
|
||
章后工具.保存一章("ch-1", "作者直接改过的新正文。")
|
||
with pytest.raises(Muse错误) as 异常:
|
||
环境["装配"].要求正文().决定候选(
|
||
环境["作者"],
|
||
"stale-adopt-1",
|
||
定位,
|
||
作者动作.采纳,
|
||
审阅["review_id"],
|
||
审阅["review_hash"],
|
||
("document",),
|
||
)
|
||
assert 异常.value.错误码 in {"SOURCE_STALE", "REVISION_CONFLICT"}
|
||
# 陈旧候选仍可明确弃用:作者端对当前版本重开审阅后拒绝。
|
||
from muse.正文写作.接口 import 候选定位
|
||
|
||
当前行 = 环境["装配"].要求正文().读取候选(环境["作者"], 定位.candidate_id)
|
||
重开定位 = 候选定位(
|
||
当前行["candidate_id"],
|
||
当前行["revision"],
|
||
当前行["candidate_hash"],
|
||
当前行["document_id"],
|
||
当前行["current_document_revision"],
|
||
)
|
||
重开审阅 = 环境["装配"].要求正文().打开候选审阅(环境["作者"], 重开定位)
|
||
环境["装配"].要求正文().决定候选(
|
||
环境["作者"],
|
||
"stale-reject-1",
|
||
重开定位,
|
||
作者动作.拒绝,
|
||
重开审阅["review_id"],
|
||
重开审阅["review_hash"],
|
||
(),
|
||
)
|
||
行 = 环境["装配"].要求正文().读取候选(环境["作者"], 定位.candidate_id)
|
||
assert 行["decision"] == "reject"
|
||
# 作者正文不受影响。
|
||
正文 = 环境["装配"].要求正文().读取正文(环境["作者"], "ch-1")
|
||
assert TypeAdapter(正文草稿).validate_python(正文["document"])
|
||
|
||
|
||
def test_并发采纳唯一成功且正文版本唯一__16d035(章后环境, 章后工具):
|
||
环境 = 章后环境
|
||
正文服务 = 环境["装配"].要求正文()
|
||
定位1, 审阅1 = _建候选(环境, "conc-cand-1", "并发候选甲。")
|
||
定位2, 审阅2 = _建候选(环境, "conc-cand-2", "并发候选乙。")
|
||
环境["剧本"].append(章后工具.抽取输出("并发摘要一。", []))
|
||
回执1 = 正文服务.决定候选(
|
||
环境["作者"],
|
||
"conc-adopt-1",
|
||
定位1,
|
||
作者动作.采纳,
|
||
审阅1["review_id"],
|
||
审阅1["review_hash"],
|
||
("document",),
|
||
)
|
||
# 第二个候选基于同一旧版本:采纳时基线已前进,必须被拒绝。
|
||
with pytest.raises(Muse错误) as 异常:
|
||
正文服务.决定候选(
|
||
环境["作者"],
|
||
"conc-adopt-2",
|
||
定位2,
|
||
作者动作.采纳,
|
||
审阅2["review_id"],
|
||
审阅2["review_hash"],
|
||
("document",),
|
||
)
|
||
assert 异常.value.错误码 in {"SOURCE_STALE", "REVISION_CONFLICT"}
|
||
正文 = 正文服务.读取正文(环境["作者"], "ch-1")
|
||
assert 正文["revision"] == 1
|
||
assert 回执1["receipt_id"]
|