Merge branch 'issue_1199' into 'master'

Change esi client loading to on-demand

Closes #1199

See merge request allianceauth/allianceauth!1165
This commit is contained in:
Ariel Rin 2020-02-18 08:31:52 +00:00
commit 5df0d1ddc6
4 changed files with 143 additions and 21 deletions

View File

@ -1,9 +1,16 @@
from esi.clients import esi_client_factory
from bravado.exception import HTTPNotFound, HTTPUnprocessableEntity
import logging import logging
import os import os
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'swagger.json') from bravado.exception import HTTPNotFound, HTTPUnprocessableEntity, HTTPError
from jsonschema.exceptions import RefResolutionError
from django.conf import settings
from esi.clients import esi_client_factory
SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(
os.path.abspath(__file__)), 'swagger.json'
)
""" """
Swagger spec operations: Swagger spec operations:
@ -151,9 +158,34 @@ class EveProvider(object):
class EveSwaggerProvider(EveProvider): class EveSwaggerProvider(EveProvider):
def __init__(self, token=None, adapter=None): def __init__(self, token=None, adapter=None):
self.client = esi_client_factory(token=token, spec_file=SWAGGER_SPEC_PATH) if settings.DEBUG:
self._client = None
logger.info(
'DEBUG mode detected: ESI client will be loaded on-demand.'
)
else:
try:
self._client = esi_client_factory(
token=token, spec_file=SWAGGER_SPEC_PATH
)
except (HTTPError, RefResolutionError):
logger.exception(
'Failed to load ESI client on startup. '
'Switching to on-demand loading for ESI client.'
)
self._client = None
self._token = token
self.adapter = adapter or self self.adapter = adapter or self
@property
def client(self):
if self._client is None:
self._client = esi_client_factory(
token=self._token, spec_file=SWAGGER_SPEC_PATH
)
return self._client
def __str__(self): def __str__(self):
return 'esi' return 'esi'

View File

@ -0,0 +1,29 @@
import logging
import os
def set_logger(logger_name: str, name: str) -> object:
"""set logger for current test module
Args:
- logger: current logger object
- name: name of current module, e.g. __file__
Returns:
- amended logger
"""
# reconfigure logger so we get logging from tested module
f_format = logging.Formatter(
'%(asctime)s - %(levelname)s - %(module)s:%(funcName)s - %(message)s'
)
f_handler = logging.FileHandler(
'{}.log'.format(os.path.splitext(name)[0]),
'w+'
)
f_handler.setFormatter(f_format)
logger = logging.getLogger(logger_name)
logger.level = logging.DEBUG
logger.addHandler(f_handler)
logger.propagate = False
return logger

File diff suppressed because one or more lines are too long

View File

@ -1,13 +1,24 @@
import os
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
from bravado.exception import HTTPNotFound, HTTPUnprocessableEntity from bravado.exception import HTTPNotFound, HTTPUnprocessableEntity
from jsonschema.exceptions import RefResolutionError
from django.test import TestCase from django.test import TestCase
from . import set_logger
from ..models import EveCharacter, EveCorporationInfo, EveAllianceInfo from ..models import EveCharacter, EveCorporationInfo, EveAllianceInfo
from ..providers import ObjectNotFound, Entity, Character, Corporation, \ from ..providers import ObjectNotFound, Entity, Character, Corporation, \
Alliance, ItemType, EveProvider, EveSwaggerProvider Alliance, ItemType, EveProvider, EveSwaggerProvider
MODULE_PATH = 'allianceauth.eveonline.providers'
SWAGGER_OLD_SPEC_PATH = os.path.join(os.path.dirname(
os.path.abspath(__file__)), 'swagger_old.json'
)
set_logger(MODULE_PATH, __file__)
class TestObjectNotFound(TestCase): class TestObjectNotFound(TestCase):
def test_str(self): def test_str(self):
@ -65,7 +76,7 @@ class TestEntity(TestCase):
class TestCorporation(TestCase): class TestCorporation(TestCase):
@patch('allianceauth.eveonline.providers.EveSwaggerProvider.get_alliance') @patch(MODULE_PATH + '.EveSwaggerProvider.get_alliance')
def test_alliance_defined(self, mock_provider_get_alliance): def test_alliance_defined(self, mock_provider_get_alliance):
my_alliance = Alliance( my_alliance = Alliance(
id=3001, id=3001,
@ -89,7 +100,7 @@ class TestCorporation(TestCase):
self.assertEqual(mock_provider_get_alliance.call_count, 1) self.assertEqual(mock_provider_get_alliance.call_count, 1)
@patch('allianceauth.eveonline.providers.EveSwaggerProvider.get_alliance') @patch(MODULE_PATH + '.EveSwaggerProvider.get_alliance')
def test_alliance_not_defined(self, mock_provider_get_alliance): def test_alliance_not_defined(self, mock_provider_get_alliance):
mock_provider_get_alliance.return_value = None mock_provider_get_alliance.return_value = None
@ -100,7 +111,7 @@ class TestCorporation(TestCase):
) )
@patch('allianceauth.eveonline.providers.EveSwaggerProvider.get_character') @patch(MODULE_PATH + '.EveSwaggerProvider.get_character')
def test_ceo(self, mock_provider_get_character): def test_ceo(self, mock_provider_get_character):
my_ceo = Character( my_ceo = Character(
id=1001, id=1001,
@ -162,7 +173,7 @@ class TestAlliance(TestCase):
if corp_id: if corp_id:
return corps[int(corp_id)] return corps[int(corp_id)]
@patch('allianceauth.eveonline.providers.EveSwaggerProvider.get_corp') @patch(MODULE_PATH + '.EveSwaggerProvider.get_corp')
def test_corp(self, mock_provider_get_corp): def test_corp(self, mock_provider_get_corp):
mock_provider_get_corp.side_effect = TestAlliance._get_corp mock_provider_get_corp.side_effect = TestAlliance._get_corp
@ -190,7 +201,7 @@ class TestAlliance(TestCase):
self.assertEqual(mock_provider_get_corp.call_count, 2) self.assertEqual(mock_provider_get_corp.call_count, 2)
@patch('allianceauth.eveonline.providers.EveSwaggerProvider.get_corp') @patch(MODULE_PATH + '.EveSwaggerProvider.get_corp')
def test_corps(self, mock_provider_get_corp): def test_corps(self, mock_provider_get_corp):
mock_provider_get_corp.side_effect = TestAlliance._get_corp mock_provider_get_corp.side_effect = TestAlliance._get_corp
@ -203,7 +214,7 @@ class TestAlliance(TestCase):
] ]
) )
@patch('allianceauth.eveonline.providers.EveSwaggerProvider.get_corp') @patch(MODULE_PATH + '.EveSwaggerProvider.get_corp')
def test_executor_corp(self, mock_provider_get_corp): def test_executor_corp(self, mock_provider_get_corp):
mock_provider_get_corp.side_effect = TestAlliance._get_corp mock_provider_get_corp.side_effect = TestAlliance._get_corp
@ -229,7 +240,7 @@ class TestCharacter(TestCase):
alliance_id=3001 alliance_id=3001
) )
@patch('allianceauth.eveonline.providers.EveSwaggerProvider.get_corp') @patch(MODULE_PATH + '.EveSwaggerProvider.get_corp')
def test_corp(self, mock_provider_get_corp): def test_corp(self, mock_provider_get_corp):
my_corp = Corporation( my_corp = Corporation(
id=2001, id=2001,
@ -244,8 +255,8 @@ class TestCharacter(TestCase):
self.assertEqual(mock_provider_get_corp.call_count, 1) self.assertEqual(mock_provider_get_corp.call_count, 1)
@patch('allianceauth.eveonline.providers.EveSwaggerProvider.get_alliance') @patch(MODULE_PATH + '.EveSwaggerProvider.get_alliance')
@patch('allianceauth.eveonline.providers.EveSwaggerProvider.get_corp') @patch(MODULE_PATH + '.EveSwaggerProvider.get_corp')
def test_alliance_has_one( def test_alliance_has_one(
self, self,
mock_provider_get_corp, mock_provider_get_corp,
@ -312,7 +323,6 @@ class TestEveProvider(TestCase):
class TestEveSwaggerProvider(TestCase): class TestEveSwaggerProvider(TestCase):
@staticmethod @staticmethod
def esi_get_alliances_alliance_id(alliance_id): def esi_get_alliances_alliance_id(alliance_id):
alliances = { alliances = {
@ -437,13 +447,13 @@ class TestEveSwaggerProvider(TestCase):
raise HTTPNotFound(Mock()) raise HTTPNotFound(Mock())
@patch('allianceauth.eveonline.providers.esi_client_factory') @patch(MODULE_PATH + '.esi_client_factory')
def test_str(self, mock_esi_client_factory): def test_str(self, mock_esi_client_factory):
my_provider = EveSwaggerProvider() my_provider = EveSwaggerProvider()
self.assertEqual(str(my_provider), 'esi') self.assertEqual(str(my_provider), 'esi')
@patch('allianceauth.eveonline.providers.esi_client_factory') @patch(MODULE_PATH + '.esi_client_factory')
def test_get_alliance(self, mock_esi_client_factory): def test_get_alliance(self, mock_esi_client_factory):
mock_esi_client_factory.return_value\ mock_esi_client_factory.return_value\
.Alliance.get_alliances_alliance_id \ .Alliance.get_alliances_alliance_id \
@ -472,7 +482,7 @@ class TestEveSwaggerProvider(TestCase):
my_provider.get_alliance(3999) my_provider.get_alliance(3999)
@patch('allianceauth.eveonline.providers.esi_client_factory') @patch(MODULE_PATH + '.esi_client_factory')
def test_get_corp(self, mock_esi_client_factory): def test_get_corp(self, mock_esi_client_factory):
mock_esi_client_factory.return_value\ mock_esi_client_factory.return_value\
.Corporation.get_corporations_corporation_id \ .Corporation.get_corporations_corporation_id \
@ -499,7 +509,7 @@ class TestEveSwaggerProvider(TestCase):
my_provider.get_corp(2999) my_provider.get_corp(2999)
@patch('allianceauth.eveonline.providers.esi_client_factory') @patch(MODULE_PATH + '.esi_client_factory')
def test_get_character(self, mock_esi_client_factory): def test_get_character(self, mock_esi_client_factory):
mock_esi_client_factory.return_value\ mock_esi_client_factory.return_value\
.Character.get_characters_character_id \ .Character.get_characters_character_id \
@ -527,7 +537,7 @@ class TestEveSwaggerProvider(TestCase):
my_provider.get_character(1999) my_provider.get_character(1999)
@patch('allianceauth.eveonline.providers.esi_client_factory') @patch(MODULE_PATH + '.esi_client_factory')
def test_get_itemtype(self, mock_esi_client_factory): def test_get_itemtype(self, mock_esi_client_factory):
mock_esi_client_factory.return_value\ mock_esi_client_factory.return_value\
.Universe.get_universe_types_type_id \ .Universe.get_universe_types_type_id \
@ -543,3 +553,53 @@ class TestEveSwaggerProvider(TestCase):
# type not found # type not found
with self.assertRaises(ObjectNotFound): with self.assertRaises(ObjectNotFound):
my_provider.get_itemtype(4999) my_provider.get_itemtype(4999)
@patch(MODULE_PATH + '.settings.DEBUG', False)
@patch(MODULE_PATH + '.esi_client_factory')
def test_create_client_on_normal_startup(self, mock_esi_client_factory):
my_provider = EveSwaggerProvider()
self.assertTrue(mock_esi_client_factory.called)
self.assertIsNotNone(my_provider._client)
@patch(MODULE_PATH + '.SWAGGER_SPEC_PATH', SWAGGER_OLD_SPEC_PATH)
@patch(MODULE_PATH + '.settings.DEBUG', False)
@patch('socket.socket')
def test_create_client_on_normal_startup_w_old_swagger_spec(
self, mock_socket
):
mock_socket.side_effect = Exception('Network blocked for testing')
my_provider = EveSwaggerProvider()
self.assertIsNone(my_provider._client)
@patch(MODULE_PATH + '.settings.DEBUG', True)
@patch(MODULE_PATH + '.esi_client_factory')
def test_dont_create_client_on_debug_startup(self, mock_esi_client_factory):
my_provider = EveSwaggerProvider()
self.assertFalse(mock_esi_client_factory.called)
self.assertIsNone(my_provider._client)
@patch(MODULE_PATH + '.settings.DEBUG', False)
@patch(MODULE_PATH + '.esi_client_factory')
def test_dont_create_client_if_client_creation_fails_on_normal_startup(
self, mock_esi_client_factory
):
mock_esi_client_factory.side_effect = RefResolutionError(cause='Test')
my_provider = EveSwaggerProvider()
self.assertTrue(mock_esi_client_factory.called)
self.assertIsNone(my_provider._client)
@patch(MODULE_PATH + '.settings.DEBUG', True)
@patch(MODULE_PATH + '.esi_client_factory')
def test_client_loads_on_demand(
self, mock_esi_client_factory
):
mock_esi_client_factory.return_value = 'my_client'
my_provider = EveSwaggerProvider()
self.assertFalse(mock_esi_client_factory.called)
self.assertIsNone(my_provider._client)
my_client = my_provider.client
self.assertTrue(mock_esi_client_factory.called)
self.assertIsNotNone(my_provider._client)
self.assertEqual(my_client, 'my_client')