|
|
@@ -96,6 +96,39 @@ def test_rulespec_compiler_is_deterministic_and_never_emits_source_code():
|
|
|
_published_rule(new_governance_uid(), assertion_only_rule())
|
|
|
)
|
|
|
assert quality["backend"] == "quality_check"
|
|
|
+ assert quality["plan"]["supported_execution_backends"] == [
|
|
|
+ "mysql",
|
|
|
+ "polars",
|
|
|
+ "postgresql",
|
|
|
+ ]
|
|
|
+
|
|
|
+
|
|
|
+def test_rulespec_compiler_never_selects_polars_without_polars_capability():
|
|
|
+ import pytest
|
|
|
+
|
|
|
+ from app.core.data_rules.compiler import compile_rule_plan
|
|
|
+
|
|
|
+ spec = valid_rule_spec()
|
|
|
+ spec["steps"] = [
|
|
|
+ {
|
|
|
+ "id": "rounded_balance",
|
|
|
+ "op": "derive",
|
|
|
+ "expression": "round(balance, 2)",
|
|
|
+ }
|
|
|
+ ]
|
|
|
+
|
|
|
+ compiled = compile_rule_plan(_published_rule(new_governance_uid(), spec))
|
|
|
+
|
|
|
+ assert compiled["backend"] == "sql_pushdown"
|
|
|
+ assert compiled["plan"]["supported_execution_backends"] == [
|
|
|
+ "mysql",
|
|
|
+ "postgresql",
|
|
|
+ ]
|
|
|
+ with pytest.raises(ValueError, match="no supported"):
|
|
|
+ compile_rule_plan(
|
|
|
+ _published_rule(new_governance_uid(), spec),
|
|
|
+ supported_backends=frozenset(),
|
|
|
+ )
|
|
|
|
|
|
|
|
|
def test_release_expands_standard_and_persists_fixed_bindings_and_plans():
|
|
|
@@ -218,6 +251,80 @@ def test_release_type_checks_persisted_rule_expressions_against_server_schema(
|
|
|
created_by=new_governance_uid(),
|
|
|
)
|
|
|
|
|
|
+ assert "begin_dataflow_release" not in [
|
|
|
+ method for method, _kwargs in repository.calls
|
|
|
+ ]
|
|
|
+
|
|
|
+
|
|
|
+def test_release_selects_an_sql_target_when_rounding_cannot_run_on_polars():
|
|
|
+ from app.core.data_rules.release import ProductionLineReleaseService
|
|
|
+
|
|
|
+ rule_id = new_governance_uid()
|
|
|
+ spec = valid_rule_spec()
|
|
|
+ spec["steps"] = [
|
|
|
+ {
|
|
|
+ "id": "rounded_balance",
|
|
|
+ "op": "derive",
|
|
|
+ "expression": "round(balance, 2)",
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ repository = ReleaseRepository(
|
|
|
+ standards={}, rules={rule_id: _published_rule(rule_id, spec)}
|
|
|
+ )
|
|
|
+ flow = valid_dataflow_spec(rule_version_id=rule_id)
|
|
|
+ flow["components"] = [flow["components"][0]]
|
|
|
+
|
|
|
+ ProductionLineReleaseService(
|
|
|
+ repository, schema_resolver=FakeSchemaResolver()
|
|
|
+ ).release(
|
|
|
+ dataflow_uid=flow["dataflow_uid"],
|
|
|
+ dataflow_spec=flow,
|
|
|
+ source_text="四舍五入需要安全的 SQL 目标",
|
|
|
+ created_by=new_governance_uid(),
|
|
|
+ )
|
|
|
+
|
|
|
+ plan = next(
|
|
|
+ kwargs["plan"]
|
|
|
+ for method, kwargs in repository.calls
|
|
|
+ if method == "persist_component_plan"
|
|
|
+ )
|
|
|
+ assert plan["backend"] == "sql_pushdown"
|
|
|
+ assert plan["plan"]["supported_execution_backends"] == ["mysql", "postgresql"]
|
|
|
+
|
|
|
+
|
|
|
+def test_release_validates_every_loaded_rule_before_beginning_a_release():
|
|
|
+ from app.core.data_rules.release import ProductionLineReleaseService
|
|
|
+
|
|
|
+ direct_rule_id = new_governance_uid()
|
|
|
+ unrelated_invalid_rule_id = new_governance_uid()
|
|
|
+ invalid_spec = valid_rule_spec()
|
|
|
+ invalid_spec["steps"][1]["expression"] = "missing_schema_field == 'x'"
|
|
|
+ repository = ReleaseRepository(
|
|
|
+ standards={},
|
|
|
+ rules={
|
|
|
+ direct_rule_id: _published_rule(direct_rule_id, valid_rule_spec()),
|
|
|
+ unrelated_invalid_rule_id: _published_rule(
|
|
|
+ unrelated_invalid_rule_id, invalid_spec
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ )
|
|
|
+ flow = valid_dataflow_spec(rule_version_id=direct_rule_id)
|
|
|
+ flow["components"] = [flow["components"][0]]
|
|
|
+
|
|
|
+ with pytest.raises(ValueError, match="unknown expression field"):
|
|
|
+ ProductionLineReleaseService(
|
|
|
+ repository, schema_resolver=FakeSchemaResolver()
|
|
|
+ ).release(
|
|
|
+ dataflow_uid=flow["dataflow_uid"],
|
|
|
+ dataflow_spec=flow,
|
|
|
+ source_text="所有已加载规则必须先通过验证",
|
|
|
+ created_by=new_governance_uid(),
|
|
|
+ )
|
|
|
+
|
|
|
+ assert "begin_dataflow_release" not in [
|
|
|
+ method for method, _kwargs in repository.calls
|
|
|
+ ]
|
|
|
+
|
|
|
|
|
|
def test_release_rejects_a_persisted_unknown_expression_function_before_compile():
|
|
|
from app.core.data_rules.release import ProductionLineReleaseService
|