aa-structures 2.9.1__py3-none-any.whl → 2.11.0__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.
- {aa_structures-2.9.1.dist-info → aa_structures-2.11.0.dist-info}/METADATA +1 -1
- {aa_structures-2.9.1.dist-info → aa_structures-2.11.0.dist-info}/RECORD +24 -20
- structures/__init__.py +1 -1
- structures/admin.py +43 -4
- structures/app_settings.py +1 -1
- structures/auth_hooks.py +6 -1
- structures/managers.py +17 -4
- structures/migrations/0006_add_ownercharacter_disabled.py +27 -0
- structures/models/owners.py +104 -51
- structures/tests/integration/test_tasks.py +2 -3
- structures/tests/integration/test_views.py +2 -2
- structures/tests/models/test_owners_1.py +95 -52
- structures/tests/models/test_owners_4.py +21 -5
- structures/tests/models/test_owners_6.py +31 -0
- structures/tests/test_admin.py +65 -0
- structures/tests/test_managers_2.py +3 -2
- structures/tests/testdata/factories.py +3 -4
- structures/tests/views/test_service_status.py +113 -0
- structures/tests/views/test_structures.py +52 -80
- structures/urls.py +3 -2
- structures/views/status.py +22 -0
- structures/views/structures.py +3 -19
- {aa_structures-2.9.1.dist-info → aa_structures-2.11.0.dist-info}/LICENSE +0 -0
- {aa_structures-2.9.1.dist-info → aa_structures-2.11.0.dist-info}/WHEEL +0 -0
@@ -318,20 +318,21 @@ class TestOwnerFetchToken(NoSocketsTestCase):
|
|
318
318
|
self.assertTrue(mock_notify.called)
|
319
319
|
self.assertEqual(owner.characters.count(), 0)
|
320
320
|
|
321
|
-
def
|
321
|
+
def test_raise_error_when_no_valid_token_found_and_disable_character(
|
322
322
|
self, mock_notify_admins, mock_notify
|
323
323
|
):
|
324
324
|
# given
|
325
|
-
|
326
|
-
user = UserMainDefaultOwnerFactory(main_character__character=
|
327
|
-
owner = OwnerFactory(user=user, characters=[
|
328
|
-
user.token_set.first().scopes.clear()
|
325
|
+
eve_character = EveCharacterFactory()
|
326
|
+
user = UserMainDefaultOwnerFactory(main_character__character=eve_character)
|
327
|
+
owner = OwnerFactory(user=user, characters=[eve_character])
|
328
|
+
user.token_set.first().scopes.clear() # token no longer valid
|
329
329
|
# when/then
|
330
330
|
with self.assertRaises(TokenError):
|
331
331
|
owner.fetch_token()
|
332
|
+
character = owner.characters.first()
|
333
|
+
self.assertFalse(character.is_enabled)
|
332
334
|
self.assertTrue(mock_notify_admins.called)
|
333
335
|
self.assertTrue(mock_notify.called)
|
334
|
-
self.assertEqual(owner.characters.count(), 0)
|
335
336
|
|
336
337
|
def test_raise_error_when_character_no_longer_a_corporation_member_and_delete_it(
|
337
338
|
self, mock_notify_admins, mock_notify
|
@@ -351,37 +352,7 @@ class TestOwnerFetchToken(NoSocketsTestCase):
|
|
351
352
|
self.assertTrue(mock_notify.called)
|
352
353
|
self.assertEqual(owner.characters.count(), 0)
|
353
354
|
|
354
|
-
def
|
355
|
-
self, mock_notify_admins, mock_notify
|
356
|
-
):
|
357
|
-
# given
|
358
|
-
character_1 = EveCharacterFactory()
|
359
|
-
user = UserMainDefaultOwnerFactory(main_character__character=character_1)
|
360
|
-
owner = OwnerFactory(
|
361
|
-
user=user,
|
362
|
-
characters=[character_1],
|
363
|
-
characters__notifications_last_used_at=dt.datetime(
|
364
|
-
2021, 1, 1, 1, 2, tzinfo=utc
|
365
|
-
),
|
366
|
-
)
|
367
|
-
character_2 = EveCharacterFactory()
|
368
|
-
OwnerCharacterFactory(
|
369
|
-
owner=owner,
|
370
|
-
eve_character=character_2,
|
371
|
-
notifications_last_used_at=dt.datetime(2021, 1, 1, 1, 1, tzinfo=utc),
|
372
|
-
)
|
373
|
-
|
374
|
-
# when
|
375
|
-
token = owner.fetch_token()
|
376
|
-
|
377
|
-
# then
|
378
|
-
self.assertIsInstance(token, Token)
|
379
|
-
self.assertEqual(token.user, user)
|
380
|
-
self.assertTrue(mock_notify_admins.called)
|
381
|
-
self.assertTrue(mock_notify.called)
|
382
|
-
self.assertEqual(owner.characters.count(), 1)
|
383
|
-
|
384
|
-
def test_should_rotate_through_characters_for_notification(
|
355
|
+
def test_should_rotate_through_enabled_characters_for_notification(
|
385
356
|
self, mock_notify_admins, mock_notify
|
386
357
|
):
|
387
358
|
# given
|
@@ -398,6 +369,9 @@ class TestOwnerFetchToken(NoSocketsTestCase):
|
|
398
369
|
owner=owner,
|
399
370
|
notifications_last_used_at=dt.datetime(2021, 1, 1, 3, 0, tzinfo=utc),
|
400
371
|
)
|
372
|
+
OwnerCharacterFactory(
|
373
|
+
owner=owner, is_enabled=False
|
374
|
+
) # this one should be ignore
|
401
375
|
tokens_received = []
|
402
376
|
|
403
377
|
# when
|
@@ -493,6 +467,36 @@ class TestOwnerFetchToken(NoSocketsTestCase):
|
|
493
467
|
],
|
494
468
|
)
|
495
469
|
|
470
|
+
def test_should_delete_invalid_characters_and_return_token_from_valid_char(
|
471
|
+
self, mock_notify_admins, mock_notify
|
472
|
+
):
|
473
|
+
# given
|
474
|
+
character_1 = EveCharacterFactory()
|
475
|
+
user = UserMainDefaultOwnerFactory(main_character__character=character_1)
|
476
|
+
owner = OwnerFactory(
|
477
|
+
user=user,
|
478
|
+
characters=[character_1],
|
479
|
+
characters__notifications_last_used_at=dt.datetime(
|
480
|
+
2021, 1, 1, 1, 2, tzinfo=utc
|
481
|
+
),
|
482
|
+
)
|
483
|
+
character_2 = EveCharacterFactory() # invalid, because of different corporation
|
484
|
+
OwnerCharacterFactory(
|
485
|
+
owner=owner,
|
486
|
+
eve_character=character_2,
|
487
|
+
notifications_last_used_at=dt.datetime(2021, 1, 1, 1, 1, tzinfo=utc),
|
488
|
+
)
|
489
|
+
|
490
|
+
# when
|
491
|
+
token = owner.fetch_token()
|
492
|
+
|
493
|
+
# then
|
494
|
+
self.assertIsInstance(token, Token)
|
495
|
+
self.assertEqual(token.user, user)
|
496
|
+
self.assertTrue(mock_notify_admins.called)
|
497
|
+
self.assertTrue(mock_notify.called)
|
498
|
+
self.assertEqual(owner.characters.count(), 1)
|
499
|
+
|
496
500
|
|
497
501
|
class TestOwnerCharacters(NoSocketsTestCase):
|
498
502
|
@classmethod
|
@@ -500,12 +504,6 @@ class TestOwnerCharacters(NoSocketsTestCase):
|
|
500
504
|
super().setUpClass()
|
501
505
|
cls.owner = OwnerFactory()
|
502
506
|
|
503
|
-
def test_should_return_str(self):
|
504
|
-
# given
|
505
|
-
character = OwnerCharacterFactory(owner=self.owner)
|
506
|
-
# when/then
|
507
|
-
self.assertTrue(str(character))
|
508
|
-
|
509
507
|
def test_should_add_new_character(self):
|
510
508
|
# given
|
511
509
|
character = EveCharacterFactory(corporation=self.owner.corporation)
|
@@ -546,22 +544,35 @@ class TestOwnerCharacters(NoSocketsTestCase):
|
|
546
544
|
with self.assertRaises(ValueError):
|
547
545
|
self.owner.add_character(character_ownership)
|
548
546
|
|
549
|
-
def
|
547
|
+
def test_should_count_enabled_characters_only(self):
|
550
548
|
# given
|
551
|
-
OwnerCharacterFactory(owner=self.owner)
|
549
|
+
OwnerCharacterFactory(owner=self.owner, is_enabled=False)
|
552
550
|
# when
|
553
|
-
result = self.owner.
|
551
|
+
result = self.owner.valid_characters_count()
|
554
552
|
# then
|
555
|
-
self.assertEqual(result,
|
553
|
+
self.assertEqual(result, 1)
|
556
554
|
|
557
555
|
def test_should_count_characters_when_empty(self):
|
558
556
|
# given
|
559
557
|
owner = OwnerFactory(characters=False)
|
560
558
|
# when
|
561
|
-
result = owner.
|
559
|
+
result = owner.valid_characters_count()
|
562
560
|
# then
|
563
561
|
self.assertEqual(result, 0)
|
564
562
|
|
563
|
+
def test_should_reset_character_when_re_adding(self):
|
564
|
+
# given
|
565
|
+
character: OwnerCharacter = self.owner.characters.first()
|
566
|
+
character.is_enabled = False
|
567
|
+
character.disabled_reason = "some reason"
|
568
|
+
character.save()
|
569
|
+
# when
|
570
|
+
self.owner.add_character(character.character_ownership)
|
571
|
+
# then
|
572
|
+
character.refresh_from_db()
|
573
|
+
self.assertTrue(character.is_enabled)
|
574
|
+
self.assertFalse(character.disabled_reason)
|
575
|
+
|
565
576
|
|
566
577
|
@patch(MODULE_PATH + ".notify", spec=True)
|
567
578
|
@patch(MODULE_PATH + ".notify_admins", spec=True)
|
@@ -577,7 +588,7 @@ class TestOwnerDeleteCharacter(NoSocketsTestCase):
|
|
577
588
|
user = character.character_ownership.user
|
578
589
|
|
579
590
|
# when
|
580
|
-
self.owner.delete_character(character=character,
|
591
|
+
self.owner.delete_character(character=character, reason="dummy error")
|
581
592
|
|
582
593
|
# then
|
583
594
|
self.assertEqual(self.owner.characters.count(), 0)
|
@@ -591,18 +602,50 @@ class TestOwnerDeleteCharacter(NoSocketsTestCase):
|
|
591
602
|
self.assertEqual(kwargs["user"], user)
|
592
603
|
self.assertEqual(kwargs["level"], "warning")
|
593
604
|
|
594
|
-
|
605
|
+
|
606
|
+
@patch(MODULE_PATH + ".notify", spec=True)
|
607
|
+
@patch(MODULE_PATH + ".notify_admins", spec=True)
|
608
|
+
class TestOwnerDisableCharacters(NoSocketsTestCase):
|
609
|
+
@classmethod
|
610
|
+
def setUpClass(cls):
|
611
|
+
super().setUpClass()
|
612
|
+
cls.owner = OwnerFactory(characters=False)
|
613
|
+
|
614
|
+
def test_should_disable_character_and_notify(self, mock_notify_admins, mock_notify):
|
615
|
+
# given
|
616
|
+
character = OwnerCharacterFactory(owner=self.owner)
|
617
|
+
user = character.character_ownership.user
|
618
|
+
|
619
|
+
# when
|
620
|
+
self.owner.disable_character(character=character, reason="dummy error")
|
621
|
+
|
622
|
+
# then
|
623
|
+
character.refresh_from_db()
|
624
|
+
self.assertFalse(character.is_enabled)
|
625
|
+
self.assertTrue(character.disabled_reason)
|
626
|
+
self.assertTrue(mock_notify_admins.called)
|
627
|
+
_, kwargs = mock_notify_admins.call_args
|
628
|
+
self.assertIn("dummy error", kwargs["message"])
|
629
|
+
self.assertEqual(kwargs["level"], "danger")
|
630
|
+
self.assertTrue(mock_notify.called)
|
631
|
+
_, kwargs = mock_notify.call_args
|
632
|
+
self.assertIn("dummy error", kwargs["message"])
|
633
|
+
self.assertEqual(kwargs["user"], user)
|
634
|
+
self.assertEqual(kwargs["level"], "warning")
|
635
|
+
|
636
|
+
def test_should_not_disable_when_error_counter_above_zero(
|
595
637
|
self, mock_notify_admins, mock_notify
|
596
638
|
):
|
597
639
|
# given
|
598
640
|
character = OwnerCharacterFactory(owner=self.owner)
|
599
641
|
|
600
642
|
# when
|
601
|
-
self.owner.
|
602
|
-
character=character,
|
643
|
+
self.owner.disable_character(
|
644
|
+
character=character, reason="dummy error", max_allowed_errors=1
|
603
645
|
)
|
604
646
|
# then
|
605
647
|
character.refresh_from_db()
|
648
|
+
self.assertTrue(character.is_enabled)
|
606
649
|
self.assertEqual(character.error_count, 1)
|
607
650
|
self.assertFalse(mock_notify_admins.called)
|
608
651
|
self.assertFalse(mock_notify.called)
|
@@ -7,7 +7,7 @@ from app_utils.esi_testing import EsiClientStub, EsiEndpoint
|
|
7
7
|
from app_utils.testing import NoSocketsTestCase
|
8
8
|
|
9
9
|
from structures.constants import EveCorporationId
|
10
|
-
from structures.models import StarbaseDetail, Structure
|
10
|
+
from structures.models import OwnerCharacter, StarbaseDetail, Structure
|
11
11
|
from structures.tests.testdata.factories import (
|
12
12
|
EveEntityCorporationFactory,
|
13
13
|
OwnerFactory,
|
@@ -353,12 +353,13 @@ class TestUpdateStarbasesEsi(NoSocketsTestCase):
|
|
353
353
|
owner.refresh_from_db()
|
354
354
|
self.assertFalse(owner.is_structure_sync_fresh)
|
355
355
|
self.assertTrue(mock_notify)
|
356
|
-
character = owner.characters.first()
|
356
|
+
character: OwnerCharacter = owner.characters.first()
|
357
357
|
self.assertEqual(character.error_count, 1)
|
358
|
+
self.assertTrue(character.is_enabled)
|
358
359
|
|
359
360
|
@patch(MODULE_PATH + ".STRUCTURES_ESI_DIRECTOR_ERROR_MAX_RETRIES", 3)
|
360
361
|
@patch(MODULE_PATH + ".notify", spec=True)
|
361
|
-
def
|
362
|
+
def test_should_disable_character_when_not_director_while_updating_starbases(
|
362
363
|
self, mock_notify, mock_esi
|
363
364
|
):
|
364
365
|
# given
|
@@ -369,7 +370,7 @@ class TestUpdateStarbasesEsi(NoSocketsTestCase):
|
|
369
370
|
)
|
370
371
|
mock_esi.client = self.esi_client_stub.replace_endpoints([new_endpoint])
|
371
372
|
owner = OwnerFactory(user=self.user, structures_last_update_at=None)
|
372
|
-
character = owner.characters.first()
|
373
|
+
character: OwnerCharacter = owner.characters.first()
|
373
374
|
character.error_count = 3
|
374
375
|
character.save()
|
375
376
|
# when
|
@@ -378,7 +379,22 @@ class TestUpdateStarbasesEsi(NoSocketsTestCase):
|
|
378
379
|
owner.refresh_from_db()
|
379
380
|
self.assertFalse(owner.is_structure_sync_fresh)
|
380
381
|
self.assertTrue(mock_notify)
|
381
|
-
|
382
|
+
character.refresh_from_db()
|
383
|
+
self.assertFalse(character.is_enabled)
|
384
|
+
|
385
|
+
def test_should_reset_error_count_for_character_when_successful(self, mock_esi):
|
386
|
+
# given
|
387
|
+
mock_esi.client = self.esi_client_stub
|
388
|
+
owner = OwnerFactory(user=self.user, structures_last_update_at=None)
|
389
|
+
character: OwnerCharacter = owner.characters.first()
|
390
|
+
character.error_count = 3
|
391
|
+
character.save()
|
392
|
+
# when
|
393
|
+
owner.update_structures_esi()
|
394
|
+
# then
|
395
|
+
character.refresh_from_db()
|
396
|
+
self.assertTrue(character.is_enabled)
|
397
|
+
self.assertEqual(character.error_count, 0)
|
382
398
|
|
383
399
|
def test_should_remove_old_starbases(self, mock_esi):
|
384
400
|
# given
|
@@ -0,0 +1,31 @@
|
|
1
|
+
from app_utils.testing import NoSocketsTestCase
|
2
|
+
|
3
|
+
from structures.tests.testdata.factories import OwnerCharacterFactory, OwnerFactory
|
4
|
+
|
5
|
+
MODULE_PATH = "structures.models.owners"
|
6
|
+
|
7
|
+
|
8
|
+
class TestOwnerCharacter(NoSocketsTestCase):
|
9
|
+
@classmethod
|
10
|
+
def setUpClass(cls):
|
11
|
+
super().setUpClass()
|
12
|
+
cls.owner = OwnerFactory()
|
13
|
+
|
14
|
+
def test_should_return_str(self):
|
15
|
+
# given
|
16
|
+
character = OwnerCharacterFactory(owner=self.owner)
|
17
|
+
# when/then
|
18
|
+
self.assertTrue(str(character))
|
19
|
+
|
20
|
+
def test_can_reset_character(self):
|
21
|
+
# given
|
22
|
+
character = OwnerCharacterFactory(
|
23
|
+
owner=self.owner, is_enabled=False, disabled_reason="reason", error_count=42
|
24
|
+
)
|
25
|
+
# when
|
26
|
+
character.reset()
|
27
|
+
# then
|
28
|
+
character.refresh_from_db()
|
29
|
+
self.assertTrue(character.is_enabled)
|
30
|
+
self.assertFalse(character.disabled_reason)
|
31
|
+
self.assertFalse(character.error_count)
|
structures/tests/test_admin.py
CHANGED
@@ -32,6 +32,7 @@ from .testdata.factories import (
|
|
32
32
|
EveCorporationInfoFactory,
|
33
33
|
FuelAlertConfigFactory,
|
34
34
|
NotificationFactory,
|
35
|
+
OwnerCharacterFactory,
|
35
36
|
OwnerFactory,
|
36
37
|
PocoFactory,
|
37
38
|
StarbaseFactory,
|
@@ -261,6 +262,7 @@ class TestNotificationAdmin(TestCase):
|
|
261
262
|
)
|
262
263
|
# when
|
263
264
|
result = self.modeladmin._structures(obj)
|
265
|
+
# then
|
264
266
|
self.assertIsNone(result)
|
265
267
|
|
266
268
|
# FIXME: Does not seam to work with special prefetch list
|
@@ -356,6 +358,52 @@ class TestNotificationAdmin(TestCase):
|
|
356
358
|
self.assertSetEqual(set(queryset), set(expected))
|
357
359
|
|
358
360
|
|
361
|
+
class TestNotificationAdminWebhooks(TestCase):
|
362
|
+
@classmethod
|
363
|
+
def setUpClass(cls):
|
364
|
+
super().setUpClass()
|
365
|
+
cls.factory = RequestFactory()
|
366
|
+
load_eveuniverse()
|
367
|
+
cls.modeladmin = NotificationAdmin(model=Notification, admin_site=AdminSite())
|
368
|
+
cls.user = SuperuserFactory()
|
369
|
+
|
370
|
+
def test_should_return_name_of_owner_webhook(self):
|
371
|
+
# given
|
372
|
+
owner = OwnerFactory(webhooks__name="Alpha")
|
373
|
+
obj = NotificationFactory(
|
374
|
+
owner=owner, notif_type=NotificationType.STRUCTURE_LOST_SHIELD
|
375
|
+
)
|
376
|
+
obj2 = self.modeladmin.get_queryset(MockRequest(user=self.user)).get(pk=obj.pk)
|
377
|
+
# when
|
378
|
+
result = self.modeladmin._webhooks(obj2)
|
379
|
+
# then
|
380
|
+
self.assertEqual("Alpha", result)
|
381
|
+
|
382
|
+
def test_should_report_missing_webhook(self):
|
383
|
+
# given
|
384
|
+
owner = OwnerFactory(webhooks=False)
|
385
|
+
obj = NotificationFactory(
|
386
|
+
owner=owner, notif_type=NotificationType.STRUCTURE_LOST_SHIELD
|
387
|
+
)
|
388
|
+
obj2 = self.modeladmin.get_queryset(MockRequest(user=self.user)).get(pk=obj.pk)
|
389
|
+
# when
|
390
|
+
result = self.modeladmin._webhooks(obj2)
|
391
|
+
# then
|
392
|
+
self.assertIn("Not configured", result)
|
393
|
+
|
394
|
+
def test_should_report_when_webhooks_not_configured_for_this_notif_type(self):
|
395
|
+
# given
|
396
|
+
owner = OwnerFactory()
|
397
|
+
obj = NotificationFactory(
|
398
|
+
owner=owner, notif_type=NotificationType.SOV_ENTOSIS_CAPTURE_STARTED
|
399
|
+
)
|
400
|
+
obj2 = self.modeladmin.get_queryset(MockRequest(user=self.user)).get(pk=obj.pk)
|
401
|
+
# when
|
402
|
+
result = self.modeladmin._webhooks(obj2)
|
403
|
+
# then
|
404
|
+
self.assertIn("Not configured", result)
|
405
|
+
|
406
|
+
|
359
407
|
class TestOwnerAdmin(TestCase):
|
360
408
|
@classmethod
|
361
409
|
def setUpClass(cls):
|
@@ -420,6 +468,23 @@ class TestOwnerAdmin(TestCase):
|
|
420
468
|
self.assertEqual(mock_task.delay.call_count, 1)
|
421
469
|
self.assertTrue(mock_message_user.called)
|
422
470
|
|
471
|
+
@patch(MODULE_PATH + ".OwnerAdmin.message_user", spec=True)
|
472
|
+
def test_action_reset_characters(self, mock_message_user):
|
473
|
+
# given
|
474
|
+
owner_1 = OwnerFactory(characters=False)
|
475
|
+
character_1 = OwnerCharacterFactory(owner=owner_1, is_enabled=False)
|
476
|
+
owner_2 = OwnerFactory(characters=False)
|
477
|
+
character_2 = OwnerCharacterFactory(owner=owner_2, is_enabled=False)
|
478
|
+
# when
|
479
|
+
queryset = Owner.objects.filter(pk=owner_1.pk)
|
480
|
+
self.modeladmin.reset_characters(MockRequest(self.user), queryset)
|
481
|
+
# then
|
482
|
+
self.assertTrue(mock_message_user.called)
|
483
|
+
character_1.refresh_from_db()
|
484
|
+
self.assertTrue(character_1.is_enabled)
|
485
|
+
character_2.refresh_from_db()
|
486
|
+
self.assertFalse(character_2.is_enabled)
|
487
|
+
|
423
488
|
def test_should_return_empty_turnaround_times(self):
|
424
489
|
# given
|
425
490
|
obj = OwnerFactory()
|
@@ -60,12 +60,13 @@ class TestOwnerManager(NoSocketsTestCase):
|
|
60
60
|
def test_should_annotate_characters_count(self):
|
61
61
|
# given
|
62
62
|
owner = OwnerFactory() # 1st character automatically created
|
63
|
-
OwnerCharacterFactory(owner=owner) # 2nd character added
|
63
|
+
OwnerCharacterFactory(owner=owner, is_enabled=False) # 2nd character added
|
64
64
|
# when
|
65
65
|
result = Owner.objects.annotate_characters_count()
|
66
66
|
# then
|
67
67
|
obj = result.get(pk=owner.pk)
|
68
|
-
self.assertEqual(obj.
|
68
|
+
self.assertEqual(obj.characters_enabled_count, 1)
|
69
|
+
self.assertEqual(obj.characters_disabled_count, 1)
|
69
70
|
|
70
71
|
def test_should_return_when_structures_where_last_updated_for_several_owners(self):
|
71
72
|
# given
|
@@ -203,9 +203,7 @@ class OwnerFactory(factory.django.DjangoModelFactory, metaclass=BaseMetaFactory[
|
|
203
203
|
def characters(
|
204
204
|
obj, create: bool, extracted: Optional[List[EveCharacter]], **kwargs
|
205
205
|
):
|
206
|
-
|
207
|
-
Set extracted to False to skip creating characters.
|
208
|
-
"""
|
206
|
+
# Set characters=False to skip creating characters.
|
209
207
|
if not create or extracted is False:
|
210
208
|
return
|
211
209
|
|
@@ -222,7 +220,8 @@ class OwnerFactory(factory.django.DjangoModelFactory, metaclass=BaseMetaFactory[
|
|
222
220
|
|
223
221
|
@factory.post_generation
|
224
222
|
def webhooks(obj, create, extracted, **kwargs):
|
225
|
-
|
223
|
+
# Set webhooks=False to skip creating characters.
|
224
|
+
if not create or extracted is False:
|
226
225
|
return
|
227
226
|
|
228
227
|
if extracted:
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import datetime as dt
|
2
|
+
from unittest.mock import patch
|
3
|
+
|
4
|
+
from django.test import TestCase
|
5
|
+
from django.urls import reverse
|
6
|
+
from django.utils.timezone import now
|
7
|
+
|
8
|
+
from app_utils.testing import response_text
|
9
|
+
|
10
|
+
from structures.tests.testdata.factories import OwnerFactory
|
11
|
+
from structures.views import status
|
12
|
+
|
13
|
+
OWNERS_PATH = "structures.models.owners"
|
14
|
+
|
15
|
+
|
16
|
+
@patch(OWNERS_PATH + ".STRUCTURES_STRUCTURE_SYNC_GRACE_MINUTES", 30)
|
17
|
+
@patch(OWNERS_PATH + ".STRUCTURES_NOTIFICATION_SYNC_GRACE_MINUTES", 30)
|
18
|
+
class TestServiceStatus(TestCase):
|
19
|
+
def test_should_report_ok(self):
|
20
|
+
# given
|
21
|
+
OwnerFactory(
|
22
|
+
structures_last_update_at=now(),
|
23
|
+
notifications_last_update_at=now(),
|
24
|
+
forwarding_last_update_at=now(),
|
25
|
+
assets_last_update_at=now(),
|
26
|
+
)
|
27
|
+
request = self.client.get(reverse("structures:service_status"))
|
28
|
+
# when
|
29
|
+
response = status.service_status(request)
|
30
|
+
# then
|
31
|
+
self.assertEqual(response.status_code, 200)
|
32
|
+
self.assertEqual(response_text(response), "service is up")
|
33
|
+
|
34
|
+
def test_should_report_ok_when_downed_owner_is_inactive(self):
|
35
|
+
# given
|
36
|
+
OwnerFactory(
|
37
|
+
structures_last_update_at=now(),
|
38
|
+
notifications_last_update_at=now(),
|
39
|
+
forwarding_last_update_at=now(),
|
40
|
+
assets_last_update_at=now(),
|
41
|
+
)
|
42
|
+
OwnerFactory(
|
43
|
+
structures_last_update_at=now() - dt.timedelta(minutes=31),
|
44
|
+
notifications_last_update_at=now(),
|
45
|
+
forwarding_last_update_at=now(),
|
46
|
+
assets_last_update_at=now(),
|
47
|
+
is_active=False,
|
48
|
+
)
|
49
|
+
request = self.client.get(reverse("structures:service_status"))
|
50
|
+
# when
|
51
|
+
response = status.service_status(request)
|
52
|
+
# then
|
53
|
+
self.assertEqual(response.status_code, 200)
|
54
|
+
|
55
|
+
def test_should_report_fail_when_issue_with_structures(self):
|
56
|
+
# given
|
57
|
+
OwnerFactory(
|
58
|
+
structures_last_update_at=now() - dt.timedelta(minutes=31),
|
59
|
+
notifications_last_update_at=now(),
|
60
|
+
forwarding_last_update_at=now(),
|
61
|
+
assets_last_update_at=now(),
|
62
|
+
)
|
63
|
+
request = self.client.get(reverse("structures:service_status"))
|
64
|
+
# when
|
65
|
+
response = status.service_status(request)
|
66
|
+
# then
|
67
|
+
self.assertEqual(response.status_code, 500)
|
68
|
+
self.assertEqual(response_text(response), "service is down")
|
69
|
+
|
70
|
+
def test_should_report_fail_when_issue_with_notifications(self):
|
71
|
+
# given
|
72
|
+
OwnerFactory(
|
73
|
+
structures_last_update_at=now(),
|
74
|
+
notifications_last_update_at=now() - dt.timedelta(minutes=31),
|
75
|
+
forwarding_last_update_at=now(),
|
76
|
+
assets_last_update_at=now(),
|
77
|
+
)
|
78
|
+
request = self.client.get(reverse("structures:service_status"))
|
79
|
+
# when
|
80
|
+
response = status.service_status(request)
|
81
|
+
# then
|
82
|
+
self.assertEqual(response.status_code, 500)
|
83
|
+
self.assertEqual(response_text(response), "service is down")
|
84
|
+
|
85
|
+
def test_should_report_fail_when_issue_with_forwarding(self):
|
86
|
+
# given
|
87
|
+
OwnerFactory(
|
88
|
+
structures_last_update_at=now(),
|
89
|
+
notifications_last_update_at=now(),
|
90
|
+
forwarding_last_update_at=now() - dt.timedelta(minutes=31),
|
91
|
+
assets_last_update_at=now(),
|
92
|
+
)
|
93
|
+
request = self.client.get(reverse("structures:service_status"))
|
94
|
+
# when
|
95
|
+
response = status.service_status(request)
|
96
|
+
# then
|
97
|
+
self.assertEqual(response.status_code, 500)
|
98
|
+
self.assertEqual(response_text(response), "service is down")
|
99
|
+
|
100
|
+
def test_should_report_fail_when_issue_with_assets(self):
|
101
|
+
# given
|
102
|
+
OwnerFactory(
|
103
|
+
structures_last_update_at=now(),
|
104
|
+
notifications_last_update_at=now(),
|
105
|
+
forwarding_last_update_at=now(),
|
106
|
+
assets_last_update_at=now() - dt.timedelta(minutes=31),
|
107
|
+
)
|
108
|
+
request = self.client.get(reverse("structures:service_status"))
|
109
|
+
# when
|
110
|
+
response = status.service_status(request)
|
111
|
+
# then
|
112
|
+
self.assertEqual(response.status_code, 500)
|
113
|
+
self.assertEqual(response_text(response), "service is down")
|