Initial SQL-only 1C adapter baseline
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
CONNECTOR = ROOT / "plugins" / "1c" / "connector"
|
||||
|
||||
|
||||
def load_adapter():
|
||||
path = CONNECTOR / "adapter_1c_server.py"
|
||||
spec = importlib.util.spec_from_file_location("adapter_1c_policy_test", path)
|
||||
assert spec and spec.loader
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def test_sql_base_access_policy_contract() -> None:
|
||||
policy = yaml.safe_load((CONNECTOR / "policies" / "sql-base-access-policy.yaml").read_text(encoding="utf-8"))
|
||||
assert policy["status"] == "active"
|
||||
assert policy["base_settings"]["selector"] == "base_id"
|
||||
assert set(policy["base_settings"]["required_fields"]) == {"server", "database", "user"}
|
||||
assert policy["read_scope"]["application_data"] == "read_only"
|
||||
assert policy["read_scope"]["metadata_structure"] == "read_only"
|
||||
assert set(policy["write_scope"]["allowed"].values()) == {"ConfigSave", "ConfigCASSave"}
|
||||
assert policy["sql_identity_management"]["mode"] == "forbidden"
|
||||
|
||||
|
||||
def test_xml_is_offline_decoder_evidence_and_runtime_is_sql_only() -> None:
|
||||
policy = yaml.safe_load((CONNECTOR / "policies" / "xml-decoding-reference-policy.yaml").read_text(encoding="utf-8"))
|
||||
service = yaml.safe_load((CONNECTOR / "service.yaml").read_text(encoding="utf-8"))
|
||||
|
||||
assert policy["status"] == "active"
|
||||
assert policy["offline_analysis"]["allowed"] is True
|
||||
assert policy["runtime"]["source"] == "sql_only"
|
||||
assert policy["runtime"]["xml_mount_required"] is False
|
||||
assert "policies/xml-decoding-reference-policy.yaml" in service["contracts"]["policies"]
|
||||
|
||||
|
||||
def test_designer_sql_decoding_policy_keeps_adapter_read_only() -> None:
|
||||
policy = yaml.safe_load((CONNECTOR / "policies" / "designer-sql-decoding-policy.yaml").read_text(encoding="utf-8"))
|
||||
service = yaml.safe_load((CONNECTOR / "service.yaml").read_text(encoding="utf-8"))
|
||||
|
||||
assert policy["scope"]["default_base_id"] == "upo_test"
|
||||
assert policy["scope"]["adapter_role"] == "sql_observer_and_decoder"
|
||||
assert policy["credentials"]["persistence"] == "forbidden_in_repository"
|
||||
assert policy["sql_observation"]["adapter_access"] == "read_only"
|
||||
assert "direct_application_data_write" in policy["sql_observation"]["forbidden"]
|
||||
assert policy["xml"]["role"] == "offline_schema_reference_only"
|
||||
assert "policies/designer-sql-decoding-policy.yaml" in service["contracts"]["policies"]
|
||||
|
||||
|
||||
def test_runtime_rejects_xml_sources_at_any_payload_depth() -> None:
|
||||
adapter = load_adapter()
|
||||
|
||||
direct = adapter.call_method_impl(
|
||||
"metadata.object.get",
|
||||
{"base_id": "upo_test", "ref": "Catalog.Test", "xml_path": "Configuration.xml"},
|
||||
)
|
||||
nested = adapter.call_method_impl(
|
||||
"metadata.write.plan",
|
||||
{"base_id": "upo_test", "target": {"form_xml_path": "Forms/Test/Ext/Form.xml"}},
|
||||
)
|
||||
|
||||
assert direct["status"] == "invalid_argument"
|
||||
assert direct["argument"] == "payload.xml_path"
|
||||
assert nested["status"] == "invalid_argument"
|
||||
assert nested["argument"] == "payload.target.form_xml_path"
|
||||
assert "SQL-only" in direct["diagnostics"]["message"]
|
||||
|
||||
|
||||
def test_adapter_has_no_xml_runtime_environment_configuration() -> None:
|
||||
source = (CONNECTOR / "adapter_1c_server.py").read_text(encoding="utf-8")
|
||||
assert "ONEC_XML" not in source
|
||||
|
||||
|
||||
def test_sql_connection_requires_explicit_base_entry(monkeypatch) -> None:
|
||||
adapter = load_adapter()
|
||||
for name in (
|
||||
"ONEC_SQL_BASES_JSON",
|
||||
"ONEC_SQL_CONNECTIONS_JSON",
|
||||
"ONEC_SQL_BASES_JSON_FILE",
|
||||
"ONEC_SQL_CONNECTIONS_JSON_FILE",
|
||||
):
|
||||
monkeypatch.delenv(name, raising=False)
|
||||
monkeypatch.setenv("ONEC_SQL_SERVER", "must-not-be-used")
|
||||
monkeypatch.setenv("ONEC_SQL_USER", "must-not-be-used")
|
||||
monkeypatch.setenv("ONEC_SQL_PASSWORD", "must-not-be-used")
|
||||
|
||||
config, error = adapter.sql_config_for_base("upo_test")
|
||||
|
||||
assert config is None
|
||||
assert error and error["status"] == "not_configured"
|
||||
|
||||
|
||||
def test_sql_connection_does_not_infer_database_name(monkeypatch) -> None:
|
||||
adapter = load_adapter()
|
||||
monkeypatch.setenv(
|
||||
"ONEC_SQL_BASES_JSON",
|
||||
'{"upo_test":{"server":"sql-host","user":"login","password":"secret"}}',
|
||||
)
|
||||
|
||||
config, error = adapter.sql_config_for_base("upo_test")
|
||||
|
||||
assert config is None
|
||||
assert error and "database" in error["message"]
|
||||
|
||||
|
||||
def test_sql_connection_ignores_legacy_connection_map(monkeypatch) -> None:
|
||||
adapter = load_adapter()
|
||||
monkeypatch.delenv("ONEC_SQL_BASES_JSON", raising=False)
|
||||
monkeypatch.delenv("ONEC_SQL_BASES_JSON_FILE", raising=False)
|
||||
monkeypatch.setenv(
|
||||
"ONEC_SQL_CONNECTIONS_JSON",
|
||||
'{"upo_test":{"server":"must-not-be-used","database":"must-not-be-used","user":"must-not-be-used","password":"must-not-be-used"}}',
|
||||
)
|
||||
|
||||
config, error = adapter.sql_config_for_base("upo_test")
|
||||
|
||||
assert config is None
|
||||
assert error and error["status"] == "not_configured"
|
||||
assert adapter.sql_configured_base_ids() == []
|
||||
Reference in New Issue
Block a user