Files
govoplan-dataflow/tests/test_dataset_output.py
T

151 lines
5.5 KiB
Python

from __future__ import annotations
import unittest
from govoplan_core.auth import ApiPrincipal
from govoplan_core.core.access import PrincipalRef
from govoplan_core.core.dataflows import DataflowDatasetRequest, DataflowRunConflictError
from govoplan_core.db.base import Base
from govoplan_core.db.session import configure_database, reset_database
from govoplan_dataflow.backend.dataset_output import SqlDataflowDatasetOutputProvider
from govoplan_dataflow.backend.db.models import DataflowPipeline, DataflowPipelineRevision
from govoplan_dataflow.backend.schemas import PipelineGraph
from govoplan_dataflow.backend.service import definition_hash
def principal(tenant_id: str = "tenant-1") -> ApiPrincipal:
return ApiPrincipal(
principal=PrincipalRef(
account_id="account-1",
membership_id="membership-1",
tenant_id=tenant_id,
scopes=frozenset({"dataflow:pipeline:read", "dataflow:pipeline:run"}),
),
account=object(),
user=object(),
)
class DataflowDatasetOutputTests(unittest.TestCase):
def setUp(self) -> None:
self.database = configure_database("sqlite:///:memory:")
Base.metadata.create_all(
self.database.engine,
tables=[DataflowPipeline.__table__, DataflowPipelineRevision.__table__],
)
def tearDown(self) -> None:
reset_database(dispose=True)
def test_pinned_revision_executes_through_typed_registry(self) -> None:
graph = PipelineGraph.model_validate(
{
"nodes": [
{
"id": "source",
"type": "source.inline",
"label": "Source",
"position": {"x": 0, "y": 0},
"config": {
"source_name": "audience",
"rows": [
{"recipient_key": "one", "email": "one@example.test"},
{"recipient_key": "two", "email": "two@example.test"},
]
},
},
{
"id": "output",
"type": "output",
"label": "Output",
"position": {"x": 200, "y": 0},
"config": {},
},
],
"edges": [{"id": "edge-1", "source": "source", "target": "output"}],
}
)
content_hash = definition_hash(graph, None)
with self.database.session() as session:
pipeline = DataflowPipeline(
id="pipeline-1",
tenant_id="tenant-1",
scope_type="tenant",
scope_id="tenant-1",
definition_kind="flow",
name="Audience",
status="active",
current_revision=1,
allow_run=True,
metadata_={},
)
revision = DataflowPipelineRevision(
id="revision-1",
tenant_id="tenant-1",
pipeline_id=pipeline.id,
revision=1,
graph=graph.model_dump(mode="json"),
sql_text=None,
editor_mode="graph",
content_hash=content_hash,
)
session.add_all((pipeline, revision))
session.flush()
provider = SqlDataflowDatasetOutputProvider()
descriptors = provider.list_outputs(session, principal())
result = provider.read_output(
session,
principal(),
request=DataflowDatasetRequest(
pipeline_ref=pipeline.id,
revision=1,
expected_definition_hash=content_hash,
),
)
self.assertEqual(1, len(descriptors))
self.assertEqual(2, result.total_rows)
self.assertEqual("one", result.rows[0]["recipient_key"])
self.assertEqual(64, len(result.output_hash))
replay = provider.read_output(
session,
principal(),
request=DataflowDatasetRequest(
pipeline_ref=pipeline.id,
revision=1,
expected_definition_hash=content_hash,
expected_source_fingerprints=result.source_fingerprints,
),
)
self.assertEqual(result.output_hash, replay.output_hash)
with self.assertRaises(DataflowRunConflictError):
provider.read_output(
session,
principal(),
request=DataflowDatasetRequest(
pipeline_ref=pipeline.id,
revision=1,
expected_definition_hash="wrong",
),
)
with self.assertRaises(DataflowRunConflictError):
provider.read_output(
session,
principal(),
request=DataflowDatasetRequest(
pipeline_ref=pipeline.id,
revision=1,
expected_definition_hash=content_hash,
expected_source_fingerprints=(
{"node_id": "source", "fingerprint": "changed"},
),
),
)
if __name__ == "__main__":
unittest.main()