Compose name-first form write plans
This commit is contained in:
@@ -3129,6 +3129,67 @@ def test_saved_state_forms_search_default_is_name_first(monkeypatch: pytest.Monk
|
||||
assert storage_marker not in str(result)
|
||||
|
||||
|
||||
def test_saved_state_forms_search_infers_public_extension_name_without_filter(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
extension_guid = "fb26cf42-7609-11f1-828f-005056b0d483"
|
||||
file_name = f"{extension_guid}__form-guid.0"
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
"extension_map_by_guid",
|
||||
lambda base_id: {extension_guid: {"guid": extension_guid, "name": "test2"}},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
"storage_files_list",
|
||||
lambda payload: {"status": "ok", "files": [{"FileName": file_name}]},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
"saved_state_form_search_row",
|
||||
lambda **kwargs: {
|
||||
"table": "ConfigCASSave",
|
||||
"file_name": file_name,
|
||||
"name": "t_Форма",
|
||||
"owner": {"status": "resolved", "kind": "Catalog", "name": "test2"},
|
||||
"form": {"name": "t_Форма"},
|
||||
"source": {"table": "ConfigCASSave", "file_name": file_name},
|
||||
"matches": [
|
||||
{
|
||||
"name": "ЗаменаДомена",
|
||||
"section": "commands",
|
||||
"writable_properties": [
|
||||
{
|
||||
"property": "title",
|
||||
"presentation": "Заголовок",
|
||||
"value": "Замена домена",
|
||||
"value_type": "string",
|
||||
}
|
||||
],
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
result = adapter_server.metadata_saved_state_forms_search(
|
||||
{
|
||||
"base_id": "upo_test",
|
||||
"tables": ["ConfigCASSave"],
|
||||
"limit": 1,
|
||||
}
|
||||
)
|
||||
|
||||
form = result["forms"][0]
|
||||
assert form["selector"]["extension"] == "test2"
|
||||
assert form["matches"][0]["selector"] == {
|
||||
"extension": "test2",
|
||||
"ref": "Catalog.test2",
|
||||
"form": "t_Форма",
|
||||
"qualified_name": "test2.t_Форма",
|
||||
"command": "ЗаменаДомена",
|
||||
}
|
||||
assert extension_guid not in str(result)
|
||||
assert "ConfigCASSave" not in str(result["forms"])
|
||||
|
||||
|
||||
def test_saved_state_form_search_resolves_owner_for_internal_name_first_write(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
@@ -14015,6 +14076,87 @@ def test_mcp_selector_chain_smoke_uses_generic_placeholders() -> None:
|
||||
assert concrete_value not in examples_json
|
||||
|
||||
|
||||
def test_mcp_selector_chain_selects_name_first_form_write_plan_candidate() -> None:
|
||||
candidate = mcp_selector_chain_smoke.first_public_form_write_plan_candidate(
|
||||
{
|
||||
"forms": [
|
||||
{
|
||||
"selector": {
|
||||
"extension": "test2",
|
||||
"ref": "Catalog.test2",
|
||||
"form": "t_Форма",
|
||||
},
|
||||
"matches": [
|
||||
{
|
||||
"selector": {
|
||||
"extension": "test2",
|
||||
"ref": "Catalog.test2",
|
||||
"form": "t_Форма",
|
||||
"command": "ЗаменаДомена",
|
||||
},
|
||||
"writable_properties": [
|
||||
{
|
||||
"property": "name",
|
||||
"presentation": "Имя",
|
||||
"value": "ЗаменаДомена",
|
||||
"value_type": "string",
|
||||
},
|
||||
{
|
||||
"property": "title",
|
||||
"presentation": "Заголовок",
|
||||
"value": "Замена домена",
|
||||
"value_type": "string",
|
||||
},
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
assert candidate == {
|
||||
"target": {
|
||||
"kind": "form",
|
||||
"extension": "test2",
|
||||
"ref": "Catalog.test2",
|
||||
"form": "t_Форма",
|
||||
"command": "ЗаменаДомена",
|
||||
},
|
||||
"edit": {
|
||||
"property": "Заголовок",
|
||||
"value": "Замена домена [NAME-FIRST PLAN]",
|
||||
},
|
||||
}
|
||||
assert not any(key in candidate["target"] for key in ("table", "file_name", "guid", "form_guid"))
|
||||
|
||||
|
||||
def test_mcp_selector_chain_form_composition_strict_check() -> None:
|
||||
missing = mcp_selector_chain_smoke.live_form_write_plan_composition_required_issue(
|
||||
{
|
||||
"form_write_plan_composition": {
|
||||
"attempted": True,
|
||||
"status": "skipped_no_public_form_target",
|
||||
"composed": False,
|
||||
"name_first": False,
|
||||
}
|
||||
}
|
||||
)
|
||||
ready = mcp_selector_chain_smoke.live_form_write_plan_composition_required_issue(
|
||||
{
|
||||
"form_write_plan_composition": {
|
||||
"attempted": True,
|
||||
"status": "planned",
|
||||
"composed": True,
|
||||
"name_first": True,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
assert missing["code"] == "live_form_write_plan_composition_required"
|
||||
assert ready is None
|
||||
|
||||
|
||||
def test_mcp_selector_chain_smoke_rejects_concrete_selector_values() -> None:
|
||||
issues = mcp_selector_chain_smoke.validate_chain(
|
||||
{
|
||||
@@ -21551,6 +21693,100 @@ def test_metadata_write_plan_resolves_public_module_selector_internally(monkeypa
|
||||
assert hint["payload"]["expected_sha1"] == "saved-payload-sha1"
|
||||
|
||||
|
||||
def test_metadata_write_plan_resolves_public_form_selector_internally(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
seen: dict[str, Any] = {}
|
||||
|
||||
def fake_resolve(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
seen.update(payload)
|
||||
return {
|
||||
"schema": "onec_form_write_target_resolution.v1",
|
||||
"status": "ok",
|
||||
"source": {
|
||||
"kind": "live_sql",
|
||||
"table": "ConfigCASSave",
|
||||
"file_name": "extension-guid__form-guid.0",
|
||||
},
|
||||
"counts": {"matches": 1},
|
||||
}
|
||||
|
||||
monkeypatch.setattr(adapter_server, "metadata_form_write_target_resolve", fake_resolve)
|
||||
|
||||
result = adapter_server.metadata_write_plan(
|
||||
{
|
||||
"base_id": "upo_test",
|
||||
"target": {
|
||||
"kind": "form",
|
||||
"extension": "test2",
|
||||
"ref": "Catalog.test2",
|
||||
"form": "t_Форма",
|
||||
"command": "ЗаменаДомена",
|
||||
},
|
||||
"edits": [{"property": "Заголовок", "value": "Новое имя"}],
|
||||
"resolve_origin": False,
|
||||
}
|
||||
)
|
||||
|
||||
assert seen["table"] == "ConfigCASSave"
|
||||
assert seen["ref"] == "Catalog.test2"
|
||||
assert seen["form"] == "t_Форма"
|
||||
assert seen["command"] == "ЗаменаДомена"
|
||||
assert seen["property"] == "Заголовок"
|
||||
assert seen["value"] == "Новое имя"
|
||||
assert seen["include_storage"] is True
|
||||
assert result["allowed"] is True
|
||||
assert result["status"] == "planned"
|
||||
assert result["route"]["name_resolution"] == {
|
||||
"status": "resolved",
|
||||
"method": "metadata.form.write_target.resolve",
|
||||
"selector": {
|
||||
"extension": "test2",
|
||||
"ref": "Catalog.test2",
|
||||
"form": "t_Форма",
|
||||
"command": "ЗаменаДомена",
|
||||
},
|
||||
"counts": {"matches": 1},
|
||||
}
|
||||
hint = result["route"]["apply_payload_hint"]
|
||||
assert hint["ready_for_apply_method"] is True
|
||||
assert hint["payload"]["table"] == "ConfigCASSave"
|
||||
assert hint["payload"]["file_name"] == "extension-guid__form-guid.0"
|
||||
assert hint["payload"]["ref"] == "Catalog.test2"
|
||||
assert hint["payload"]["form"] == "t_Форма"
|
||||
assert hint["payload"]["command"] == "ЗаменаДомена"
|
||||
assert hint["payload"]["edits"] == [{"property": "Заголовок", "value": "Новое имя"}]
|
||||
|
||||
|
||||
def test_metadata_write_plan_reports_unresolved_public_form_selector(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setattr(
|
||||
adapter_server,
|
||||
"metadata_form_write_target_resolve",
|
||||
lambda payload: {
|
||||
"schema": "onec_form_write_target_resolution.v1",
|
||||
"status": "not_found",
|
||||
"counts": {"matches": 0},
|
||||
},
|
||||
)
|
||||
|
||||
result = adapter_server.metadata_write_plan(
|
||||
{
|
||||
"base_id": "upo_test",
|
||||
"target": {
|
||||
"kind": "form",
|
||||
"ref": "Catalog.Контрагенты",
|
||||
"form": "ФормаЭлемента",
|
||||
"element": "КнопкаЗаписать",
|
||||
},
|
||||
"edits": [{"property": "Заголовок", "value": "Записать"}],
|
||||
"resolve_origin": False,
|
||||
}
|
||||
)
|
||||
|
||||
assert result["allowed"] is False
|
||||
assert result["status"] == "needs_origin"
|
||||
assert result["route"]["name_resolution"]["status"] == "not_found"
|
||||
assert any(problem["code"] == "public_form_target_not_resolved" for problem in result["problems"])
|
||||
|
||||
|
||||
def test_metadata_write_preflight_verifies_concrete_saved_state(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
def fake_diff(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
assert payload["module_ref"] == "ConfigCASSave:object-guid__module-guid.0#stream:4"
|
||||
|
||||
Reference in New Issue
Block a user