| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- from __future__ import annotations
- from dataclasses import replace
- import pytest
- from app.core.data_research.data_elements import DataElementRecord
- class FakeElementService:
- def __init__(self):
- self.record = DataElementRecord(
- uid="element-1",
- code="ORDER_ID",
- status="draft",
- current_version=1,
- snapshot={"definition": "订单唯一标识"},
- created_by="editor-1",
- updated_by="editor-1",
- )
- self.actions = []
- def create_draft(self, payload, actor_uid):
- self.actions.append(("create", payload, actor_uid))
- return self.record
- def transition(self, uid, target_status, *, expected_version, actor_uid):
- self.actions.append(("transition", uid, target_status, expected_version, actor_uid))
- return replace(
- self.record,
- uid=uid,
- status=target_status,
- current_version=expected_version + 1,
- updated_by=actor_uid,
- )
- class FakeDecisionService:
- def __init__(self):
- self.calls = []
- def decide(self, items, *, actor_uid):
- self.calls.append((items, actor_uid))
- return [
- type(
- "Decision",
- (),
- {
- "uid": "decision-1",
- "candidate_uid": "candidate-1",
- "action": "ignore",
- "data_element_uid": None,
- "evidence_uids": ("evidence-1",),
- "actor_uid": actor_uid,
- "reason": "重复字段",
- },
- )()
- ]
- @pytest.fixture()
- def client(monkeypatch):
- from flask import request
- from app import create_app
- from app.api.data_development import routes
- from app.core.system import permissions
- elements = FakeElementService()
- decisions = FakeDecisionService()
- def identity():
- token = request.headers.get("Authorization", "")
- if token == "Bearer editor":
- return {"id": "editor-1", "roles": ["editor"]}
- if token == "Bearer admin":
- return {"id": "admin-1", "roles": ["admin"]}
- return None
- monkeypatch.setattr(permissions, "authenticate_request", identity)
- monkeypatch.setattr(routes, "get_data_element_service", lambda: elements)
- monkeypatch.setattr(routes, "get_candidate_decision_service", lambda: decisions)
- app = create_app()
- app.config.update(TESTING=True)
- return app.test_client(), elements, decisions
- def test_editor_creates_draft_and_submits_review(client):
- http, elements, _decisions = client
- headers = {"Authorization": "Bearer editor"}
- created = http.post(
- "/api/development/v1/data-elements",
- headers=headers,
- json={"code": "ORDER_ID", "definition": "订单唯一标识"},
- )
- reviewed = http.post(
- "/api/development/v1/data-elements/element-1/transitions",
- headers=headers,
- json={"target_status": "in_review", "expected_version": 1},
- )
- assert created.status_code == 201
- assert created.get_json()["data"]["status"] == "draft"
- assert reviewed.status_code == 200
- assert reviewed.get_json()["data"]["status"] == "in_review"
- assert elements.actions[-1] == (
- "transition",
- "element-1",
- "in_review",
- 1,
- "editor-1",
- )
- def test_only_publisher_can_publish(client):
- http, _elements, _decisions = client
- payload = {"target_status": "published", "expected_version": 2}
- denied = http.post(
- "/api/development/v1/data-elements/element-1/transitions",
- headers={"Authorization": "Bearer editor"},
- json=payload,
- )
- allowed = http.post(
- "/api/development/v1/data-elements/element-1/transitions",
- headers={"Authorization": "Bearer admin"},
- json=payload,
- )
- assert denied.status_code == 403
- assert allowed.status_code == 200
- assert allowed.get_json()["data"]["current_version"] == 3
- def test_candidate_decisions_are_editor_gated(client):
- http, _elements, decisions = client
- response = http.post(
- "/api/development/v1/candidate-decisions",
- headers={"Authorization": "Bearer editor"},
- json={"decisions": [{"candidate_uid": "candidate-1", "action": "ignore"}]},
- )
- assert response.status_code == 200
- assert response.get_json()["data"][0]["evidence_uids"] == ["evidence-1"]
- assert decisions.calls[0][1] == "editor-1"
|