Fix test failures and workload/websocket behavior

This commit is contained in:
beabigegg
2026-01-11 08:37:21 +08:00
parent 3bdc6ff1c9
commit f5f870da56
49 changed files with 3006 additions and 1132 deletions

View File

@@ -1,7 +1,13 @@
import pytest
import uuid
from app.models import User, Space, Project, Task, TaskStatus, Trigger, TriggerLog, Notification
from datetime import datetime
from app.models import (
User, Space, Project, Task, TaskStatus, Trigger, TriggerLog, Notification,
CustomField, ProjectMember, Department, Role
)
from app.services.trigger_service import TriggerService
from app.services.custom_value_service import CustomValueService
from app.schemas.task import CustomValueInput
@pytest.fixture
@@ -188,6 +194,39 @@ class TestTriggerService:
result = TriggerService._check_conditions(conditions, old_values, new_values)
assert result is True
def test_check_conditions_composite_and(self, db, test_status):
"""Test composite AND conditions with one unchanged rule."""
conditions = {
"logic": "and",
"rules": [
{"field": "status_id", "operator": "changed_to", "value": test_status[1].id},
{"field": "priority", "operator": "equals", "value": "high"},
],
}
old_values = {"status_id": test_status[0].id, "priority": "high"}
new_values = {"status_id": test_status[1].id, "priority": "high"}
result = TriggerService._check_conditions(conditions, old_values, new_values)
assert result is True
def test_check_conditions_due_date_in_range_inclusive(self, db):
"""Test due_date in range operator is inclusive."""
conditions = {
"logic": "and",
"rules": [
{
"field": "due_date",
"operator": "in",
"value": {"start": "2024-01-01", "end": "2024-01-15"},
}
],
}
old_values = {"due_date": datetime(2024, 1, 10)}
new_values = {"due_date": datetime(2024, 1, 15)}
result = TriggerService._check_conditions(conditions, old_values, new_values)
assert result is True
def test_evaluate_triggers_creates_notification(self, db, test_task, test_trigger, test_user, test_status):
"""Test that evaluate_triggers creates notification when conditions match."""
# Create another user to receive notification
@@ -229,6 +268,247 @@ class TestTriggerService:
assert len(logs) == 0
def test_custom_field_formula_condition(self, db, test_task, test_project, test_user):
"""Test formula custom field conditions are evaluated."""
number_field = CustomField(
id=str(uuid.uuid4()),
project_id=test_project.id,
name="Points",
field_type="number",
position=0,
)
formula_field = CustomField(
id=str(uuid.uuid4()),
project_id=test_project.id,
name="Double Points",
field_type="formula",
formula="{Points} * 2",
position=1,
)
db.add_all([number_field, formula_field])
db.commit()
CustomValueService.save_custom_values(
db,
test_task,
[CustomValueInput(field_id=number_field.id, value=3)],
)
db.commit()
old_custom_values = {
cv.field_id: cv.value
for cv in CustomValueService.get_custom_values_for_task(db, test_task)
}
CustomValueService.save_custom_values(
db,
test_task,
[CustomValueInput(field_id=number_field.id, value=4)],
)
db.commit()
new_custom_values = {
cv.field_id: cv.value
for cv in CustomValueService.get_custom_values_for_task(db, test_task)
}
trigger = Trigger(
id=str(uuid.uuid4()),
project_id=test_project.id,
name="Formula Trigger",
description="Notify when formula changes to 8",
trigger_type="field_change",
conditions={
"field": "custom_fields",
"field_id": formula_field.id,
"operator": "changed_to",
"value": "8",
},
actions=[{"type": "notify", "target": f"user:{test_user.id}"}],
is_active=True,
created_by=test_user.id,
)
db.add(trigger)
db.commit()
logs = TriggerService.evaluate_triggers(
db,
test_task,
{"custom_fields": old_custom_values},
{"custom_fields": new_custom_values},
test_user,
)
db.commit()
assert len(logs) == 1
assert logs[0].status == "success"
class TestTriggerNotifications:
"""Tests for trigger notification target resolution."""
def test_notify_project_members_excludes_triggerer(self, db, test_task, test_project, test_user, test_status):
member_user = User(
id=str(uuid.uuid4()),
email="member@example.com",
name="Member User",
role_id="00000000-0000-0000-0000-000000000003",
is_active=True,
)
other_member = User(
id=str(uuid.uuid4()),
email="member2@example.com",
name="Other Member",
role_id="00000000-0000-0000-0000-000000000003",
is_active=True,
)
db.add_all([member_user, other_member])
db.commit()
db.add_all([
ProjectMember(
id=str(uuid.uuid4()),
project_id=test_project.id,
user_id=member_user.id,
role="member",
added_by=test_user.id,
),
ProjectMember(
id=str(uuid.uuid4()),
project_id=test_project.id,
user_id=other_member.id,
role="member",
added_by=test_user.id,
),
ProjectMember(
id=str(uuid.uuid4()),
project_id=test_project.id,
user_id=test_user.id,
role="member",
added_by=test_user.id,
),
])
db.commit()
trigger = Trigger(
id=str(uuid.uuid4()),
project_id=test_project.id,
name="Project Members Trigger",
description="Notify all project members",
trigger_type="field_change",
conditions={
"field": "status_id",
"operator": "changed_to",
"value": test_status[1].id,
},
actions=[{"type": "notify", "target": "project_members"}],
is_active=True,
created_by=test_user.id,
)
db.add(trigger)
db.commit()
logs = TriggerService.evaluate_triggers(
db,
test_task,
{"status_id": test_status[0].id},
{"status_id": test_status[1].id},
member_user,
)
db.commit()
assert len(logs) == 1
assert db.query(Notification).filter(Notification.user_id == member_user.id).count() == 0
assert db.query(Notification).filter(Notification.user_id == other_member.id).count() == 1
assert db.query(Notification).filter(Notification.user_id == test_user.id).count() == 1
def test_notify_department_and_role_targets(self, db, test_task, test_project, test_user, test_status):
department = Department(
id=str(uuid.uuid4()),
name="QA Department",
)
qa_role = Role(
id=str(uuid.uuid4()),
name="qa",
permissions={},
is_system_role=False,
)
db.add_all([department, qa_role])
db.commit()
triggerer = User(
id=str(uuid.uuid4()),
email="qa_lead@example.com",
name="QA Lead",
role_id=qa_role.id,
department_id=department.id,
is_active=True,
)
dept_user = User(
id=str(uuid.uuid4()),
email="dept_user@example.com",
name="Dept User",
role_id="00000000-0000-0000-0000-000000000003",
department_id=department.id,
is_active=True,
)
role_user = User(
id=str(uuid.uuid4()),
email="role_user@example.com",
name="Role User",
role_id=qa_role.id,
department_id=None,
is_active=True,
)
db.add_all([triggerer, dept_user, role_user])
db.commit()
dept_trigger = Trigger(
id=str(uuid.uuid4()),
project_id=test_project.id,
name="Department Trigger",
description="Notify department",
trigger_type="field_change",
conditions={
"field": "status_id",
"operator": "changed_to",
"value": test_status[1].id,
},
actions=[{"type": "notify", "target": f"department:{department.id}"}],
is_active=True,
created_by=test_user.id,
)
role_trigger = Trigger(
id=str(uuid.uuid4()),
project_id=test_project.id,
name="Role Trigger",
description="Notify role",
trigger_type="field_change",
conditions={
"field": "status_id",
"operator": "changed_to",
"value": test_status[1].id,
},
actions=[{"type": "notify", "target": f"role:{qa_role.name}"}],
is_active=True,
created_by=test_user.id,
)
db.add_all([dept_trigger, role_trigger])
db.commit()
TriggerService.evaluate_triggers(
db,
test_task,
{"status_id": test_status[0].id},
{"status_id": test_status[1].id},
triggerer,
)
db.commit()
assert db.query(Notification).filter(Notification.user_id == triggerer.id).count() == 0
assert db.query(Notification).filter(Notification.user_id == dept_user.id).count() == 1
assert db.query(Notification).filter(Notification.user_id == role_user.id).count() == 1
class TestTriggerAPI:
"""Tests for Trigger API endpoints."""