CheddahBot/tests/test_clickup_tools.py

181 lines
6.3 KiB
Python

"""Tests for the ClickUp chat tools (API-backed, no KV store)."""
from __future__ import annotations
from dataclasses import dataclass, field
from unittest.mock import MagicMock, patch
from cheddahbot.tools.clickup_tool import (
clickup_list_tasks,
clickup_query_tasks,
clickup_reset_task,
clickup_task_status,
get_active_tasks,
)
@dataclass
class FakeTask:
id: str = "t1"
name: str = "Test Task"
status: str = "to do"
task_type: str = "Press Release"
url: str = "https://app.clickup.com/t/t1"
due_date: str = ""
date_updated: str = ""
tags: list = field(default_factory=list)
custom_fields: dict = field(default_factory=dict)
def _make_ctx():
config = MagicMock()
config.clickup.api_token = "test-token"
config.clickup.workspace_id = "ws1"
config.clickup.space_id = "sp1"
config.clickup.task_type_field_name = "Work Category"
config.clickup.automation_status = "automation underway"
config.clickup.review_status = "internal review"
config.clickup.error_status = "error"
config.clickup.poll_statuses = ["to do"]
return {"config": config, "db": MagicMock()}
class TestClickupQueryTasks:
@patch("cheddahbot.tools.clickup_tool._get_clickup_client")
def test_returns_tasks(self, mock_client_fn):
mock_client = MagicMock()
mock_client.get_tasks_from_space.return_value = [
FakeTask(id="t1", name="PR Task", task_type="Press Release"),
]
mock_client_fn.return_value = mock_client
result = clickup_query_tasks(ctx=_make_ctx())
assert "PR Task" in result
assert "t1" in result
@patch("cheddahbot.tools.clickup_tool._get_clickup_client")
def test_no_tasks_found(self, mock_client_fn):
mock_client = MagicMock()
mock_client.get_tasks_from_space.return_value = []
mock_client_fn.return_value = mock_client
result = clickup_query_tasks(ctx=_make_ctx())
assert "No tasks found" in result
class TestClickupListTasks:
@patch("cheddahbot.tools.clickup_tool._get_clickup_client")
def test_lists_automation_tasks(self, mock_client_fn):
mock_client = MagicMock()
mock_client.get_tasks_from_space.return_value = [
FakeTask(id="t1", name="Active Task", status="automation underway"),
]
mock_client_fn.return_value = mock_client
result = clickup_list_tasks(ctx=_make_ctx())
assert "Active Task" in result
assert "t1" in result
@patch("cheddahbot.tools.clickup_tool._get_clickup_client")
def test_no_automation_tasks(self, mock_client_fn):
mock_client = MagicMock()
mock_client.get_tasks_from_space.return_value = []
mock_client_fn.return_value = mock_client
result = clickup_list_tasks(ctx=_make_ctx())
assert "No tasks found" in result
@patch("cheddahbot.tools.clickup_tool._get_clickup_client")
def test_filter_by_status(self, mock_client_fn):
mock_client = MagicMock()
mock_client.get_tasks_from_space.return_value = [
FakeTask(id="t1", name="Error Task", status="error"),
]
mock_client_fn.return_value = mock_client
result = clickup_list_tasks(status="error", ctx=_make_ctx())
assert "Error Task" in result
class TestClickupTaskStatus:
@patch("cheddahbot.tools.clickup_tool._get_clickup_client")
def test_shows_details(self, mock_client_fn):
mock_client = MagicMock()
mock_client.get_task.return_value = FakeTask(
id="t1",
name="My Task",
status="automation underway",
task_type="Press Release",
)
mock_client_fn.return_value = mock_client
result = clickup_task_status(task_id="t1", ctx=_make_ctx())
assert "My Task" in result
assert "automation underway" in result
assert "Press Release" in result
@patch("cheddahbot.tools.clickup_tool._get_clickup_client")
def test_api_error(self, mock_client_fn):
mock_client = MagicMock()
mock_client.get_task.side_effect = Exception("Not found")
mock_client_fn.return_value = mock_client
result = clickup_task_status(task_id="bad", ctx=_make_ctx())
assert "Error" in result
class TestClickupResetTask:
@patch("cheddahbot.tools.clickup_tool._get_clickup_client")
def test_resets_task(self, mock_client_fn):
mock_client = MagicMock()
mock_client_fn.return_value = mock_client
result = clickup_reset_task(task_id="t1", ctx=_make_ctx())
assert "reset" in result.lower()
mock_client.update_task_status.assert_called_once_with("t1", "to do")
mock_client.add_comment.assert_called_once()
@patch("cheddahbot.tools.clickup_tool._get_clickup_client")
def test_api_error(self, mock_client_fn):
mock_client = MagicMock()
mock_client.update_task_status.side_effect = Exception("API error")
mock_client_fn.return_value = mock_client
result = clickup_reset_task(task_id="t1", ctx=_make_ctx())
assert "Error" in result
class TestGetActiveTasks:
def test_no_scheduler(self):
result = get_active_tasks(ctx={"config": MagicMock()})
assert "not available" in result.lower()
def test_nothing_running(self):
scheduler = MagicMock()
scheduler.get_active_executions.return_value = {}
scheduler.get_loop_timestamps.return_value = {"clickup": None, "folder_watch": None}
result = get_active_tasks(ctx={"scheduler": scheduler})
assert "No tasks actively executing" in result
assert "Safe to restart: Yes" in result
def test_tasks_running(self):
from datetime import UTC, datetime, timedelta
scheduler = MagicMock()
scheduler.get_active_executions.return_value = {
"t1": {
"name": "Press Release for Acme",
"tool": "write_press_releases",
"started_at": datetime.now(UTC) - timedelta(minutes=5),
"thread": "clickup_thread",
}
}
scheduler.get_loop_timestamps.return_value = {"clickup": datetime.now(UTC).isoformat()}
result = get_active_tasks(ctx={"scheduler": scheduler})
assert "Active Executions (1)" in result
assert "Press Release for Acme" in result
assert "write_press_releases" in result
assert "Safe to restart: No" in result