django-esi 8.1.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.
Files changed (100) hide show
  1. django_esi-8.1.0.dist-info/METADATA +93 -0
  2. django_esi-8.1.0.dist-info/RECORD +100 -0
  3. django_esi-8.1.0.dist-info/WHEEL +4 -0
  4. django_esi-8.1.0.dist-info/licenses/LICENSE +674 -0
  5. esi/__init__.py +7 -0
  6. esi/admin.py +42 -0
  7. esi/aiopenapi3/client.py +79 -0
  8. esi/aiopenapi3/plugins.py +224 -0
  9. esi/app_settings.py +112 -0
  10. esi/apps.py +11 -0
  11. esi/checks.py +56 -0
  12. esi/clients.py +657 -0
  13. esi/decorators.py +271 -0
  14. esi/errors.py +22 -0
  15. esi/exceptions.py +51 -0
  16. esi/helpers.py +63 -0
  17. esi/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  18. esi/locale/cs_CZ/LC_MESSAGES/django.po +53 -0
  19. esi/locale/de/LC_MESSAGES/django.mo +0 -0
  20. esi/locale/de/LC_MESSAGES/django.po +58 -0
  21. esi/locale/en/LC_MESSAGES/django.mo +0 -0
  22. esi/locale/en/LC_MESSAGES/django.po +54 -0
  23. esi/locale/es/LC_MESSAGES/django.mo +0 -0
  24. esi/locale/es/LC_MESSAGES/django.po +59 -0
  25. esi/locale/fr_FR/LC_MESSAGES/django.mo +0 -0
  26. esi/locale/fr_FR/LC_MESSAGES/django.po +59 -0
  27. esi/locale/it_IT/LC_MESSAGES/django.mo +0 -0
  28. esi/locale/it_IT/LC_MESSAGES/django.po +59 -0
  29. esi/locale/ja/LC_MESSAGES/django.mo +0 -0
  30. esi/locale/ja/LC_MESSAGES/django.po +58 -0
  31. esi/locale/ko_KR/LC_MESSAGES/django.mo +0 -0
  32. esi/locale/ko_KR/LC_MESSAGES/django.po +58 -0
  33. esi/locale/nl_NL/LC_MESSAGES/django.mo +0 -0
  34. esi/locale/nl_NL/LC_MESSAGES/django.po +53 -0
  35. esi/locale/pl_PL/LC_MESSAGES/django.mo +0 -0
  36. esi/locale/pl_PL/LC_MESSAGES/django.po +53 -0
  37. esi/locale/ru/LC_MESSAGES/django.mo +0 -0
  38. esi/locale/ru/LC_MESSAGES/django.po +61 -0
  39. esi/locale/sk/LC_MESSAGES/django.mo +0 -0
  40. esi/locale/sk/LC_MESSAGES/django.po +55 -0
  41. esi/locale/uk/LC_MESSAGES/django.mo +0 -0
  42. esi/locale/uk/LC_MESSAGES/django.po +57 -0
  43. esi/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  44. esi/locale/zh_Hans/LC_MESSAGES/django.po +58 -0
  45. esi/management/commands/__init__.py +0 -0
  46. esi/management/commands/esi_clear_spec_cache.py +21 -0
  47. esi/management/commands/generate_esi_stubs.py +661 -0
  48. esi/management/commands/migrate_to_ssov2.py +188 -0
  49. esi/managers.py +303 -0
  50. esi/managers.pyi +85 -0
  51. esi/migrations/0001_initial.py +55 -0
  52. esi/migrations/0002_scopes_20161208.py +56 -0
  53. esi/migrations/0003_hide_tokens_from_admin_site.py +23 -0
  54. esi/migrations/0004_remove_unique_access_token.py +18 -0
  55. esi/migrations/0005_remove_token_length_limit.py +23 -0
  56. esi/migrations/0006_remove_url_length_limit.py +18 -0
  57. esi/migrations/0007_fix_mysql_8_migration.py +18 -0
  58. esi/migrations/0008_nullable_refresh_token.py +18 -0
  59. esi/migrations/0009_set_old_tokens_to_sso_v1.py +18 -0
  60. esi/migrations/0010_set_new_tokens_to_sso_v2.py +18 -0
  61. esi/migrations/0011_add_token_indices.py +28 -0
  62. esi/migrations/0012_fix_token_type_choices.py +18 -0
  63. esi/migrations/0013_squashed_0012_fix_token_type_choices.py +57 -0
  64. esi/migrations/__init__.py +0 -0
  65. esi/models.py +349 -0
  66. esi/openapi_clients.py +1225 -0
  67. esi/rate_limiting.py +107 -0
  68. esi/signals.py +21 -0
  69. esi/static/esi/img/EVE_SSO_Login_Buttons_Large_Black.png +0 -0
  70. esi/static/esi/img/EVE_SSO_Login_Buttons_Large_White.png +0 -0
  71. esi/static/esi/img/EVE_SSO_Login_Buttons_Small_Black.png +0 -0
  72. esi/static/esi/img/EVE_SSO_Login_Buttons_Small_White.png +0 -0
  73. esi/stubs.py +2 -0
  74. esi/stubs.pyi +6807 -0
  75. esi/tasks.py +78 -0
  76. esi/templates/esi/select_token.html +116 -0
  77. esi/templatetags/__init__.py +0 -0
  78. esi/templatetags/scope_tags.py +8 -0
  79. esi/tests/__init__.py +134 -0
  80. esi/tests/client_authed_pilot.py +63 -0
  81. esi/tests/client_public_pilot.py +53 -0
  82. esi/tests/factories.py +47 -0
  83. esi/tests/factories_2.py +60 -0
  84. esi/tests/jwt_factory.py +135 -0
  85. esi/tests/test_checks.py +48 -0
  86. esi/tests/test_clients.py +1019 -0
  87. esi/tests/test_decorators.py +578 -0
  88. esi/tests/test_management_command.py +307 -0
  89. esi/tests/test_managers.py +673 -0
  90. esi/tests/test_models.py +403 -0
  91. esi/tests/test_openapi.json +854 -0
  92. esi/tests/test_openapi.py +1017 -0
  93. esi/tests/test_swagger.json +489 -0
  94. esi/tests/test_swagger_full.json +51112 -0
  95. esi/tests/test_tasks.py +116 -0
  96. esi/tests/test_templatetags.py +22 -0
  97. esi/tests/test_views.py +331 -0
  98. esi/tests/threading_pilot.py +69 -0
  99. esi/urls.py +9 -0
  100. esi/views.py +129 -0
@@ -0,0 +1,1019 @@
1
+ import datetime
2
+ import os
3
+ from unittest.mock import patch, Mock
4
+ import json
5
+
6
+ import bravado
7
+ from bravado_core.spec import Spec
8
+ from bravado.requests_client import RequestsClient
9
+ from bravado.exception import HTTPBadGateway
10
+ import requests_mock
11
+
12
+ import django
13
+ from django.contrib.auth.models import User
14
+ from django.core.cache import cache
15
+
16
+ from . import _generate_token, _store_as_Token, NoSocketsTestCase
17
+ from .factories import create_http_error
18
+ from ..clients import (
19
+ EsiClientProvider,
20
+ esi_client_factory,
21
+ TokenAuthenticator,
22
+ build_cache_name,
23
+ build_spec,
24
+ build_spec_url,
25
+ cache_spec,
26
+ get_spec,
27
+ read_spec,
28
+ minimize_spec,
29
+ SwaggerClient,
30
+ CachingHttpFuture,
31
+ RequestsClientPlus,
32
+ )
33
+ from ..errors import TokenExpiredError
34
+
35
+ SWAGGER_SPEC_PATH_MINIMAL = os.path.join(
36
+ os.path.dirname(os.path.abspath(__file__)), "test_swagger.json"
37
+ )
38
+ SWAGGER_SPEC_PATH_FULL = os.path.join(
39
+ os.path.dirname(os.path.abspath(__file__)), "test_swagger_full.json"
40
+ )
41
+
42
+ MODULE_PATH = "esi.clients"
43
+
44
+
45
+ def _load_json_file(path):
46
+ with open(path, encoding="utf-8") as f:
47
+ return json.load(f)
48
+
49
+
50
+ class MockResultFuture:
51
+ def __init__(self):
52
+ dt = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=60)
53
+ self.headers = {"Expires": dt.strftime("%a, %d %b %Y %H:%M:%S %Z")}
54
+ self.status_code = 200
55
+ self.text = "dummy"
56
+
57
+
58
+ class MockResultPast:
59
+ def __init__(self):
60
+ dt = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(seconds=60)
61
+ self.headers = {"Expires": dt.strftime("%a, %d %b %Y %H:%M:%S %Z")}
62
+
63
+
64
+ @patch.object(django.core.cache.cache, "set")
65
+ @patch.object(django.core.cache.cache, "get")
66
+ @patch.object(bravado.http_future.HttpFuture, "result")
67
+ class TestClientCache(NoSocketsTestCase):
68
+ @classmethod
69
+ def setUpTestData(cls):
70
+ spec = _load_json_file(SWAGGER_SPEC_PATH_MINIMAL)
71
+ with requests_mock.Mocker() as requests_mocker:
72
+ requests_mocker.register_uri(
73
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=spec
74
+ )
75
+ cls.c = esi_client_factory(spec_file=SWAGGER_SPEC_PATH_MINIMAL)
76
+
77
+ def setUp(self) -> None:
78
+ cache.clear()
79
+
80
+ def test_cache_expire(self, mock_future_result, mock_cache_get, mock_cache_set):
81
+ mock_future_result.return_value = ({"players": 500}, MockResultFuture())
82
+ mock_cache_get.return_value = False
83
+
84
+ # hit api
85
+ r = self.c.Status.get_status().result()
86
+ self.assertEqual(r["players"], 500)
87
+
88
+ mock_cache_get.return_value = ({"players": 50}, MockResultFuture())
89
+ # hit cache and pass
90
+ r = self.c.Status.get_status().result()
91
+ self.assertEqual(r["players"], 50)
92
+
93
+ mock_cache_get.return_value = ({"players": 50}, MockResultPast())
94
+ # hit cache fail, re-hit api
95
+ r = self.c.Status.get_status().result()
96
+ self.assertEqual(r["players"], 500)
97
+
98
+ def test_should_use_cache(self, mock_future_result, mock_cache_get, mock_cache_set):
99
+ # given
100
+ mock_future_result.return_value = ({"players": 500}, MockResultFuture())
101
+ mock_cache_get.return_value = False
102
+
103
+ # when
104
+ r = self.c.Status.get_status().result()
105
+ # then
106
+ self.assertEqual(r["players"], 500)
107
+ self.assertTrue(mock_cache_get.called)
108
+ self.assertTrue(mock_cache_set.called)
109
+
110
+ def test_should_not_use_cache(
111
+ self, mock_future_result, mock_cache_get, mock_cache_set
112
+ ):
113
+ # given
114
+ mock_future_result.return_value = ({"players": 500}, MockResultFuture())
115
+ mock_cache_get.return_value = False
116
+
117
+ # when
118
+ r = self.c.Status.get_status().result(ignore_cache=True)
119
+ # then
120
+ self.assertEqual(r["players"], 500)
121
+ self.assertFalse(mock_cache_get.called)
122
+ self.assertFalse(mock_cache_set.called)
123
+
124
+ def test_can_handle_exception_from_cache_set(
125
+ self, mock_future_result, mock_cache_get, mock_cache_set
126
+ ):
127
+ mock_future_result.return_value = ({"players": 500}, MockResultFuture())
128
+ mock_cache_get.return_value = False
129
+ mock_cache_set.side_effect = RuntimeError("TEST: Could not write to cache")
130
+
131
+ # hit api
132
+ r = self.c.Status.get_status().result()
133
+ self.assertEqual(r["players"], 500)
134
+
135
+ def test_can_handle_exception_from_cache_get(
136
+ self, mock_future_result, mock_cache_get, mock_cache_set
137
+ ):
138
+ mock_future_result.return_value = ({"players": 500}, MockResultFuture())
139
+ mock_cache_get.side_effect = RuntimeError("TEST: Could not read from cache")
140
+
141
+ # hit api
142
+ r = self.c.Status.get_status().result()
143
+ self.assertEqual(r["players"], 500)
144
+
145
+
146
+ @patch(MODULE_PATH + ".app_settings.ESI_SPEC_CACHE_DURATION", 3)
147
+ @patch(MODULE_PATH + ".app_settings.ESI_API_URL", "https://www.example.com/esi/")
148
+ @patch(MODULE_PATH + ".app_settings.ESI_API_DATASOURCE", "dummy")
149
+ @patch("esi.models.app_settings.ESI_TOKEN_VALID_DURATION", 120)
150
+ class TestTokenAuthenticator(NoSocketsTestCase):
151
+ def setUp(self):
152
+ self.user = User.objects.create_user(
153
+ "Bruce Wayne", "abc@example.com", "password"
154
+ )
155
+ self.token = _store_as_Token(
156
+ _generate_token(
157
+ character_id=101,
158
+ character_name=self.user.username,
159
+ scopes=["abc"],
160
+ access_token="my_access_token",
161
+ ),
162
+ self.user,
163
+ )
164
+
165
+ def test_apply_defaults(self):
166
+ request = Mock()
167
+ request.headers = dict()
168
+ request.params = dict()
169
+
170
+ x = TokenAuthenticator()
171
+ request2 = x.apply(request)
172
+ self.assertEqual(request2.headers["Authorization"], None)
173
+ self.assertEqual(request2.params["datasource"], "dummy")
174
+
175
+ def test_apply_token(self):
176
+ request = Mock()
177
+ request.headers = dict()
178
+ request.params = dict()
179
+
180
+ x = TokenAuthenticator(token=self.token)
181
+ request2 = x.apply(request)
182
+ self.assertEqual(request2.headers["Authorization"], "Bearer my_access_token")
183
+ self.assertEqual(request2.params["datasource"], "dummy")
184
+
185
+ def test_apply_token_datasource(self):
186
+ request = Mock()
187
+ request.headers = dict()
188
+ request.params = dict()
189
+
190
+ x = TokenAuthenticator(token=self.token, datasource="dummy2")
191
+ request2 = x.apply(request)
192
+ self.assertEqual(request2.headers["Authorization"], "Bearer my_access_token")
193
+ self.assertEqual(request2.params["datasource"], "dummy2")
194
+
195
+ @patch("esi.models.Token.refresh", spec=True)
196
+ def test_apply_token_expired_success(self, mock_Token_refresh):
197
+ request = Mock()
198
+ request.headers = dict()
199
+ request.params = dict()
200
+
201
+ self.token.created -= datetime.timedelta(121)
202
+
203
+ x = TokenAuthenticator(token=self.token)
204
+ request2 = x.apply(request)
205
+ self.assertEqual(request2.headers["Authorization"], "Bearer my_access_token")
206
+ self.assertEqual(request2.params["datasource"], "dummy")
207
+ self.assertEqual(mock_Token_refresh.call_count, 1)
208
+
209
+ @patch("esi.models.Token.refresh", spec=True)
210
+ def test_apply_token_expired_failed(self, mock_Token_refresh):
211
+ request = Mock()
212
+ request.headers = dict()
213
+ request.params = dict()
214
+
215
+ self.token.created -= datetime.timedelta(121)
216
+ self.token.refresh_token = None
217
+
218
+ x = TokenAuthenticator(token=self.token)
219
+ with self.assertRaises(TokenExpiredError):
220
+ x.apply(request)
221
+
222
+ self.assertEqual(mock_Token_refresh.call_count, 0)
223
+
224
+
225
+ class TestModuleFunctions(NoSocketsTestCase):
226
+ @classmethod
227
+ def setUpClass(cls):
228
+ super().setUpClass()
229
+ cls.spec = _load_json_file(SWAGGER_SPEC_PATH_MINIMAL)
230
+
231
+ def test_build_cache_name(self):
232
+ self.assertEqual(build_cache_name("abc"), "esi_swaggerspec_abc")
233
+
234
+ @patch(MODULE_PATH + ".app_settings.ESI_SPEC_CACHE_DURATION", 3)
235
+ def test_cache_spec(self):
236
+ spec = {"dummy_spec": True}
237
+ cache_spec("abc", spec)
238
+ self.assertDictEqual(cache.get("esi_swaggerspec_abc"), spec)
239
+
240
+ @patch(MODULE_PATH + ".app_settings.ESI_API_URL", "https://www.example.com/esi/")
241
+ def test_build_spec_url(self):
242
+ self.assertEqual(
243
+ build_spec_url("v2"), "https://www.example.com/esi/v2/swagger.json"
244
+ )
245
+
246
+ @requests_mock.Mocker()
247
+ @patch(MODULE_PATH + ".app_settings.ESI_SPEC_CACHE_DURATION", 1)
248
+ def test_get_spec_defaults(self, requests_mocker):
249
+ # given
250
+ requests_mocker.register_uri(
251
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
252
+ )
253
+ requests_mocker.register_uri(
254
+ "GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec
255
+ )
256
+ # when
257
+ spec = get_spec("latest")
258
+ # then
259
+ self.assertIsInstance(spec, Spec)
260
+
261
+ @patch(MODULE_PATH + ".app_settings.ESI_SPEC_CACHE_DURATION", 1)
262
+ def test_get_spec_with_http_client(self):
263
+ mock_http_client = Mock(spec=RequestsClient)
264
+ mock_http_client.request.return_value.result.return_value.json.return_value = (
265
+ self.spec
266
+ )
267
+ spec = get_spec("latest", http_client=mock_http_client)
268
+ self.assertIsInstance(spec, Spec)
269
+
270
+ @patch(MODULE_PATH + ".app_settings.ESI_SPEC_CACHE_DURATION", 1)
271
+ def test_get_spec_with_config(self):
272
+ mock_http_client = Mock(spec=RequestsClient)
273
+ mock_http_client.request.return_value.result.return_value.json.return_value = (
274
+ self.spec
275
+ )
276
+ spec = get_spec(
277
+ "latest", http_client=mock_http_client, config={"dummy_config": True}
278
+ )
279
+ self.assertIsInstance(spec, Spec)
280
+ self.assertIn("dummy_config", spec.config)
281
+
282
+ @patch(MODULE_PATH + ".app_settings.ESI_SPEC_CACHE_DURATION", 1)
283
+ def test_build_spec_defaults(self):
284
+ mock_http_client = Mock(spec=RequestsClient)
285
+ mock_http_client.request.return_value.result.return_value.json.return_value = (
286
+ self.spec
287
+ )
288
+ spec = build_spec("v1", http_client=mock_http_client)
289
+ self.assertIsInstance(spec, Spec)
290
+
291
+ @patch(MODULE_PATH + ".app_settings.ESI_SPEC_CACHE_DURATION", 1)
292
+ def test_build_spec_explicit_resource_found(self):
293
+ mock_http_client = Mock(spec=RequestsClient)
294
+ mock_http_client.request.return_value.result.return_value.json.return_value = (
295
+ self.spec
296
+ )
297
+ spec = build_spec("v1", http_client=mock_http_client, Status="v1")
298
+ self.assertIsInstance(spec, Spec)
299
+
300
+ @patch(MODULE_PATH + ".app_settings.ESI_SPEC_CACHE_DURATION", 1)
301
+ def test_build_spec_explicit_resource_not_found(self):
302
+ mock_http_client = Mock(spec=RequestsClient)
303
+ mock_http_client.request.return_value.result.return_value.json.return_value = (
304
+ self.spec
305
+ )
306
+ with self.assertRaises(AttributeError):
307
+ build_spec("v1", http_client=mock_http_client, Character="v4")
308
+
309
+ @requests_mock.Mocker()
310
+ def test_read_spec(self, requests_mocker):
311
+ # given
312
+ requests_mocker.register_uri(
313
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
314
+ )
315
+ # when
316
+ client = read_spec(SWAGGER_SPEC_PATH_MINIMAL)
317
+ # then
318
+ self.assertIsInstance(client, SwaggerClient)
319
+
320
+ def test_minimize_spec_defaults(self):
321
+ spec_dict = minimize_spec(self.spec)
322
+ self.assertIsInstance(spec_dict, dict)
323
+ # todo: add better verification of functionality
324
+
325
+ def test_minimize_spec_resources(self):
326
+ spec_dict = minimize_spec(self.spec, resources=["Status"])
327
+ self.assertIsInstance(spec_dict, dict)
328
+ # todo: add better verification of functionality
329
+
330
+
331
+ @patch(MODULE_PATH + ".app_settings.ESI_SPEC_CACHE_DURATION", 1)
332
+ @requests_mock.Mocker()
333
+ class TestEsiClientFactory(NoSocketsTestCase):
334
+ @classmethod
335
+ def setUpClass(cls):
336
+ super().setUpClass()
337
+ cls.spec = _load_json_file(SWAGGER_SPEC_PATH_MINIMAL)
338
+
339
+ def setUp(self):
340
+ self.user = User.objects.create_user(
341
+ "Bruce Wayne", "abc@example.com", "password"
342
+ )
343
+ self.token = _store_as_Token(
344
+ _generate_token(
345
+ character_id=101,
346
+ character_name=self.user.username,
347
+ scopes=["abc"],
348
+ access_token="my_access_token",
349
+ ),
350
+ self.user,
351
+ )
352
+
353
+ def test_minimal_client(self, requests_mocker):
354
+ requests_mocker.register_uri(
355
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
356
+ )
357
+ requests_mocker.register_uri(
358
+ "GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec
359
+ )
360
+ # when
361
+ client = esi_client_factory()
362
+ # then
363
+ self.assertIsInstance(client, SwaggerClient)
364
+
365
+ def test_client_with_token(self, requests_mocker):
366
+ # given
367
+ requests_mocker.register_uri(
368
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
369
+ )
370
+ requests_mocker.register_uri(
371
+ "GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec
372
+ )
373
+ # when
374
+ client = esi_client_factory(token=self.token)
375
+ # then
376
+ self.assertIsInstance(client, SwaggerClient)
377
+
378
+ def test_client_with_version(self, requests_mocker):
379
+ # given
380
+ requests_mocker.register_uri(
381
+ "GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec
382
+ )
383
+ requests_mocker.register_uri(
384
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
385
+ )
386
+ requests_mocker.register_uri(
387
+ "GET", url="https://esi.evetech.net/v1/swagger.json", json=self.spec
388
+ )
389
+ # when
390
+ client = esi_client_factory(version="v1")
391
+ # then
392
+ self.assertIsInstance(client, SwaggerClient)
393
+
394
+ def test_client_with_spec_file(self, requests_mocker):
395
+ # given
396
+ requests_mocker.register_uri(
397
+ "GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec
398
+ )
399
+ requests_mocker.register_uri(
400
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
401
+ )
402
+ # when
403
+ client = esi_client_factory(spec_file=SWAGGER_SPEC_PATH_MINIMAL)
404
+ # then
405
+ self.assertIsInstance(client, SwaggerClient)
406
+
407
+ def test_client_with_explicit_resource(self, requests_mocker):
408
+ # given
409
+ requests_mocker.register_uri(
410
+ "GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec
411
+ )
412
+ requests_mocker.register_uri(
413
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
414
+ )
415
+ requests_mocker.register_uri(
416
+ "GET", url="https://esi.evetech.net/v1/swagger.json", json=self.spec
417
+ )
418
+ # when
419
+ client = esi_client_factory(Status="v1")
420
+ # then
421
+ self.assertIsInstance(client, SwaggerClient)
422
+
423
+ def test__time_to_expiry_failure(self, requests_mocker):
424
+ seconds = CachingHttpFuture._time_to_expiry("fail")
425
+ self.assertEqual(seconds, 0)
426
+
427
+
428
+ @patch(MODULE_PATH + ".HttpFuture.result")
429
+ class TestClientResult(NoSocketsTestCase):
430
+ @classmethod
431
+ def setUpClass(cls) -> None:
432
+ super().setUpClass()
433
+ spec = _load_json_file(SWAGGER_SPEC_PATH_MINIMAL)
434
+ with requests_mock.Mocker() as requests_mocker:
435
+ requests_mocker.register_uri(
436
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=spec
437
+ )
438
+ cls.esi_client = esi_client_factory(spec_file=SWAGGER_SPEC_PATH_MINIMAL)
439
+
440
+ @patch(MODULE_PATH + ".app_settings.ESI_REQUESTS_CONNECT_TIMEOUT", 10)
441
+ @patch(MODULE_PATH + ".app_settings.ESI_REQUESTS_READ_TIMEOUT", 60)
442
+ def test_use_default_timeout(self, mock_future_result):
443
+ # given
444
+ mock_future_result.return_value = (None, Mock(**{"headers": {}}))
445
+ # when
446
+ self.esi_client.Status.get_status().result()
447
+ # then
448
+ self.assertTrue(mock_future_result.called)
449
+ _, kwargs = mock_future_result.call_args
450
+ self.assertEqual(kwargs["timeout"], (10, 60))
451
+
452
+ @patch(MODULE_PATH + ".app_settings.ESI_REQUESTS_CONNECT_TIMEOUT", 10)
453
+ @patch(MODULE_PATH + ".app_settings.ESI_REQUESTS_READ_TIMEOUT", 60)
454
+ def test_use_custom_timeout(self, mock_future_result):
455
+ # given
456
+ mock_future_result.return_value = (None, Mock(**{"headers": {}}))
457
+ # when
458
+ self.esi_client.Status.get_status().result(timeout=42)
459
+ # then
460
+ self.assertTrue(mock_future_result.called)
461
+ _, kwargs = mock_future_result.call_args
462
+ self.assertEqual(kwargs["timeout"], 42)
463
+
464
+ def test_support_language_parameter(self, mock_future_result):
465
+ # given
466
+ mock_future_result.return_value = (None, Mock(**{"headers": {}}))
467
+ my_language = "de"
468
+ operation = self.esi_client.Status.get_status()
469
+ # when
470
+ operation.result(language=my_language)
471
+ # then
472
+ self.assertTrue(mock_future_result.called)
473
+ self.assertEqual(operation.future.request.params["language"], my_language)
474
+ _, kwargs = mock_future_result.call_args
475
+ self.assertNotIn("language", kwargs)
476
+
477
+ @patch(MODULE_PATH + ".app_settings.ESI_SERVER_ERROR_BACKOFF_FACTOR", 0.5)
478
+ @patch(MODULE_PATH + ".app_settings.ESI_SERVER_ERROR_MAX_RETRIES", 3)
479
+ @patch(MODULE_PATH + ".sleep", wraps=lambda x: None)
480
+ def test_retries_1(self, mock_sleep, mock_future_result):
481
+ mock_future_result.side_effect = create_http_error(502)
482
+ try:
483
+ self.esi_client.Status.get_status().result()
484
+ except HTTPBadGateway as e:
485
+ # requests error thrown
486
+ self.assertIsInstance(e, HTTPBadGateway)
487
+ # we tried # times before raising
488
+ self.assertEqual(mock_future_result.call_count, 4)
489
+ call_list = mock_sleep.call_args_list
490
+ result = [args[0] for args, _ in [x for x in call_list]]
491
+ expected = [0.5, 1.0, 2.0]
492
+ self.assertListEqual(expected, result)
493
+
494
+ @patch(MODULE_PATH + ".app_settings.ESI_SERVER_ERROR_BACKOFF_FACTOR", 0.5)
495
+ @patch(MODULE_PATH + ".app_settings.ESI_SERVER_ERROR_MAX_RETRIES", 1)
496
+ @patch(MODULE_PATH + ".sleep", lambda x: None)
497
+ def test_retries_2(self, mock_future_result):
498
+ mock_future_result.side_effect = create_http_error(502)
499
+ try:
500
+ self.esi_client.Status.get_status().result()
501
+ except HTTPBadGateway as e:
502
+ # requests error thrown
503
+ self.assertIsInstance(e, HTTPBadGateway)
504
+ # we tried # times before raising
505
+ self.assertEqual(mock_future_result.call_count, 2)
506
+
507
+ @patch(MODULE_PATH + ".app_settings.ESI_SERVER_ERROR_BACKOFF_FACTOR", 0.5)
508
+ @patch(MODULE_PATH + ".app_settings.ESI_SERVER_ERROR_MAX_RETRIES", 0)
509
+ @patch(MODULE_PATH + ".sleep", lambda x: None)
510
+ def test_retries_3(self, mock_future_result):
511
+ mock_future_result.side_effect = create_http_error(502)
512
+ try:
513
+ self.esi_client.Status.get_status().result()
514
+ except HTTPBadGateway as e:
515
+ # requests error thrown
516
+ self.assertIsInstance(e, HTTPBadGateway)
517
+ # we tried # times before raising
518
+ self.assertEqual(mock_future_result.call_count, 1)
519
+
520
+ @patch(MODULE_PATH + ".app_settings.ESI_SERVER_ERROR_BACKOFF_FACTOR", 0.5)
521
+ @patch(MODULE_PATH + ".app_settings.ESI_SERVER_ERROR_MAX_RETRIES", 4)
522
+ @patch(MODULE_PATH + ".sleep", lambda x: None)
523
+ def test_retry_with_custom_retries(self, mock_future_result):
524
+ mock_future_result.side_effect = create_http_error(502)
525
+ try:
526
+ self.esi_client.Status.get_status().result(retries=1)
527
+ except HTTPBadGateway as e:
528
+ # requests error thrown
529
+ self.assertIsInstance(e, HTTPBadGateway)
530
+ # we tried # times before raising
531
+ self.assertEqual(mock_future_result.call_count, 2)
532
+
533
+
534
+ @patch(MODULE_PATH + ".HttpFuture.result")
535
+ class TestClientResultAllPages(NoSocketsTestCase):
536
+ @classmethod
537
+ def setUpClass(cls) -> None:
538
+ super().setUpClass()
539
+ spec = _load_json_file(SWAGGER_SPEC_PATH_FULL)
540
+ with requests_mock.Mocker() as requests_mocker:
541
+ requests_mocker.register_uri(
542
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=spec
543
+ )
544
+ cls.esi_client = esi_client_factory(spec_file=SWAGGER_SPEC_PATH_FULL)
545
+
546
+ def test_pages(self, mock_future_result):
547
+ class MockResultHeaders:
548
+ def __init__(self):
549
+ self.headers = {"X-Pages": 10}
550
+ self.status_code = 200
551
+ self.text = "dummy"
552
+
553
+ # given
554
+ mock_future_result.return_value = ({"contract_test": 1}, MockResultHeaders())
555
+ self.esi_client.Contracts.get_contracts_public_region_id(region_id=1).results()
556
+ # then
557
+ self.assertEqual(mock_future_result.call_count, 10) # we got 10 pages of data
558
+
559
+ def test_pages_response(self, mock_future_result):
560
+ class MockResultHeaders:
561
+ def __init__(self):
562
+ self.headers = {"X-Pages": 10}
563
+ self.status_code = 200
564
+ self.text = "dummy"
565
+
566
+ # given
567
+ mock_future_result.return_value = ({"contract_test": 1}, MockResultHeaders())
568
+ o = self.esi_client.Contracts.get_contracts_public_region_id(region_id=1)
569
+ o.request_config.also_return_response = True
570
+ # when
571
+ result, response = o.results()
572
+ # then
573
+ self.assertEqual(mock_future_result.call_count, 10) # we got 10 pages of data
574
+ self.assertEqual(len(result), 10) # we got 10 lots of data
575
+ self.assertEqual(response.headers, {"X-Pages": 10}) # we got header of data
576
+
577
+ def test_pages_on_non_paged_endpoint(self, mock_future_result):
578
+ class MockResultHeaders:
579
+ def __init__(self):
580
+ self.headers = {"header_test": "ok"}
581
+ self.status_code = 200
582
+ self.text = "dummy"
583
+
584
+ # given
585
+ mock_future_result.return_value = ({"status_test": 1}, MockResultHeaders())
586
+ # when
587
+ self.esi_client.Status.get_status().results()
588
+ # then
589
+ self.assertEqual(mock_future_result.call_count, 1) # we got no pages of data
590
+
591
+
592
+ @patch(MODULE_PATH + ".app_settings.ESI_LANGUAGES", ["lang1", "lang2", "lang3"])
593
+ @patch(MODULE_PATH + ".CachingHttpFuture.results", spec=True)
594
+ @requests_mock.Mocker()
595
+ class TestClientResultsLocalized(NoSocketsTestCase):
596
+ @classmethod
597
+ def setUpClass(cls) -> None:
598
+ super().setUpClass()
599
+ cls.spec = _load_json_file(SWAGGER_SPEC_PATH_MINIMAL)
600
+
601
+ @staticmethod
602
+ def my_results(**kwargs):
603
+ if "language" in kwargs:
604
+ return "response_" + kwargs["language"]
605
+ return ""
606
+
607
+ def test_default(self, mock_future_results, requests_mocker):
608
+ # given
609
+ mock_future_results.side_effect = self.my_results
610
+ requests_mocker.register_uri(
611
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
612
+ )
613
+ client = esi_client_factory(spec_file=SWAGGER_SPEC_PATH_MINIMAL)
614
+ # when
615
+ result = client.Status.get_status().results_localized()
616
+ # then
617
+ expected = {
618
+ "lang1": "response_lang1",
619
+ "lang2": "response_lang2",
620
+ "lang3": "response_lang3",
621
+ }
622
+ self.assertDictEqual(result, expected)
623
+
624
+ def test_custom_languages(self, mock_future_results, requests_mocker):
625
+ # given
626
+ mock_future_results.side_effect = self.my_results
627
+ requests_mocker.register_uri(
628
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
629
+ )
630
+ client = esi_client_factory(spec_file=SWAGGER_SPEC_PATH_MINIMAL)
631
+ # when
632
+ result = client.Status.get_status().results_localized(
633
+ languages=["lang2", "lang3"]
634
+ )
635
+ # then
636
+ expected = {
637
+ "lang2": "response_lang2",
638
+ "lang3": "response_lang3",
639
+ }
640
+ self.assertDictEqual(result, expected)
641
+
642
+ def test_raise_on_invalid_language(self, mock_future_results, requests_mocker):
643
+ # given
644
+ mock_future_results.side_effect = self.my_results
645
+ requests_mocker.register_uri(
646
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
647
+ )
648
+ client = esi_client_factory(spec_file=SWAGGER_SPEC_PATH_MINIMAL)
649
+ # when/then
650
+ with self.assertRaises(ValueError):
651
+ client.Status.get_status().results_localized(languages=["lang2", "xxx"])
652
+
653
+
654
+ @requests_mock.Mocker()
655
+ class TestEsiClientProvider(NoSocketsTestCase):
656
+ @classmethod
657
+ def setUpClass(cls) -> None:
658
+ super().setUpClass()
659
+ cls.spec = _load_json_file(SWAGGER_SPEC_PATH_MINIMAL)
660
+
661
+ def test_client_loads_on_demand(self, requests_mocker):
662
+ # given
663
+ requests_mocker.register_uri(
664
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
665
+ )
666
+ requests_mocker.register_uri(
667
+ "GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec
668
+ )
669
+ my_provider = EsiClientProvider()
670
+ # when
671
+ esi_client = my_provider.client
672
+ # then
673
+ self.assertIsInstance(esi_client, SwaggerClient)
674
+ self.assertIsInstance(my_provider, EsiClientProvider)
675
+ self.assertIsInstance(my_provider.client, SwaggerClient)
676
+ self.assertEqual(str(my_provider), "EsiClientProvider")
677
+
678
+ # FIXME: This test currently fails sometimes when run with tox.
679
+ # def test_with_version(self, requests_mocker):
680
+ # # given
681
+ # requests_mocker.register_uri(
682
+ # "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
683
+ # )
684
+ # requests_mocker.register_uri(
685
+ # "GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec
686
+ # )
687
+ # requests_mocker.register_uri(
688
+ # "GET", url="https://esi.evetech.net/v1/swagger.json", json=self.spec
689
+ # )
690
+ # my_provider = EsiClientProvider(version="v1")
691
+ # # when
692
+ # esi_client = my_provider.client
693
+ # # then
694
+ # self.assertIsInstance(esi_client, SwaggerClient)
695
+ # urls_callled = [x.url for x in requests_mocker.request_history]
696
+ # self.assertIn("https://esi.evetech.net/v1/swagger.json", urls_callled)
697
+
698
+ def test_with_spec_file(self, requests_mocker):
699
+ # given
700
+ requests_mocker.register_uri(
701
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec
702
+ )
703
+ requests_mocker.register_uri(
704
+ "GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec
705
+ )
706
+ my_provider = EsiClientProvider(spec_file=SWAGGER_SPEC_PATH_MINIMAL)
707
+ # when
708
+ esi_client = my_provider.client
709
+ # then
710
+ self.assertIsInstance(esi_client, SwaggerClient)
711
+
712
+
713
+ @requests_mock.Mocker()
714
+ class TestClientResult2(NoSocketsTestCase):
715
+ @classmethod
716
+ def setUpClass(cls) -> None:
717
+ super().setUpClass()
718
+ spec = _load_json_file(SWAGGER_SPEC_PATH_MINIMAL)
719
+ with patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com"), patch(
720
+ MODULE_PATH + ".__title__", "Django-ESI"
721
+ ), patch(MODULE_PATH + ".__version__", "1.0.0"):
722
+ with requests_mock.Mocker() as requests_mocker:
723
+ requests_mocker.register_uri(
724
+ "GET", url="https://esi.evetech.net/_latest/swagger.json", json=spec
725
+ )
726
+ cls.esi_client = esi_client_factory(spec_file=SWAGGER_SPEC_PATH_MINIMAL)
727
+
728
+ def test_normal_call(self, requests_mocker):
729
+ # given
730
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/")
731
+ # when
732
+ self.esi_client.Status.get_status().result()
733
+ # then
734
+ self.assertTrue(requests_mocker.called)
735
+ request = requests_mocker.last_request
736
+
737
+ expected_title = 'DjangoEsi'
738
+
739
+ self.assertEqual(request._request.headers["User-Agent"], f"{expected_title}/1.0.0 (email@example.com; +https://gitlab.com/allianceauth/django-esi)")
740
+
741
+ def test_existing_headers(self, requests_mocker):
742
+ # given
743
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/")
744
+ # when
745
+ self.esi_client.Status.get_status().result()
746
+ # then
747
+ self.assertTrue(requests_mocker.called)
748
+ request = requests_mocker.last_request
749
+
750
+ expected_title = 'DjangoEsi'
751
+
752
+ self.assertEqual(request._request.headers["User-Agent"], f"{expected_title}/1.0.0 (email@example.com; +https://gitlab.com/allianceauth/django-esi)")
753
+
754
+
755
+ class TestRequestsClientPlus(NoSocketsTestCase):
756
+ def test_single_header(self):
757
+ """When no headers are set, just add the new header"""
758
+ obj = RequestsClientPlus()
759
+ obj.user_agent = "abc"
760
+ result = obj.request(
761
+ {"method": "GET", "url": "https://esi.evetech.net/v1/status/"}
762
+ )
763
+ self.assertEqual(result.future.request.headers["User-Agent"], "abc")
764
+
765
+ def test_existing_header(self):
766
+ """When a header exists, leave it intact"""
767
+ obj = RequestsClientPlus()
768
+ obj.user_agent = "abc"
769
+ result = obj.request(
770
+ {
771
+ "method": "GET",
772
+ "url": "https://esi.evetech.net/v1/status/",
773
+ "headers": {"From": "email@example.com"},
774
+ }
775
+ )
776
+ self.assertEqual(result.future.request.headers["User-Agent"], "abc")
777
+ self.assertEqual(result.future.request.headers["From"], "email@example.com")
778
+
779
+ def test_no_user_agent(self):
780
+ """When no user agent is defined, leave the existing header intact"""
781
+ obj = RequestsClientPlus()
782
+ result = obj.request(
783
+ {
784
+ "method": "GET",
785
+ "url": "https://esi.evetech.net/v1/status/",
786
+ "headers": {"From": "email@example.com"},
787
+ }
788
+ )
789
+ self.assertEqual(result.future.request.headers["From"], "email@example.com")
790
+ self.assertNotIn("User-Agent", result.future.request.headers)
791
+
792
+
793
+ @patch(MODULE_PATH + ".__title__", "Django-ESI")
794
+ @patch(MODULE_PATH + ".__version__", "1.0.0")
795
+ @requests_mock.Mocker()
796
+ class TestEsiClientFactoryAppText(NoSocketsTestCase):
797
+ @classmethod
798
+ def setUpClass(cls) -> None:
799
+ super().setUpClass()
800
+ cls.spec = _load_json_file(SWAGGER_SPEC_PATH_MINIMAL)
801
+ cls.status_response = {
802
+ "players": 12345,
803
+ "server_version": "1132976",
804
+ "start_time": "2017-01-02T12:34:56Z",
805
+ }
806
+
807
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", None)
808
+ def test_defaults(self, requests_mocker) -> None:
809
+ # This test is not expected to hit given that ESI_USER_CONTACT_EMAIL must be set
810
+ # But here it is for completeness
811
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
812
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
813
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
814
+ client = esi_client_factory()
815
+ # when
816
+ operation = client.Status.get_status()
817
+ # then
818
+ expected_app_name = "MyApp"
819
+ expected_title = 'DjangoEsi'
820
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_title}/1.0.0 (None; +https://gitlab.com/allianceauth/django-esi)")
821
+
822
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
823
+ def test_defaults_email(self, requests_mocker) -> None:
824
+ # given
825
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
826
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
827
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
828
+ client = esi_client_factory()
829
+ # when
830
+ operation = client.Status.get_status()
831
+ # then
832
+ expected_app_name = "MyApp"
833
+ expected_title = 'DjangoEsi'
834
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_title}/1.0.0 (email@example.com; +https://gitlab.com/allianceauth/django-esi)")
835
+
836
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", None)
837
+ def test_app_text(self, requests_mocker) -> None:
838
+ # Deprecated
839
+ # This test is not expected to hit given that ESI_USER_CONTACT_EMAIL must be set
840
+ # given
841
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
842
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
843
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
844
+ client = esi_client_factory(app_info_text="my-app v1.0.0")
845
+ # when
846
+ operation = client.Status.get_status()
847
+ # then
848
+ expected_app_name = "MyApp"
849
+ expected_title = 'DjangoEsi'
850
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"my-app v1.0.0 (None) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)",)
851
+
852
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
853
+ def test_app_text_with_email(self, requests_mocker):
854
+ # Deprecated
855
+ # given
856
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
857
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
858
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
859
+ client = esi_client_factory(app_info_text="my-app v1.0.0")
860
+ # when
861
+ operation = client.Status.get_status()
862
+ # then
863
+ expected_app_name = "MyApp"
864
+ expected_title = 'DjangoEsi'
865
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"my-app v1.0.0 (email@example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)",)
866
+
867
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
868
+ def test_ua_generator(self, requests_mocker):
869
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
870
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
871
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
872
+ client = esi_client_factory(ua_appname="MyApp", ua_version="1.0.0")
873
+ # when
874
+ operation = client.Status.get_status()
875
+ # then
876
+ expected_app_name = "MyApp"
877
+ expected_title = 'DjangoEsi'
878
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_app_name}/1.0.0 (email@example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
879
+
880
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
881
+ def test_ua_generator_for_appname_with_spaces(self, requests_mocker):
882
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
883
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
884
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
885
+ client = esi_client_factory(ua_appname="My App", ua_version="1.0.0")
886
+
887
+ # when
888
+ operation = client.Status.get_status()
889
+
890
+ # then
891
+ expected_app_name = "MyApp"
892
+ expected_title = 'DjangoEsi'
893
+
894
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_app_name}/1.0.0 (email@example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
895
+
896
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
897
+ def test_ua_generator_for_appname_with_hyphens(self, requests_mocker):
898
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
899
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
900
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
901
+ client = esi_client_factory(ua_appname="My-App", ua_version="1.0.0")
902
+
903
+ # when
904
+ operation = client.Status.get_status()
905
+
906
+ # then
907
+ expected_app_name = "MyApp"
908
+ expected_title = 'DjangoEsi'
909
+
910
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_app_name}/1.0.0 (email@example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
911
+
912
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
913
+ def test_ua_generator_with_url(self, requests_mocker):
914
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
915
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
916
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
917
+ client = esi_client_factory(ua_appname="MyApp", ua_version="1.0.0", ua_url="https://example.com")
918
+ # when
919
+ operation = client.Status.get_status()
920
+ # then
921
+ expected_app_name = "MyApp"
922
+ expected_title = 'DjangoEsi'
923
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_app_name}/1.0.0 (email@example.com; +https://example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
924
+
925
+ @patch(MODULE_PATH + ".__title__", "Django-ESI")
926
+ @patch(MODULE_PATH + ".__version__", "1.0.0")
927
+ @requests_mock.Mocker()
928
+ class TestEsiClientProviderAppText(NoSocketsTestCase):
929
+ @classmethod
930
+ def setUpClass(cls) -> None:
931
+ super().setUpClass()
932
+ cls.spec = _load_json_file(SWAGGER_SPEC_PATH_MINIMAL)
933
+ cls.status_response = {
934
+ "players": 12345,
935
+ "server_version": "1132976",
936
+ "start_time": "2017-01-02T12:34:56Z",
937
+ }
938
+
939
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", None)
940
+ def test_defaults(self, requests_mocker) -> None:
941
+ # This test is not expected to hit given that ESI_USER_CONTACT_EMAIL must be set
942
+ # But here it is for completeness
943
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
944
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
945
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
946
+ client = EsiClientProvider().client
947
+ # when
948
+ operation = client.Status.get_status()
949
+ # then
950
+ expected_title = 'DjangoEsi'
951
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_title}/1.0.0 (None; +https://gitlab.com/allianceauth/django-esi)")
952
+
953
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
954
+ def test_defaults_email(self, requests_mocker) -> None:
955
+ # given
956
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
957
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
958
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
959
+ client = EsiClientProvider().client
960
+ # when
961
+ operation = client.Status.get_status()
962
+ # then
963
+ expected_title = 'DjangoEsi'
964
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_title}/1.0.0 (email@example.com; +https://gitlab.com/allianceauth/django-esi)")
965
+
966
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", None)
967
+ def test_app_text(self, requests_mocker) -> None:
968
+ # Deprecated
969
+ # This test is not expected to hit given that ESI_USER_CONTACT_EMAIL must be set
970
+ # given
971
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
972
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
973
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
974
+ client = EsiClientProvider(app_info_text="my-app v1.0.0").client
975
+ # when
976
+ operation = client.Status.get_status()
977
+ # then
978
+ expected_title = 'DjangoEsi'
979
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"my-app v1.0.0 (None) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)",)
980
+
981
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
982
+ def test_app_text_with_email(self, requests_mocker):
983
+ # Deprecated
984
+ # given
985
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
986
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
987
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
988
+ client = EsiClientProvider(app_info_text="my-app v1.0.0").client
989
+ # when
990
+ operation = client.Status.get_status()
991
+ # then
992
+ expected_title = 'DjangoEsi'
993
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"my-app v1.0.0 (email@example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)",)
994
+
995
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
996
+ def test_ua_generator(self, requests_mocker):
997
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
998
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
999
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
1000
+ client = EsiClientProvider(ua_appname="MyApp", ua_version="1.0.0").client
1001
+ # when
1002
+ operation = client.Status.get_status()
1003
+ # then
1004
+ expected_app_name = "MyApp"
1005
+ expected_title = 'DjangoEsi'
1006
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_app_name}/1.0.0 (email@example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")
1007
+
1008
+ @patch(MODULE_PATH + ".app_settings.ESI_USER_CONTACT_EMAIL", "email@example.com")
1009
+ def test_ua_generator_with_url(self, requests_mocker):
1010
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/_latest/swagger.json", json=self.spec)
1011
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/latest/swagger.json", json=self.spec)
1012
+ requests_mocker.register_uri("GET", url="https://esi.evetech.net/v1/status/", json=self.status_response)
1013
+ client = EsiClientProvider(ua_appname="MyApp", ua_version="1.0.0", ua_url="https://example.com").client
1014
+ # when
1015
+ operation = client.Status.get_status()
1016
+ # then
1017
+ expected_app_name = "MyApp"
1018
+ expected_title = 'DjangoEsi'
1019
+ self.assertEqual(operation.future.request.headers["User-Agent"], f"{expected_app_name}/1.0.0 (email@example.com; +https://example.com) {expected_title}/1.0.0 (+https://gitlab.com/allianceauth/django-esi)")