119 lines
3.1 KiB
Python
119 lines
3.1 KiB
Python
import pytest
|
|
|
|
from backend.app.services.experiment_sync_service import ExperimentSyncService
|
|
|
|
|
|
class _FakeExperiment:
|
|
def __init__(self):
|
|
self.id = 11
|
|
self.tenant_id = 1
|
|
self.title = "exp"
|
|
self.status = "running"
|
|
self.target_metric = "acc"
|
|
self.current_score = 0.9
|
|
self.linked_context_nodes = [101]
|
|
self.project_id = 1
|
|
|
|
|
|
class _FakeTruthNode:
|
|
def __init__(self):
|
|
self.id = 101
|
|
self.tenant_id = 1
|
|
self.project_id = 1
|
|
self.content = {}
|
|
self.version = 1
|
|
|
|
|
|
class _FakeSyncRecord:
|
|
def __init__(self):
|
|
self.id = 999
|
|
self.tenant_id = 1
|
|
self.experiment_id = 11
|
|
self.truth_node_id = 101
|
|
self.sync_type = "result_sync"
|
|
self.confidence_score = 0.9
|
|
self.auto_applied = True
|
|
self.apply_status = "applied"
|
|
self.sync_data = {"previous_truth_content": {}}
|
|
self.reviewed_at = None
|
|
|
|
|
|
class _FakeResult:
|
|
def __init__(self, value):
|
|
self._value = value
|
|
|
|
def scalar_one_or_none(self):
|
|
return self._value
|
|
|
|
def all(self):
|
|
if isinstance(self._value, list):
|
|
return self._value
|
|
return []
|
|
|
|
|
|
class _FakeDB:
|
|
def __init__(self):
|
|
self.experiment = _FakeExperiment()
|
|
self.truth_node = _FakeTruthNode()
|
|
self.sync_record = _FakeSyncRecord()
|
|
self.added = []
|
|
|
|
async def execute(self, query):
|
|
sql = str(query)
|
|
if "experiment_truth_node_syncs" in sql:
|
|
return _FakeResult(self.sync_record)
|
|
if "experiments" in sql:
|
|
return _FakeResult(self.experiment)
|
|
if "SELECT truth_nodes.id," in sql:
|
|
return _FakeResult(self.truth_node)
|
|
if "SELECT truth_nodes.id" in sql:
|
|
return _FakeResult([(101,)])
|
|
if "FROM truth_nodes" in sql:
|
|
return _FakeResult(self.truth_node)
|
|
return _FakeResult(self.truth_node)
|
|
|
|
def add(self, obj):
|
|
self.added.append(obj)
|
|
if hasattr(obj, "id") and getattr(obj, "id", None) is None:
|
|
setattr(obj, "id", 1001)
|
|
|
|
async def commit(self):
|
|
return None
|
|
|
|
async def refresh(self, obj):
|
|
if hasattr(obj, "id") and getattr(obj, "id", None) is None:
|
|
setattr(obj, "id", 1001)
|
|
return None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_sync_create_and_review_and_rollback():
|
|
db = _FakeDB()
|
|
service = ExperimentSyncService(db=db) # type: ignore[arg-type]
|
|
|
|
created = await service.auto_sync_experiment_result(
|
|
experiment_id=11,
|
|
truth_node_id=101,
|
|
tenant_id=1,
|
|
project_id=1,
|
|
auto_apply_threshold=0.8,
|
|
)
|
|
assert created["auto_applied"] is True
|
|
assert created["apply_status"] == "applied"
|
|
|
|
reviewed = await service.review_sync(
|
|
sync_id=999,
|
|
tenant_id=1,
|
|
reviewer_id=1,
|
|
action="approve",
|
|
)
|
|
assert reviewed["apply_status"] in ("applied",)
|
|
|
|
rolled = await service.rollback_sync(
|
|
sync_id=999,
|
|
tenant_id=1,
|
|
reviewer_id=1,
|
|
)
|
|
assert rolled["rolled_back"] is True
|
|
assert rolled["apply_status"] == "requires_review"
|