aa-killtracker 0.16.0__py3-none-any.whl → 0.18.0a2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,4 @@
1
+ import datetime as dt
1
2
  from unittest.mock import patch
2
3
 
3
4
  import celery
@@ -6,10 +7,13 @@ import dhooks_lite
6
7
  from django.core.cache import cache
7
8
  from django.test import TestCase
8
9
  from django.test.utils import override_settings
10
+ from django.utils.timezone import now
9
11
 
12
+ from killtracker.core.discord_messages import DiscordMessage
10
13
  from killtracker.exceptions import WebhookTooManyRequests
11
14
  from killtracker.models import EveKillmail
12
15
  from killtracker.tasks import (
16
+ ZKBTooManyRequestsError,
13
17
  delete_stale_killmails,
14
18
  generate_killmail_message,
15
19
  run_killtracker,
@@ -21,6 +25,7 @@ from killtracker.tasks import (
21
25
 
22
26
  from .testdata.factories import TrackerFactory
23
27
  from .testdata.helpers import LoadTestDataMixin, load_eve_killmails, load_killmail
28
+ from .utils import reset_celery_once_locks
24
29
 
25
30
  MODULE_PATH = "killtracker.tasks"
26
31
 
@@ -48,16 +53,13 @@ class TestTrackerBase(LoadTestDataMixin, TestCase):
48
53
  )
49
54
 
50
55
 
51
- @override_settings(CELERY_ALWAYS_EAGER=True, CELERY_EAGER_PROPAGATES_EXCEPTIONS=True)
56
+ @patch(MODULE_PATH + ".worker_shutdown.is_shutting_down", spec=True)
52
57
  @patch(MODULE_PATH + ".is_esi_online", spec=True)
53
58
  @patch(MODULE_PATH + ".delete_stale_killmails", spec=True)
54
59
  @patch(MODULE_PATH + ".store_killmail", spec=True)
55
60
  @patch(MODULE_PATH + ".Killmail.create_from_zkb_redisq")
56
61
  @patch(MODULE_PATH + ".run_tracker", spec=True)
57
62
  class TestRunKilltracker(TestTrackerBase):
58
- def setUp(self) -> None:
59
- cache.clear()
60
-
61
63
  @staticmethod
62
64
  def my_fetch_from_zkb():
63
65
  for killmail_id in [10000001, 10000002, 10000003, None]:
@@ -66,6 +68,9 @@ class TestRunKilltracker(TestTrackerBase):
66
68
  else:
67
69
  yield None
68
70
 
71
+ def setUp(self):
72
+ reset_celery_once_locks()
73
+
69
74
  @patch(MODULE_PATH + ".KILLTRACKER_STORING_KILLMAILS_ENABLED", False)
70
75
  def test_should_run_normally(
71
76
  self,
@@ -74,35 +79,41 @@ class TestRunKilltracker(TestTrackerBase):
74
79
  mock_store_killmail,
75
80
  mock_delete_stale_killmails,
76
81
  mock_is_esi_online,
82
+ mock_is_shutting_down,
77
83
  ):
78
84
  # given
85
+ mock_is_shutting_down.return_value = False
79
86
  mock_create_from_zkb_redisq.side_effect = self.my_fetch_from_zkb()
80
87
  mock_is_esi_online.return_value = True
81
- self.webhook_1.error_queue.enqueue(load_killmail(10000004).asjson())
88
+ self.webhook_1._error_queue.enqueue(load_killmail(10000004).asjson())
82
89
  # when
83
- run_killtracker.delay()
90
+ got = run_killtracker()
84
91
  # then
92
+ self.assertEqual(got, 3)
85
93
  self.assertEqual(mock_run_tracker.delay.call_count, 6)
86
94
  self.assertEqual(mock_store_killmail.si.call_count, 0)
87
95
  self.assertFalse(mock_delete_stale_killmails.delay.called)
88
- self.assertEqual(self.webhook_1.main_queue.size(), 1)
89
- self.assertEqual(self.webhook_1.error_queue.size(), 0)
96
+ self.assertEqual(self.webhook_1._main_queue.size(), 1)
97
+ self.assertEqual(self.webhook_1._error_queue.size(), 0)
90
98
 
91
99
  @patch(MODULE_PATH + ".KILLTRACKER_STORING_KILLMAILS_ENABLED", False)
92
- def test_should_stop_when_esi_is_offline(
100
+ def test_should_abort_when_esi_is_offline(
93
101
  self,
94
102
  mock_run_tracker,
95
103
  mock_create_from_zkb_redisq,
96
104
  mock_store_killmail,
97
105
  mock_delete_stale_killmails,
98
106
  mock_is_esi_online,
107
+ mock_is_shutting_down,
99
108
  ):
100
109
  # given
110
+ mock_is_shutting_down.return_value = False
101
111
  mock_create_from_zkb_redisq.side_effect = self.my_fetch_from_zkb()
102
112
  mock_is_esi_online.return_value = False
103
113
  # when
104
- run_killtracker.delay()
114
+ got = run_killtracker()
105
115
  # then
116
+ self.assertEqual(got, 0)
106
117
  self.assertEqual(mock_run_tracker.delay.call_count, 0)
107
118
  self.assertEqual(mock_store_killmail.si.call_count, 0)
108
119
  self.assertFalse(mock_delete_stale_killmails.delay.called)
@@ -115,13 +126,16 @@ class TestRunKilltracker(TestTrackerBase):
115
126
  mock_store_killmail,
116
127
  mock_delete_stale_killmails,
117
128
  mock_is_esi_online,
129
+ mock_is_shutting_down,
118
130
  ):
119
131
  # given
132
+ mock_is_shutting_down.return_value = False
120
133
  mock_create_from_zkb_redisq.side_effect = self.my_fetch_from_zkb()
121
134
  mock_is_esi_online.return_value = True
122
135
  # when
123
- run_killtracker.delay()
136
+ got = run_killtracker()
124
137
  # then
138
+ self.assertEqual(got, 2)
125
139
  self.assertEqual(mock_run_tracker.delay.call_count, 4)
126
140
 
127
141
  @patch(MODULE_PATH + ".KILLTRACKER_PURGE_KILLMAILS_AFTER_DAYS", 30)
@@ -133,17 +147,63 @@ class TestRunKilltracker(TestTrackerBase):
133
147
  mock_store_killmail,
134
148
  mock_delete_stale_killmails,
135
149
  mock_is_esi_online,
150
+ mock_is_shutting_down,
136
151
  ):
137
152
  # given
153
+ mock_is_shutting_down.return_value = False
138
154
  mock_create_from_zkb_redisq.side_effect = self.my_fetch_from_zkb()
139
155
  mock_is_esi_online.return_value = True
140
156
  # when
141
- run_killtracker.delay()
157
+ run_killtracker()
142
158
  # then
143
159
  self.assertEqual(mock_run_tracker.delay.call_count, 6)
144
160
  self.assertEqual(mock_store_killmail.si.call_count, 3)
145
161
  self.assertTrue(mock_delete_stale_killmails.delay.called)
146
162
 
163
+ @patch(MODULE_PATH + ".KILLTRACKER_MAX_KILLMAILS_PER_RUN", 2)
164
+ def test_should_retry_when_too_many_errors_received(
165
+ self,
166
+ mock_run_tracker,
167
+ mock_create_from_zkb_redisq,
168
+ mock_store_killmail,
169
+ mock_delete_stale_killmails,
170
+ mock_is_esi_online,
171
+ mock_is_shutting_down,
172
+ ):
173
+ # given
174
+ mock_is_shutting_down.return_value = False
175
+ mock_create_from_zkb_redisq.side_effect = ZKBTooManyRequestsError(
176
+ now() + dt.timedelta(minutes=1)
177
+ )
178
+ mock_is_esi_online.return_value = True
179
+ # when/then
180
+ with self.assertRaises(celery.exceptions.Retry):
181
+ run_killtracker()
182
+ # then
183
+ self.assertEqual(mock_run_tracker.delay.call_count, 0)
184
+
185
+ @patch(MODULE_PATH + ".KILLTRACKER_STORING_KILLMAILS_ENABLED", False)
186
+ def test_should_abort_when_worker_is_offline(
187
+ self,
188
+ mock_run_tracker,
189
+ mock_create_from_zkb_redisq,
190
+ mock_store_killmail,
191
+ mock_delete_stale_killmails,
192
+ mock_is_esi_online,
193
+ mock_is_shutting_down,
194
+ ):
195
+ # given
196
+ mock_is_shutting_down.return_value = True
197
+ mock_create_from_zkb_redisq.side_effect = self.my_fetch_from_zkb()
198
+ mock_is_esi_online.return_value = True
199
+ # when
200
+ got = run_killtracker()
201
+ # then
202
+ self.assertEqual(got, 0)
203
+ self.assertEqual(mock_run_tracker.delay.call_count, 0)
204
+ self.assertEqual(mock_store_killmail.si.call_count, 0)
205
+ self.assertFalse(mock_delete_stale_killmails.delay.called)
206
+
147
207
 
148
208
  @patch(MODULE_PATH + ".retry_task_if_esi_is_down", lambda x: None)
149
209
  @patch(MODULE_PATH + ".send_messages_to_webhook", spec=True)
@@ -189,7 +249,7 @@ class TestRunTracker(TestTrackerBase):
189
249
  # given
190
250
  killmail = load_killmail(10000003)
191
251
  killmail.save()
192
- self.webhook_1.enqueue_message(content="test")
252
+ self.webhook_1.enqueue_message(DiscordMessage(content="test"))
193
253
  # when
194
254
  run_tracker(self.tracker_1.pk, killmail.id)
195
255
  # then
@@ -222,7 +282,7 @@ class TestGenerateKillmailMessage(TestTrackerBase):
222
282
  generate_killmail_message(self.tracker_1.pk, self.killmail_id)
223
283
  # then
224
284
  self.assertTrue(mock_send_messages_to_webhook.delay.called)
225
- self.assertEqual(self.webhook_1.main_queue.size(), 1)
285
+ self.assertEqual(self.webhook_1._main_queue.size(), 1)
226
286
  self.assertFalse(mock_retry.called)
227
287
 
228
288
  @patch(MODULE_PATH + ".KILLTRACKER_GENERATE_MESSAGE_MAX_RETRIES", 3)
@@ -238,87 +298,86 @@ class TestGenerateKillmailMessage(TestTrackerBase):
238
298
  with self.assertRaises(RuntimeError):
239
299
  generate_killmail_message(self.tracker_1.pk, self.killmail_id)
240
300
  self.assertFalse(mock_send_messages_to_webhook.delay.called)
241
- self.assertEqual(self.webhook_1.main_queue.size(), 0)
301
+ self.assertEqual(self.webhook_1._main_queue.size(), 0)
242
302
  self.assertEqual(mock_retry.call_count, 4)
243
303
 
244
304
 
245
305
  @patch("celery.app.task.Context.called_directly", False) # make retry work with eager
246
306
  @override_settings(CELERY_ALWAYS_EAGER=True)
247
- @patch(MODULE_PATH + ".Webhook.send_message_to_webhook", spec=True)
307
+ @patch(MODULE_PATH + ".Webhook.send_message", spec=True)
248
308
  class TestSendMessagesToWebhook(TestTrackerBase):
249
309
  def setUp(self) -> None:
250
310
  cache.clear()
251
311
 
252
- def test_one_message(self, mock_send_message_to_webhook):
253
- """when one message in queue, then send it and retry with delay"""
312
+ def test_should_send_one_message(self, mock_send_message):
254
313
  # given
255
- mock_send_message_to_webhook.return_value = dhooks_lite.WebhookResponse(
314
+ mock_send_message.return_value = dhooks_lite.WebhookResponse(
256
315
  {}, status_code=200
257
316
  )
258
- self.webhook_1.enqueue_message(content="Test message")
317
+ self.webhook_1.enqueue_message(DiscordMessage(content="Test message"))
259
318
  # when
260
319
  send_messages_to_webhook.delay(self.webhook_1.pk)
261
320
  # then
262
- self.assertEqual(mock_send_message_to_webhook.call_count, 1)
263
- self.assertEqual(self.webhook_1.main_queue.size(), 0)
264
- self.assertEqual(self.webhook_1.error_queue.size(), 0)
321
+ self.assertEqual(mock_send_message.call_count, 1)
322
+ self.assertEqual(self.webhook_1._main_queue.size(), 0)
323
+ self.assertEqual(self.webhook_1._error_queue.size(), 0)
265
324
 
266
- def test_three_message(self, mock_send_message_to_webhook):
325
+ def test_three_message(self, mock_send_message):
267
326
  """when three messages in queue, then sends them and returns 3"""
268
327
  # given
269
- mock_send_message_to_webhook.return_value = dhooks_lite.WebhookResponse(
328
+ mock_send_message.return_value = dhooks_lite.WebhookResponse(
270
329
  {}, status_code=200
271
330
  )
272
- self.webhook_1.enqueue_message(content="Test message")
273
- self.webhook_1.enqueue_message(content="Test message")
274
- self.webhook_1.enqueue_message(content="Test message")
331
+ self.webhook_1.enqueue_message(DiscordMessage(content="Test message"))
332
+ self.webhook_1.enqueue_message(DiscordMessage(content="Test message"))
333
+ self.webhook_1.enqueue_message(DiscordMessage(content="Test message"))
275
334
  # when
276
335
  send_messages_to_webhook.delay(self.webhook_1.pk)
277
336
  # then
278
- self.assertEqual(mock_send_message_to_webhook.call_count, 3)
279
- self.assertEqual(self.webhook_1.main_queue.size(), 0)
280
- self.assertEqual(self.webhook_1.error_queue.size(), 0)
337
+ self.assertEqual(mock_send_message.call_count, 3)
338
+ self.assertEqual(self.webhook_1._main_queue.size(), 0)
339
+ self.assertEqual(self.webhook_1._error_queue.size(), 0)
281
340
 
282
- def test_no_messages(self, mock_send_message_to_webhook):
341
+ def test_no_messages(self, mock_send_message):
283
342
  """when no messages in queue, then do nothing"""
284
343
  # given
285
- mock_send_message_to_webhook.return_value = dhooks_lite.WebhookResponse(
344
+ mock_send_message.return_value = dhooks_lite.WebhookResponse(
286
345
  {}, status_code=200
287
346
  )
288
347
  # when
289
348
  send_messages_to_webhook.delay(self.webhook_1.pk)
290
349
  # then
291
- self.assertEqual(mock_send_message_to_webhook.call_count, 0)
292
- self.assertEqual(self.webhook_1.main_queue.size(), 0)
293
- self.assertEqual(self.webhook_1.error_queue.size(), 0)
350
+ self.assertEqual(mock_send_message.call_count, 0)
351
+ self.assertEqual(self.webhook_1._main_queue.size(), 0)
352
+ self.assertEqual(self.webhook_1._error_queue.size(), 0)
294
353
 
295
- def test_failed_message(self, mock_send_message_to_webhook):
354
+ def test_failed_message(self, mock_send_message):
296
355
  """when message sending failed, then put message in error queue"""
297
356
  # given
298
- mock_send_message_to_webhook.return_value = dhooks_lite.WebhookResponse(
357
+ mock_send_message.return_value = dhooks_lite.WebhookResponse(
299
358
  {}, status_code=404
300
359
  )
301
- self.webhook_1.enqueue_message(content="Test message")
360
+ self.webhook_1.enqueue_message(DiscordMessage(content="Test message"))
302
361
  # when
303
362
  send_messages_to_webhook.delay(self.webhook_1.pk)
304
363
  # then
305
- self.assertEqual(mock_send_message_to_webhook.call_count, 1)
306
- self.assertEqual(self.webhook_1.main_queue.size(), 0)
307
- self.assertEqual(self.webhook_1.error_queue.size(), 1)
364
+ self.assertEqual(mock_send_message.call_count, 1)
365
+ self.assertEqual(self.webhook_1._main_queue.size(), 0)
366
+ self.assertEqual(self.webhook_1._error_queue.size(), 1)
308
367
 
309
- def test_abort_on_too_many_requests(self, mock_send_message_to_webhook):
368
+ def test_abort_on_too_many_requests(self, mock_send_message):
310
369
  """
311
370
  when WebhookTooManyRequests exception is raised
312
371
  then message is re-queued and retry once
313
372
  """
314
373
  # given
315
- mock_send_message_to_webhook.side_effect = WebhookTooManyRequests(10)
316
- self.webhook_1.enqueue_message(content="Test message")
374
+ mock_send_message.side_effect = WebhookTooManyRequests(10)
375
+ self.webhook_1.enqueue_message(DiscordMessage(content="Test message"))
317
376
  # when
318
377
  send_messages_to_webhook.delay(self.webhook_1.pk)
319
378
  # then
320
- self.assertEqual(mock_send_message_to_webhook.call_count, 1)
321
- self.assertEqual(self.webhook_1.main_queue.size(), 1)
379
+ self.assertEqual(mock_send_message.call_count, 1)
380
+ self.assertEqual(self.webhook_1._main_queue.size(), 1)
322
381
 
323
382
 
324
383
  @patch(MODULE_PATH + ".logger", spec=True)
@@ -352,7 +411,7 @@ class TestStoreKillmail(TestTrackerBase):
352
411
  @patch(MODULE_PATH + ".logger", spec=True)
353
412
  class TestSendTestKillmailsToWebhook(TestTrackerBase):
354
413
  def setUp(self) -> None:
355
- self.webhook_1.main_queue.clear()
414
+ self.webhook_1._main_queue.clear()
356
415
 
357
416
  def test_run_normal(self, mock_logger, mock_execute):
358
417
  # given
@@ -0,0 +1,16 @@
1
+ import logging
2
+
3
+ from app_utils.allianceauth import get_redis_client
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+
8
+ def reset_celery_once_locks():
9
+ """Reset celery once locks for given tasks."""
10
+ r = get_redis_client()
11
+ app_label = "killtracker"
12
+ if keys := r.keys(f":?:qo_{app_label}.*"):
13
+ deleted_count = r.delete(*keys)
14
+ logger.info("Removed %d stuck celery once keys", deleted_count)
15
+ else:
16
+ deleted_count = 0