111 lines
4.5 KiB
Python
111 lines
4.5 KiB
Python
"""Тесты агрегации активностей Clockify перед переносом в Redmine."""
|
||
|
||
from datetime import datetime
|
||
from unittest import TestCase
|
||
from unittest.mock import Mock
|
||
|
||
from classes import Activity
|
||
from services.tracking import TrackingService, aggregate_activities
|
||
|
||
|
||
class TrackingServiceTestCase(TestCase):
|
||
"""Проверяет объединение и сохранение активностей Clockify."""
|
||
|
||
def create_activity(self, activity_id: str, description: str, **changes) -> Activity:
|
||
"""Создаёт активность с типовыми значениями для теста."""
|
||
values = {
|
||
"id": activity_id,
|
||
"author_id": 1,
|
||
"vetro_project_id": "vetro-project",
|
||
"task_id": 51906,
|
||
"tag_id": "tag",
|
||
"description": description,
|
||
"project_id": "project",
|
||
"time_spent": 0.5,
|
||
"date_start": datetime(2026, 7, 14, 9),
|
||
"date_end": datetime(2026, 7, 14, 9, 30),
|
||
}
|
||
values.update(changes)
|
||
return Activity(**values)
|
||
|
||
def test_fully_matching_activities_are_merged(self):
|
||
"""Полностью одинаковые активности образуют одну запись без повтора описания."""
|
||
activities = [
|
||
self.create_activity("first", "Доработки"),
|
||
self.create_activity(
|
||
"second",
|
||
"Доработки",
|
||
date_start=datetime(2026, 7, 14, 10),
|
||
date_end=datetime(2026, 7, 14, 10, 30),
|
||
),
|
||
]
|
||
|
||
result = aggregate_activities(activities)
|
||
|
||
self.assertEqual(len(result), 1)
|
||
self.assertEqual(result[0].time_spent, 1)
|
||
self.assertEqual(result[0].description, "Доработки")
|
||
self.assertEqual(result[0].source_activities, tuple(activities))
|
||
|
||
def test_descriptions_are_joined_for_otherwise_matching_activities(self):
|
||
"""Разные описания одинаковых активностей объединяются через точку."""
|
||
result = aggregate_activities(
|
||
[
|
||
self.create_activity("first", "Доработки"),
|
||
self.create_activity("second", "Влил в тест.", time_spent=0.25),
|
||
self.create_activity("third", "Доработки", time_spent=0.25),
|
||
]
|
||
)
|
||
|
||
self.assertEqual(len(result), 1)
|
||
self.assertEqual(result[0].time_spent, 1)
|
||
self.assertEqual(result[0].description, "Доработки. Влил в тест")
|
||
|
||
def test_activities_for_different_dates_are_not_merged(self):
|
||
"""Активности за разные даты остаются отдельными записями Redmine."""
|
||
result = aggregate_activities(
|
||
[
|
||
self.create_activity("first", "Доработки"),
|
||
self.create_activity(
|
||
"second",
|
||
"Доработки",
|
||
date_start=datetime(2026, 7, 15, 9),
|
||
date_end=datetime(2026, 7, 15, 9, 30),
|
||
),
|
||
]
|
||
)
|
||
|
||
self.assertEqual(len(result), 2)
|
||
|
||
def test_all_source_activities_are_marked_as_tracked(self):
|
||
"""После успешной отправки сохраняются все исходные таймеры Clockify."""
|
||
activities = [
|
||
self.create_activity("first", "Доработки"),
|
||
self.create_activity("second", "Влил в тест"),
|
||
]
|
||
aggregated_activity = aggregate_activities(activities)[0]
|
||
db = Mock()
|
||
service = TrackingService(
|
||
clock=Mock(),
|
||
red=Mock(),
|
||
db=db,
|
||
is_debug=False,
|
||
)
|
||
|
||
service._save_tracked_activity(aggregated_activity)
|
||
|
||
self.assertTrue(all(activity.is_tracked for activity in activities))
|
||
db.insert_activities.assert_called_once_with(activities)
|
||
db.insert_time_entries.assert_called_once_with(activities)
|
||
|
||
def test_activities_for_different_tasks_are_not_merged(self):
|
||
"""Активности разных задач остаются отдельными записями Redmine."""
|
||
result = aggregate_activities(
|
||
[
|
||
self.create_activity("first", "Доработки"),
|
||
self.create_activity("second", "Доработки", task_id=60130),
|
||
]
|
||
)
|
||
|
||
self.assertEqual(len(result), 2)
|