Fix test failures and workload/websocket behavior
This commit is contained in:
@@ -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."""
|
||||
|
||||
Reference in New Issue
Block a user