diff options
Diffstat (limited to '')
| -rw-r--r-- | tests/cogs/test_cron.py | 129 |
1 files changed, 55 insertions, 74 deletions
diff --git a/tests/cogs/test_cron.py b/tests/cogs/test_cron.py index 93031f8..28ccfe1 100644 --- a/tests/cogs/test_cron.py +++ b/tests/cogs/test_cron.py | |||
| @@ -1,10 +1,9 @@ | |||
| 1 | import json | ||
| 2 | import os | ||
| 3 | import pytest | 1 | import pytest |
| 4 | from datetime import datetime | 2 | from datetime import datetime |
| 5 | from unittest.mock import MagicMock, patch | 3 | from unittest.mock import MagicMock, patch |
| 6 | 4 | ||
| 7 | from cogs.cron import Cron | 5 | from cogs.cron import Cron |
| 6 | from cogs.utils.database import _ConnectionContextManager | ||
| 8 | 7 | ||
| 9 | 8 | ||
| 10 | @pytest.fixture | 9 | @pytest.fixture |
| @@ -17,90 +16,74 @@ def mock_bot(): | |||
| 17 | return bot | 16 | return bot |
| 18 | 17 | ||
| 19 | 18 | ||
| 20 | def create_cog(mock_bot, tmp_path): | 19 | def create_cog(mock_bot): |
| 21 | with patch.object(Cron, "__init__", lambda self, bot: None): | 20 | with patch.object(Cron, "__init__", lambda self, bot: None): |
| 22 | cog = Cron.__new__(Cron) | 21 | with patch("cogs.cron.init_database"): |
| 23 | cog.bot = mock_bot | 22 | cog = Cron.__new__(Cron) |
| 24 | cog.scheduled_tasks = [] | 23 | cog.bot = mock_bot |
| 25 | cog.cron_file = str(tmp_path / "cron_jobs.json") | 24 | cog.scheduled_tasks = [] |
| 26 | cog.task = MagicMock() | 25 | cog.task = MagicMock() |
| 27 | return cog | 26 | return cog |
| 28 | 27 | ||
| 29 | 28 | ||
| 30 | class TestLoadTasks: | 29 | class TestLoadTasks: |
| 31 | def test_load_tasks_file_not_exists(self, mock_bot, tmp_path): | 30 | def test_load_tasks_with_data(self, mock_bot): |
| 32 | cog = create_cog(mock_bot, tmp_path) | 31 | mock_conn = MagicMock() |
| 33 | cog.cron_file = str(tmp_path / "nonexistent.json") | 32 | mock_cursor = MagicMock() |
| 34 | cog.load_tasks() | 33 | mock_cursor.fetchall.return_value = [ |
| 35 | assert cog.scheduled_tasks == [] | 34 | (1, "* * * * *", "audio", 123, 1, None, "test message") |
| 36 | 35 | ] | |
| 37 | def test_load_tasks_empty_file(self, mock_bot, tmp_path): | 36 | mock_conn.cursor.return_value = mock_cursor |
| 38 | cron_file = tmp_path / "empty.json" | ||
| 39 | cron_file.write_text("") | ||
| 40 | cog = create_cog(mock_bot, tmp_path) | ||
| 41 | cog.cron_file = str(cron_file) | ||
| 42 | cog.load_tasks() | ||
| 43 | assert cog.scheduled_tasks == [] | ||
| 44 | |||
| 45 | def test_load_tasks_valid_file(self, mock_bot, tmp_path): | ||
| 46 | cron_file = tmp_path / "valid.json" | ||
| 47 | tasks = [{"id": 1, "cron_expression": "* * * * *", "type": "audio", "channel_id": 123, "active": True}] | ||
| 48 | cron_file.write_text(json.dumps(tasks)) | ||
| 49 | cog = create_cog(mock_bot, tmp_path) | ||
| 50 | cog.cron_file = str(cron_file) | ||
| 51 | cog.load_tasks() | ||
| 52 | assert len(cog.scheduled_tasks) == 1 | ||
| 53 | assert cog.scheduled_tasks[0]["id"] == 1 | ||
| 54 | 37 | ||
| 55 | def test_load_tasks_io_error(self, mock_bot, tmp_path): | 38 | # Create a context manager mock |
| 56 | cog = create_cog(mock_bot, tmp_path) | 39 | mock_ctx = MagicMock() |
| 57 | with patch("builtins.open", side_effect=IOError("test error")): | 40 | mock_ctx.__enter__ = MagicMock(return_value=mock_conn) |
| 58 | cog.load_tasks() | 41 | mock_ctx.__exit__ = MagicMock(return_value=False) |
| 59 | assert cog.scheduled_tasks == [] | ||
| 60 | 42 | ||
| 43 | with patch("cogs.cron.get_connection", return_value=mock_ctx): | ||
| 44 | cog = Cron.__new__(Cron) | ||
| 45 | cog.bot = mock_bot | ||
| 46 | cog.scheduled_tasks = [] | ||
| 47 | cog.task = MagicMock() | ||
| 48 | cog.load_tasks() | ||
| 49 | assert len(cog.scheduled_tasks) == 1 | ||
| 50 | assert cog.scheduled_tasks[0]["id"] == 1 | ||
| 61 | 51 | ||
| 62 | class TestSaveTasks: | 52 | class TestSaveTasks: |
| 63 | def test_save_tasks_with_real_file(self, mock_bot, tmp_path): | 53 | def test_save_tasks(self, mock_bot): |
| 64 | cron_file = tmp_path / "cron_jobs.json" | 54 | cog = create_cog(mock_bot) |
| 65 | cog = create_cog(mock_bot, tmp_path) | 55 | cog.scheduled_tasks = [{"id": 1, "cron_expression": "* * * * *", "type": "audio", "channel_id": 123, "active": True}] |
| 66 | cog.cron_file = str(cron_file) | ||
| 67 | cog.scheduled_tasks = [{"id": 1, "cron_expression": "* * * * *"}] | ||
| 68 | cog.save_tasks() | ||
| 69 | assert os.path.exists(cron_file) | ||
| 70 | with open(cron_file) as f: | ||
| 71 | loaded = json.load(f) | ||
| 72 | assert len(loaded) == 1 | ||
| 73 | 56 | ||
| 74 | def test_save_tasks_creates_directory_structure(self, mock_bot, tmp_path): | 57 | mock_conn = MagicMock() |
| 75 | cog = create_cog(mock_bot, tmp_path) | 58 | mock_cursor = MagicMock() |
| 76 | new_dir = tmp_path / "new_dir" | 59 | mock_conn.cursor.return_value = mock_cursor |
| 77 | cron_file = new_dir / "cron_jobs.json" | ||
| 78 | cog.cron_file = str(cron_file) | ||
| 79 | cog.scheduled_tasks = [{"id": 1}] | ||
| 80 | 60 | ||
| 81 | cog.save_tasks() | 61 | # Create a context manager mock |
| 82 | 62 | mock_ctx = MagicMock() | |
| 83 | assert os.path.exists(new_dir) | 63 | mock_ctx.__enter__ = MagicMock(return_value=mock_conn) |
| 64 | mock_ctx.__exit__ = MagicMock(return_value=False) | ||
| 84 | 65 | ||
| 66 | with patch("cogs.cron.get_connection", return_value=mock_ctx): | ||
| 67 | cog.save_tasks() | ||
| 68 | assert len(cog.scheduled_tasks) == 1 | ||
| 85 | 69 | ||
| 86 | class TestShouldRunTask: | 70 | class TestShouldRunTask: |
| 87 | def test_should_run_task_invalid_cron(self, mock_bot, tmp_path): | 71 | def test_should_run_task_invalid_cron(self, mock_bot): |
| 88 | cog = create_cog(mock_bot, tmp_path) | 72 | cog = create_cog(mock_bot) |
| 89 | task = {"cron_expression": "invalid"} | 73 | task = {"cron_expression": "invalid"} |
| 90 | now = datetime.now() | 74 | now = datetime.now() |
| 91 | result = cog.should_run_task(task, now) | 75 | result = cog.should_run_task(task, now) |
| 92 | assert result is False | 76 | assert result is False |
| 93 | 77 | ||
| 94 | def test_should_run_task_missing_cron_expression(self, mock_bot, tmp_path): | 78 | def test_should_run_task_missing_cron_expression(self, mock_bot): |
| 95 | cog = create_cog(mock_bot, tmp_path) | 79 | cog = create_cog(mock_bot) |
| 96 | task = {} | 80 | task = {} |
| 97 | now = datetime.now() | 81 | now = datetime.now() |
| 98 | result = cog.should_run_task(task, now) | 82 | result = cog.should_run_task(task, now) |
| 99 | assert result is False | 83 | assert result is False |
| 100 | 84 | ||
| 101 | |||
| 102 | class TestCogUnload: | 85 | class TestCogUnload: |
| 103 | def test_cog_unload_cancels_task(self, mock_bot, tmp_path): | 86 | def test_cog_unload_cancels_task(self, mock_bot): |
| 104 | with patch.object(Cron, "__init__", lambda self, bot: None): | 87 | with patch.object(Cron, "__init__", lambda self, bot: None): |
| 105 | cog = Cron.__new__(Cron) | 88 | cog = Cron.__new__(Cron) |
| 106 | cog.bot = mock_bot | 89 | cog.bot = mock_bot |
| @@ -109,10 +92,9 @@ class TestCogUnload: | |||
| 109 | cog.cog_unload() | 92 | cog.cog_unload() |
| 110 | cog.task.cancel.assert_called_once() | 93 | cog.task.cancel.assert_called_once() |
| 111 | 94 | ||
| 112 | |||
| 113 | class TestTaskManagement: | 95 | class TestTaskManagement: |
| 114 | def test_add_task_increments_id(self, mock_bot, tmp_path): | 96 | def test_add_task_increments_id(self, mock_bot): |
| 115 | cog = create_cog(mock_bot, tmp_path) | 97 | cog = create_cog(mock_bot) |
| 116 | cog.scheduled_tasks = [ | 98 | cog.scheduled_tasks = [ |
| 117 | {"id": 1, "cron_expression": "* * * * *"}, | 99 | {"id": 1, "cron_expression": "* * * * *"}, |
| 118 | {"id": 2, "cron_expression": "0 * * * *"}, | 100 | {"id": 2, "cron_expression": "0 * * * *"}, |
| @@ -121,8 +103,8 @@ class TestTaskManagement: | |||
| 121 | new_id = max([t["id"] for t in cog.scheduled_tasks], default=0) + 1 | 103 | new_id = max([t["id"] for t in cog.scheduled_tasks], default=0) + 1 |
| 122 | assert new_id == 3 | 104 | assert new_id == 3 |
| 123 | 105 | ||
| 124 | def test_find_task_by_id(self, mock_bot, tmp_path): | 106 | def test_find_task_by_id(self, mock_bot): |
| 125 | cog = create_cog(mock_bot, tmp_path) | 107 | cog = create_cog(mock_bot) |
| 126 | cog.scheduled_tasks = [ | 108 | cog.scheduled_tasks = [ |
| 127 | {"id": 1, "cron_expression": "* * * * *"}, | 109 | {"id": 1, "cron_expression": "* * * * *"}, |
| 128 | {"id": 2, "cron_expression": "0 * * * *"}, | 110 | {"id": 2, "cron_expression": "0 * * * *"}, |
| @@ -132,8 +114,8 @@ class TestTaskManagement: | |||
| 132 | assert found_task is not None | 114 | assert found_task is not None |
| 133 | assert found_task["cron_expression"] == "0 * * * *" | 115 | assert found_task["cron_expression"] == "0 * * * *" |
| 134 | 116 | ||
| 135 | def test_remove_task_by_index(self, mock_bot, tmp_path): | 117 | def test_remove_task_by_index(self, mock_bot): |
| 136 | cog = create_cog(mock_bot, tmp_path) | 118 | cog = create_cog(mock_bot) |
| 137 | cog.scheduled_tasks = [ | 119 | cog.scheduled_tasks = [ |
| 138 | {"id": 1, "cron_expression": "* * * * *"}, | 120 | {"id": 1, "cron_expression": "* * * * *"}, |
| 139 | {"id": 2, "cron_expression": "0 * * * *"}, | 121 | {"id": 2, "cron_expression": "0 * * * *"}, |
| @@ -143,8 +125,8 @@ class TestTaskManagement: | |||
| 143 | assert len(cog.scheduled_tasks) == 1 | 125 | assert len(cog.scheduled_tasks) == 1 |
| 144 | assert cog.scheduled_tasks[0]["id"] == 2 | 126 | assert cog.scheduled_tasks[0]["id"] == 2 |
| 145 | 127 | ||
| 146 | def test_toggle_task_active(self, mock_bot, tmp_path): | 128 | def test_toggle_task_active(self, mock_bot): |
| 147 | cog = create_cog(mock_bot, tmp_path) | 129 | cog = create_cog(mock_bot) |
| 148 | cog.scheduled_tasks = [{"id": 1, "active": True}] | 130 | cog.scheduled_tasks = [{"id": 1, "active": True}] |
| 149 | 131 | ||
| 150 | cog.scheduled_tasks[0]["active"] = False | 132 | cog.scheduled_tasks[0]["active"] = False |
| @@ -153,14 +135,13 @@ class TestTaskManagement: | |||
| 153 | cog.scheduled_tasks[0]["active"] = True | 135 | cog.scheduled_tasks[0]["active"] = True |
| 154 | assert cog.scheduled_tasks[0]["active"] is True | 136 | assert cog.scheduled_tasks[0]["active"] is True |
| 155 | 137 | ||
| 156 | |||
| 157 | class TestTaskTypes: | 138 | class TestTaskTypes: |
| 158 | def test_task_type_audio_aliases(self, mock_bot, tmp_path): | 139 | def test_task_type_audio_aliases(self, mock_bot): |
| 159 | audio_types = ("zagraj_audio", "audio") | 140 | audio_types = ("zagraj_audio", "audio") |
| 160 | for task_type in audio_types: | 141 | for task_type in audio_types: |
| 161 | assert task_type in ("zagraj_audio", "audio") | 142 | assert task_type in ("zagraj_audio", "audio") |
| 162 | 143 | ||
| 163 | def test_task_type_message_aliases(self, mock_bot, tmp_path): | 144 | def test_task_type_message_aliases(self, mock_bot): |
| 164 | message_types = ("wyślij_wiadomość", "send_message") | 145 | message_types = ("wyślij_wiadomość", "send_message") |
| 165 | for task_type in message_types: | 146 | for task_type in message_types: |
| 166 | assert task_type in ("wyślij_wiadomość", "send_message") | 147 | assert task_type in ("wyślij_wiadomość", "send_message") |
