django-esi 8.0.0a4__py3-none-any.whl → 8.0.0b2__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.
Potentially problematic release.
This version of django-esi might be problematic. Click here for more details.
- {django_esi-8.0.0a4.dist-info → django_esi-8.0.0b2.dist-info}/METADATA +5 -3
- {django_esi-8.0.0a4.dist-info → django_esi-8.0.0b2.dist-info}/RECORD +48 -47
- esi/__init__.py +1 -1
- esi/aiopenapi3/plugins.py +99 -3
- esi/clients.py +56 -7
- esi/decorators.py +26 -10
- esi/exceptions.py +7 -3
- esi/helpers.py +38 -0
- esi/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
- esi/locale/cs_CZ/LC_MESSAGES/django.po +2 -2
- esi/locale/de/LC_MESSAGES/django.mo +0 -0
- esi/locale/de/LC_MESSAGES/django.po +2 -2
- esi/locale/en/LC_MESSAGES/django.mo +0 -0
- esi/locale/en/LC_MESSAGES/django.po +2 -2
- esi/locale/es/LC_MESSAGES/django.mo +0 -0
- esi/locale/es/LC_MESSAGES/django.po +2 -2
- esi/locale/fr_FR/LC_MESSAGES/django.mo +0 -0
- esi/locale/fr_FR/LC_MESSAGES/django.po +2 -2
- esi/locale/it_IT/LC_MESSAGES/django.mo +0 -0
- esi/locale/it_IT/LC_MESSAGES/django.po +2 -2
- esi/locale/ja/LC_MESSAGES/django.mo +0 -0
- esi/locale/ja/LC_MESSAGES/django.po +2 -2
- esi/locale/ko_KR/LC_MESSAGES/django.mo +0 -0
- esi/locale/ko_KR/LC_MESSAGES/django.po +2 -2
- esi/locale/nl_NL/LC_MESSAGES/django.mo +0 -0
- esi/locale/nl_NL/LC_MESSAGES/django.po +2 -2
- esi/locale/pl_PL/LC_MESSAGES/django.mo +0 -0
- esi/locale/pl_PL/LC_MESSAGES/django.po +2 -2
- esi/locale/ru/LC_MESSAGES/django.mo +0 -0
- esi/locale/ru/LC_MESSAGES/django.po +2 -2
- esi/locale/sk/LC_MESSAGES/django.mo +0 -0
- esi/locale/sk/LC_MESSAGES/django.po +2 -2
- esi/locale/uk/LC_MESSAGES/django.mo +0 -0
- esi/locale/uk/LC_MESSAGES/django.po +2 -2
- esi/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
- esi/locale/zh_Hans/LC_MESSAGES/django.po +2 -2
- esi/managers.pyi +3 -0
- esi/openapi_clients.py +188 -44
- esi/rate_limiting.py +50 -21
- esi/signals.py +21 -0
- esi/stubs.pyi +9 -9
- esi/tests/__init__.py +33 -11
- esi/tests/test_clients.py +77 -19
- esi/tests/test_decorators.py +61 -1
- esi/tests/test_openapi.json +65 -2
- esi/tests/test_openapi.py +512 -18
- {django_esi-8.0.0a4.dist-info → django_esi-8.0.0b2.dist-info}/WHEEL +0 -0
- {django_esi-8.0.0a4.dist-info → django_esi-8.0.0b2.dist-info}/licenses/LICENSE +0 -0
esi/tests/test_openapi.py
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import os
|
|
2
|
-
from unittest import mock
|
|
3
3
|
from unittest.mock import MagicMock, patch
|
|
4
4
|
from django.test import TestCase
|
|
5
5
|
from datetime import date, timedelta
|
|
6
6
|
|
|
7
7
|
from esi.openapi_clients import ESIClientProvider
|
|
8
|
+
from django.core.cache import cache
|
|
8
9
|
from django.utils import timezone
|
|
10
|
+
from esi.tests import NoSocketsTestCase
|
|
9
11
|
from httpx import RequestError, HTTPStatusError
|
|
10
|
-
from esi.exceptions import ESIErrorLimitException
|
|
12
|
+
from esi.exceptions import ESIErrorLimitException, HTTPClientError, HTTPNotModified, ESIBucketLimitException, HTTPServerError
|
|
13
|
+
from esi.rate_limiting import ESIRateLimits
|
|
11
14
|
from esi import app_settings
|
|
12
15
|
from esi import __title__, __url__, __version__
|
|
13
16
|
import httpx
|
|
14
17
|
|
|
18
|
+
from . import _generate_token
|
|
15
19
|
from .. import openapi_clients as oc
|
|
16
20
|
|
|
17
21
|
SPEC_PATH = os.path.join(
|
|
18
22
|
os.path.dirname(os.path.abspath(__file__)), "test_openapi.json"
|
|
19
23
|
)
|
|
24
|
+
MODULE_PATH_PLUGINS = 'esi.aiopenapi3.plugins'
|
|
20
25
|
|
|
21
26
|
|
|
22
27
|
class TestClientFunctions(TestCase):
|
|
@@ -69,28 +74,80 @@ class TestClientFunctions(TestCase):
|
|
|
69
74
|
|
|
70
75
|
|
|
71
76
|
class BuildUserAgentTests(TestCase):
|
|
72
|
-
app_name = "
|
|
77
|
+
app_name = "TestApp"
|
|
73
78
|
app_ver = "1.2.3"
|
|
74
79
|
app_url = "https://tests.pass"
|
|
75
80
|
|
|
76
81
|
def test_build_user_agent_with_url(self):
|
|
77
82
|
ua = oc._build_user_agent(self.app_name, self.app_ver, self.app_url)
|
|
83
|
+
|
|
84
|
+
expected_app_name = "TestApp"
|
|
85
|
+
expected_title = "DjangoEsi"
|
|
86
|
+
|
|
87
|
+
self.assertEqual(
|
|
88
|
+
(
|
|
89
|
+
f"{expected_app_name}/{self.app_ver} "
|
|
90
|
+
f"({app_settings.ESI_USER_CONTACT_EMAIL}{f'; +{self.app_url})'} "
|
|
91
|
+
f"{expected_title}/{__version__} (+{__url__})"
|
|
92
|
+
),
|
|
93
|
+
ua
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def test_enforce_pascal_case_for_ua_appname_with_space(self):
|
|
97
|
+
"""
|
|
98
|
+
Test that the application name is converted to PascalCase in the User-Agent string when it contains spaces.
|
|
99
|
+
|
|
100
|
+
:return:
|
|
101
|
+
:rtype:
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
ua = oc._build_user_agent("test app", self.app_ver, self.app_url)
|
|
105
|
+
|
|
106
|
+
expected_app_name = "TestApp"
|
|
107
|
+
expected_title = "DjangoEsi"
|
|
108
|
+
|
|
109
|
+
self.assertEqual(
|
|
110
|
+
(
|
|
111
|
+
f"{expected_app_name}/{self.app_ver} "
|
|
112
|
+
f"({app_settings.ESI_USER_CONTACT_EMAIL}{f'; +{self.app_url})'} "
|
|
113
|
+
f"{expected_title}/{__version__} (+{__url__})"
|
|
114
|
+
),
|
|
115
|
+
ua
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def test_enforce_pascal_case_for_ua_appname_with_hyphen(self):
|
|
119
|
+
"""
|
|
120
|
+
Test that the application name is converted to PascalCase in the User-Agent string when it contains hyphens.
|
|
121
|
+
|
|
122
|
+
:return:
|
|
123
|
+
:rtype:
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
ua = oc._build_user_agent("test-app", self.app_ver, self.app_url)
|
|
127
|
+
|
|
128
|
+
expected_app_name = "TestApp"
|
|
129
|
+
expected_title = "DjangoEsi"
|
|
130
|
+
|
|
78
131
|
self.assertEqual(
|
|
79
132
|
(
|
|
80
|
-
f"{
|
|
133
|
+
f"{expected_app_name}/{self.app_ver} "
|
|
81
134
|
f"({app_settings.ESI_USER_CONTACT_EMAIL}{f'; +{self.app_url})'} "
|
|
82
|
-
f"{
|
|
135
|
+
f"{expected_title}/{__version__} (+{__url__})"
|
|
83
136
|
),
|
|
84
137
|
ua
|
|
85
138
|
)
|
|
86
139
|
|
|
87
140
|
def test_build_user_agent_without_url(self):
|
|
88
141
|
ua = oc._build_user_agent(self.app_name, self.app_ver)
|
|
142
|
+
|
|
143
|
+
expected_app_name = "TestApp"
|
|
144
|
+
expected_title = "DjangoEsi"
|
|
145
|
+
|
|
89
146
|
self.assertEqual(
|
|
90
147
|
(
|
|
91
|
-
f"{
|
|
148
|
+
f"{expected_app_name}/{self.app_ver} "
|
|
92
149
|
f"({app_settings.ESI_USER_CONTACT_EMAIL}) "
|
|
93
|
-
f"{
|
|
150
|
+
f"{expected_title}/{__version__} (+{__url__})"
|
|
94
151
|
),
|
|
95
152
|
ua
|
|
96
153
|
)
|
|
@@ -123,6 +180,7 @@ class BaseEsiOperationTests(TestCase):
|
|
|
123
180
|
]
|
|
124
181
|
self.fake_op.tags = ["test"]
|
|
125
182
|
self.fake_op.operationId = "fake_op"
|
|
183
|
+
self.fake_op.extensions = {}
|
|
126
184
|
self.api = MagicMock(app_name="TestApp")
|
|
127
185
|
self.op = oc.BaseEsiOperation(
|
|
128
186
|
("GET", "/fake_op", self.fake_op, {}),
|
|
@@ -193,6 +251,19 @@ class EsiOperationTests(TestCase):
|
|
|
193
251
|
self.op_mock.parameters = []
|
|
194
252
|
self.op_mock.tags = ["tag"]
|
|
195
253
|
self.op_mock.operationId = "opid"
|
|
254
|
+
self.op_mock.extensions = {}
|
|
255
|
+
|
|
256
|
+
self.op_mock_rate = MagicMock()
|
|
257
|
+
self.op_mock_rate.parameters = []
|
|
258
|
+
self.op_mock_rate.tags = ["tag"]
|
|
259
|
+
self.op_mock_rate.operationId = "opidRated"
|
|
260
|
+
self.op_mock_rate.extensions = {
|
|
261
|
+
"rate-limit": {
|
|
262
|
+
"group": "test-group",
|
|
263
|
+
"max-tokens": 100,
|
|
264
|
+
"window-size": "5m"
|
|
265
|
+
}
|
|
266
|
+
}
|
|
196
267
|
|
|
197
268
|
self.api_mock = MagicMock()
|
|
198
269
|
self.api_mock.app_name = "TestApp"
|
|
@@ -207,6 +278,16 @@ class EsiOperationTests(TestCase):
|
|
|
207
278
|
self.api_mock
|
|
208
279
|
)
|
|
209
280
|
|
|
281
|
+
self.op_rate_rated = oc.EsiOperation(
|
|
282
|
+
(
|
|
283
|
+
"GET",
|
|
284
|
+
"/url",
|
|
285
|
+
self.op_mock_rate,
|
|
286
|
+
{}
|
|
287
|
+
),
|
|
288
|
+
self.api_mock
|
|
289
|
+
)
|
|
290
|
+
|
|
210
291
|
@patch.object(oc.EsiOperation, "_make_request")
|
|
211
292
|
def test_result_and_results(self, mock_make_request):
|
|
212
293
|
data = {"data": "stuff"}
|
|
@@ -215,8 +296,37 @@ class EsiOperationTests(TestCase):
|
|
|
215
296
|
data_resp = self.op(foo="bar").result()
|
|
216
297
|
self.assertEqual(data, data_resp)
|
|
217
298
|
|
|
299
|
+
def test_esi_bucket_public(self):
|
|
300
|
+
op = self.op_rate_rated(foo="bar")
|
|
301
|
+
self.assertEqual(op.bucket.window, 300)
|
|
302
|
+
self.assertEqual(op.bucket.slug, "test-group")
|
|
303
|
+
self.assertEqual(op.bucket.limit, 100)
|
|
304
|
+
|
|
305
|
+
def test_esi_bucket_limit(self):
|
|
306
|
+
op = self.op_rate_rated(foo="bar")
|
|
307
|
+
ESIRateLimits.set_bucket(op.bucket, 0)
|
|
308
|
+
|
|
309
|
+
with self.assertRaises(ESIBucketLimitException):
|
|
310
|
+
op.result()
|
|
311
|
+
|
|
312
|
+
class TestOpenapiClientProvider(NoSocketsTestCase):
|
|
313
|
+
def setUp(self):
|
|
314
|
+
self.app_name = "TestsApp"
|
|
315
|
+
self.app_ver = "1.2.3"
|
|
316
|
+
self.app_url = "https://tests.pass"
|
|
317
|
+
self.esi = ESIClientProvider(
|
|
318
|
+
ua_appname=self.app_name,
|
|
319
|
+
ua_url=self.app_url,
|
|
320
|
+
ua_version=self.app_ver,
|
|
321
|
+
compatibility_date="2020-01-01",
|
|
322
|
+
tags=["Status"],
|
|
323
|
+
spec_file=SPEC_PATH
|
|
324
|
+
)
|
|
325
|
+
cache.clear()
|
|
218
326
|
|
|
219
|
-
|
|
327
|
+
def test_str(self):
|
|
328
|
+
self.assertIn(self.esi._ua_appname, str(self.esi))
|
|
329
|
+
self.assertIn(self.esi._ua_version, str(self.esi))
|
|
220
330
|
|
|
221
331
|
def test_compatibilitydate_date_to_string(self):
|
|
222
332
|
testdate_1 = date(2024, 1, 1)
|
|
@@ -227,9 +337,38 @@ class TestOpenapiClientProvider(TestCase):
|
|
|
227
337
|
|
|
228
338
|
@patch.object(httpx.Client, "send")
|
|
229
339
|
def test_ua(self, send: MagicMock):
|
|
340
|
+
send.return_value = httpx.Response(
|
|
341
|
+
200,
|
|
342
|
+
json={
|
|
343
|
+
"players": 1234,
|
|
344
|
+
"server_version": "1234",
|
|
345
|
+
"start_time": "2029-09-19T11:02:08Z"
|
|
346
|
+
},
|
|
347
|
+
request=httpx.Request("GET", "test"),
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
status = self.esi.client.Status.GetStatus().result()
|
|
351
|
+
call_args, call_kwargs = send.call_args
|
|
352
|
+
|
|
353
|
+
expected_app_name = "TestsApp"
|
|
354
|
+
expected_title = 'DjangoEsi'
|
|
355
|
+
|
|
356
|
+
self.assertEqual(
|
|
357
|
+
call_args[0].headers["user-agent"],
|
|
358
|
+
(
|
|
359
|
+
f"{expected_app_name}/{self.app_ver} "
|
|
360
|
+
f"({app_settings.ESI_USER_CONTACT_EMAIL}{f'; +{self.app_url})'} "
|
|
361
|
+
f"{expected_title}/{__version__} (+{__url__})"
|
|
362
|
+
)
|
|
363
|
+
)
|
|
364
|
+
self.assertEqual(status.players, 1234)
|
|
365
|
+
|
|
366
|
+
@patch(MODULE_PATH_PLUGINS + '.settings.DEBUG', True)
|
|
367
|
+
def test_no_tag_no_op_debug(self):
|
|
230
368
|
app_name = "TestsApp"
|
|
231
369
|
app_ver = "1.2.3"
|
|
232
370
|
app_url = "https://tests.pass"
|
|
371
|
+
|
|
233
372
|
esi = ESIClientProvider(
|
|
234
373
|
ua_appname=app_name,
|
|
235
374
|
ua_url=app_url,
|
|
@@ -237,6 +376,87 @@ class TestOpenapiClientProvider(TestCase):
|
|
|
237
376
|
compatibility_date="2020-01-01",
|
|
238
377
|
spec_file=SPEC_PATH
|
|
239
378
|
)
|
|
379
|
+
self.assertIsNotNone(esi.client.Status)
|
|
380
|
+
self.assertIsNotNone(esi.client.Status.GetStatus)
|
|
381
|
+
|
|
382
|
+
@patch(MODULE_PATH_PLUGINS + '.settings.DEBUG', True)
|
|
383
|
+
def test_tag_no_op_debug(self):
|
|
384
|
+
app_name = "TestsApp"
|
|
385
|
+
app_ver = "1.2.3"
|
|
386
|
+
app_url = "https://tests.pass"
|
|
387
|
+
|
|
388
|
+
esi = ESIClientProvider(
|
|
389
|
+
ua_appname=app_name,
|
|
390
|
+
ua_url=app_url,
|
|
391
|
+
ua_version=app_ver,
|
|
392
|
+
compatibility_date="2020-01-01",
|
|
393
|
+
tags=["Status"],
|
|
394
|
+
spec_file=SPEC_PATH
|
|
395
|
+
)
|
|
396
|
+
self.assertIsNotNone(esi.client.Status)
|
|
397
|
+
self.assertIsNotNone(esi.client.Status.GetStatus)
|
|
398
|
+
|
|
399
|
+
@patch(MODULE_PATH_PLUGINS + '.settings.DEBUG', True)
|
|
400
|
+
def test_no_tag_op_debug(self):
|
|
401
|
+
app_name = "TestsApp"
|
|
402
|
+
app_ver = "1.2.3"
|
|
403
|
+
app_url = "https://tests.pass"
|
|
404
|
+
|
|
405
|
+
esi = ESIClientProvider(
|
|
406
|
+
ua_appname=app_name,
|
|
407
|
+
ua_url=app_url,
|
|
408
|
+
ua_version=app_ver,
|
|
409
|
+
compatibility_date="2020-01-01",
|
|
410
|
+
tags=["Status"],
|
|
411
|
+
spec_file=SPEC_PATH
|
|
412
|
+
)
|
|
413
|
+
self.assertIsNotNone(esi.client.Status)
|
|
414
|
+
self.assertIsNotNone(esi.client.Status.GetStatus)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
@patch(MODULE_PATH_PLUGINS + '.settings.DEBUG', False)
|
|
418
|
+
def test_no_tag_no_op_no_debug(self):
|
|
419
|
+
app_name = "TestsApp"
|
|
420
|
+
app_ver = "1.2.3"
|
|
421
|
+
app_url = "https://tests.pass"
|
|
422
|
+
|
|
423
|
+
with self.assertRaises(AttributeError):
|
|
424
|
+
esi = ESIClientProvider(
|
|
425
|
+
ua_appname=app_name,
|
|
426
|
+
ua_url=app_url,
|
|
427
|
+
ua_version=app_ver,
|
|
428
|
+
compatibility_date="2020-01-01",
|
|
429
|
+
spec_file=SPEC_PATH
|
|
430
|
+
)
|
|
431
|
+
esi.client
|
|
432
|
+
|
|
433
|
+
@patch.object(httpx.Client, "send")
|
|
434
|
+
def test_no_bucket(self, send: MagicMock):
|
|
435
|
+
self.esi = ESIClientProvider(
|
|
436
|
+
ua_appname=self.app_name,
|
|
437
|
+
ua_url=self.app_url,
|
|
438
|
+
ua_version=self.app_ver,
|
|
439
|
+
compatibility_date="2020-01-01",
|
|
440
|
+
tags=["Universe"],
|
|
441
|
+
spec_file=SPEC_PATH
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
send.return_value = httpx.Response(
|
|
445
|
+
200,
|
|
446
|
+
json=[1,2,3,4],
|
|
447
|
+
request=httpx.Request("GET", "test"),
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
types = self.esi.client.Universe.GetUniverseTypes().result()
|
|
451
|
+
self.assertEqual(len(types), 4)
|
|
452
|
+
|
|
453
|
+
@patch.object(httpx.Client, "send")
|
|
454
|
+
def test_etag_hit_cached(self, send: MagicMock):
|
|
455
|
+
etag = "'123456789abcdef123456789abcdef'"
|
|
456
|
+
|
|
457
|
+
expires = (
|
|
458
|
+
timezone.now() + timedelta(minutes=5)
|
|
459
|
+
).strftime('%a, %d %b %Y %H:%M:%S %Z')
|
|
240
460
|
|
|
241
461
|
send.return_value = httpx.Response(
|
|
242
462
|
200,
|
|
@@ -245,17 +465,291 @@ class TestOpenapiClientProvider(TestCase):
|
|
|
245
465
|
"server_version": "1234",
|
|
246
466
|
"start_time": "2029-09-19T11:02:08Z"
|
|
247
467
|
},
|
|
248
|
-
|
|
468
|
+
headers={
|
|
469
|
+
"etag": etag,
|
|
470
|
+
"expires": expires
|
|
471
|
+
},
|
|
472
|
+
request=httpx.Request(
|
|
473
|
+
"GET",
|
|
474
|
+
"test",
|
|
475
|
+
),
|
|
249
476
|
)
|
|
250
477
|
|
|
251
|
-
|
|
252
|
-
|
|
478
|
+
self.esi.client.Status.GetStatus().result()
|
|
479
|
+
|
|
480
|
+
with self.assertRaises(HTTPNotModified):
|
|
481
|
+
self.esi.client.Status.GetStatus().result()
|
|
482
|
+
|
|
483
|
+
@patch.object(httpx.Client, "send")
|
|
484
|
+
def test_etag_not_hit_cached(self, send: MagicMock):
|
|
485
|
+
etag = "'123456789abcdef123456789abcdef'"
|
|
486
|
+
|
|
487
|
+
expires = (
|
|
488
|
+
timezone.now() + timedelta(minutes=5)
|
|
489
|
+
).strftime('%a, %d %b %Y %H:%M:%S %Z')
|
|
490
|
+
|
|
491
|
+
send.return_value = httpx.Response(
|
|
492
|
+
200,
|
|
493
|
+
json={
|
|
494
|
+
"players": 1234,
|
|
495
|
+
"server_version": "1234",
|
|
496
|
+
"start_time": "2029-09-19T11:02:08Z"
|
|
497
|
+
},
|
|
498
|
+
headers={
|
|
499
|
+
"etag": etag,
|
|
500
|
+
"expires": expires
|
|
501
|
+
},
|
|
502
|
+
request=httpx.Request(
|
|
503
|
+
"GET",
|
|
504
|
+
"test",
|
|
505
|
+
),
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
self.esi.client.Status.GetStatus().result()
|
|
509
|
+
|
|
510
|
+
result = self.esi.client.Status.GetStatus().result(use_etag=False)
|
|
511
|
+
self.assertEqual(result.players, 1234)
|
|
512
|
+
|
|
513
|
+
@patch.object(httpx.Client, "send")
|
|
514
|
+
def test_force_refresh(self, send: MagicMock):
|
|
515
|
+
etag = "'123456789abcdef123456789abcdef'"
|
|
516
|
+
|
|
517
|
+
expires = (
|
|
518
|
+
timezone.now() + timedelta(minutes=5)
|
|
519
|
+
).strftime('%a, %d %b %Y %H:%M:%S %Z')
|
|
520
|
+
|
|
521
|
+
send.return_value = httpx.Response(
|
|
522
|
+
200,
|
|
523
|
+
json={
|
|
524
|
+
"players": 1234,
|
|
525
|
+
"server_version": "1234",
|
|
526
|
+
"start_time": "2029-09-19T11:02:08Z"
|
|
527
|
+
},
|
|
528
|
+
headers={
|
|
529
|
+
"etag": etag,
|
|
530
|
+
"expires": expires
|
|
531
|
+
},
|
|
532
|
+
request=httpx.Request(
|
|
533
|
+
"GET",
|
|
534
|
+
"test",
|
|
535
|
+
),
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
self.esi.client.Status.GetStatus().result()
|
|
539
|
+
|
|
540
|
+
result = self.esi.client.Status.GetStatus().result(force_refresh=True)
|
|
541
|
+
self.assertEqual(result.players, 1234)
|
|
542
|
+
self.assertEqual(send.call_count, 2)
|
|
543
|
+
|
|
544
|
+
@patch.object(httpx.Client, "send")
|
|
545
|
+
def test_404(self, send: MagicMock):
|
|
546
|
+
self.esi = ESIClientProvider(
|
|
547
|
+
ua_appname=self.app_name,
|
|
548
|
+
ua_url=self.app_url,
|
|
549
|
+
ua_version=self.app_ver,
|
|
550
|
+
compatibility_date="2020-01-01",
|
|
551
|
+
tags=["Universe"],
|
|
552
|
+
spec_file=SPEC_PATH
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
send.return_value = httpx.Response(
|
|
556
|
+
404,
|
|
557
|
+
json={
|
|
558
|
+
"error": "error"
|
|
559
|
+
},
|
|
560
|
+
headers={
|
|
561
|
+
"X-RateLimit-Reset": "15",
|
|
562
|
+
"X-RateLimit-Remaining": "0"
|
|
563
|
+
},
|
|
564
|
+
request=httpx.Request(
|
|
565
|
+
"GET",
|
|
566
|
+
"/universe/types"
|
|
567
|
+
),
|
|
568
|
+
)
|
|
569
|
+
|
|
570
|
+
with self.assertRaises(HTTPClientError):
|
|
571
|
+
self.esi.client.Universe.GetUniverseTypes().result()
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
@patch.object(httpx.Client, "send")
|
|
575
|
+
def test_420(self, send: MagicMock):
|
|
576
|
+
self.esi = ESIClientProvider(
|
|
577
|
+
ua_appname=self.app_name,
|
|
578
|
+
ua_url=self.app_url,
|
|
579
|
+
ua_version=self.app_ver,
|
|
580
|
+
compatibility_date="2020-01-01",
|
|
581
|
+
tags=["Universe"],
|
|
582
|
+
spec_file=SPEC_PATH
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
send.return_value = httpx.Response(
|
|
586
|
+
420,
|
|
587
|
+
json={
|
|
588
|
+
"error": "error"
|
|
589
|
+
},
|
|
590
|
+
headers={
|
|
591
|
+
"X-RateLimit-Reset": "15",
|
|
592
|
+
"X-RateLimit-Remaining": "0"
|
|
593
|
+
},
|
|
594
|
+
request=httpx.Request(
|
|
595
|
+
"GET",
|
|
596
|
+
"/universe/types"
|
|
597
|
+
),
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
with self.assertRaises(ESIErrorLimitException):
|
|
601
|
+
self.esi.client.Universe.GetUniverseTypes().result()
|
|
602
|
+
|
|
603
|
+
self.assertGreater(cache.get("esi_error_limit_reset"), 10)
|
|
604
|
+
|
|
605
|
+
@patch.object(httpx.Client, "send")
|
|
606
|
+
def test_420_past(self, send: MagicMock):
|
|
607
|
+
self.esi = ESIClientProvider(
|
|
608
|
+
ua_appname=self.app_name,
|
|
609
|
+
ua_url=self.app_url,
|
|
610
|
+
ua_version=self.app_ver,
|
|
611
|
+
compatibility_date="2020-01-01",
|
|
612
|
+
tags=["Universe"],
|
|
613
|
+
spec_file=SPEC_PATH
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
send.return_value = httpx.Response(
|
|
617
|
+
420,
|
|
618
|
+
json={
|
|
619
|
+
"error": "error"
|
|
620
|
+
},
|
|
621
|
+
headers={
|
|
622
|
+
"X-RateLimit-Remaining": "0"
|
|
623
|
+
},
|
|
624
|
+
request=httpx.Request(
|
|
625
|
+
"GET",
|
|
626
|
+
"/universe/types"
|
|
627
|
+
),
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
with self.assertRaises(ESIErrorLimitException):
|
|
631
|
+
self.esi.client.Universe.GetUniverseTypes().result()
|
|
632
|
+
|
|
633
|
+
self.assertIsNone(cache.get("esi_error_limit_reset"))
|
|
634
|
+
|
|
635
|
+
@patch.object(httpx.Client, "send")
|
|
636
|
+
def test_rate_bucket(self, send: MagicMock):
|
|
637
|
+
send.return_value = httpx.Response(
|
|
638
|
+
200,
|
|
639
|
+
json={
|
|
640
|
+
"players": 1234,
|
|
641
|
+
"server_version": "1234",
|
|
642
|
+
"start_time": "2029-09-19T11:02:08Z"
|
|
643
|
+
},
|
|
644
|
+
headers={
|
|
645
|
+
"x-ratelimit-group": "status",
|
|
646
|
+
"x-ratelimit-used": "2",
|
|
647
|
+
"x-ratelimit-remaining": "598",
|
|
648
|
+
"x-ratelimit-limit": "600/15m",
|
|
649
|
+
},
|
|
650
|
+
request=httpx.Request(
|
|
651
|
+
"GET",
|
|
652
|
+
"/status"
|
|
653
|
+
),
|
|
654
|
+
)
|
|
655
|
+
self.esi.client.Status.GetStatus().result()
|
|
253
656
|
self.assertEqual(
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
f"{app_name}/{app_ver} "
|
|
257
|
-
f"({app_settings.ESI_USER_CONTACT_EMAIL}{f'; +{app_url})'} "
|
|
258
|
-
f"{__title__}/{__version__} (+{__url__})"
|
|
259
|
-
)
|
|
657
|
+
ESIRateLimits.get_bucket(self.esi.client.Status.GetStatus().bucket),
|
|
658
|
+
598
|
|
260
659
|
)
|
|
261
|
-
|
|
660
|
+
|
|
661
|
+
@patch.object(httpx.Client, "send")
|
|
662
|
+
def test_server_error(self, send: MagicMock):
|
|
663
|
+
send.return_value = httpx.Response(
|
|
664
|
+
520,
|
|
665
|
+
json={
|
|
666
|
+
"error": "error"
|
|
667
|
+
},
|
|
668
|
+
headers={
|
|
669
|
+
"x-ratelimit-group": "status",
|
|
670
|
+
"x-ratelimit-used": "5",
|
|
671
|
+
"x-ratelimit-remaining": "595",
|
|
672
|
+
"x-ratelimit-limit": "600/15m",
|
|
673
|
+
},
|
|
674
|
+
request=httpx.Request(
|
|
675
|
+
"GET",
|
|
676
|
+
"/status"
|
|
677
|
+
),
|
|
678
|
+
)
|
|
679
|
+
with self.assertRaises(HTTPServerError):
|
|
680
|
+
self.esi.client.Status.GetStatus().result()
|
|
681
|
+
|
|
682
|
+
def test_minified_op_not_found(self):
|
|
683
|
+
with self.assertRaises(AttributeError):
|
|
684
|
+
self.esi.client.Universe.GetUniverseTypes()
|
|
685
|
+
|
|
686
|
+
def test_minified_op_not_found(self):
|
|
687
|
+
self.esi = ESIClientProvider(
|
|
688
|
+
ua_appname=self.app_name,
|
|
689
|
+
ua_url=self.app_url,
|
|
690
|
+
ua_version=self.app_ver,
|
|
691
|
+
compatibility_date="2020-01-01",
|
|
692
|
+
tags=["Universe"],
|
|
693
|
+
spec_file=SPEC_PATH
|
|
694
|
+
)
|
|
695
|
+
|
|
696
|
+
with self.assertRaises(AttributeError):
|
|
697
|
+
self.esi.client.Universe.GetUniverseAncestries()
|
|
698
|
+
|
|
699
|
+
def test_rate_bucket_found_in_spec(self):
|
|
700
|
+
|
|
701
|
+
op = self.esi.client.Status.GetStatus()
|
|
702
|
+
|
|
703
|
+
self.assertIsNotNone(op.bucket)
|
|
704
|
+
self.assertEqual(op.bucket.limit, 600)
|
|
705
|
+
self.assertEqual(op.bucket.slug, "status")
|
|
706
|
+
self.assertEqual(op.bucket.window, 900)
|
|
707
|
+
|
|
708
|
+
def test_rate_bucket_hit(self):
|
|
709
|
+
op = self.esi.client.Status.GetStatus()
|
|
710
|
+
|
|
711
|
+
ESIRateLimits.set_bucket(op.bucket, 0)
|
|
712
|
+
|
|
713
|
+
with self.assertRaises(ESIBucketLimitException):
|
|
714
|
+
op.result()
|
|
715
|
+
|
|
716
|
+
def test_global_limit_hit(self):
|
|
717
|
+
op = self.esi.client.Status.GetStatus()
|
|
718
|
+
|
|
719
|
+
cache.set("esi_error_limit_reset", 15, 15)
|
|
720
|
+
|
|
721
|
+
with self.assertRaises(ESIErrorLimitException):
|
|
722
|
+
op.result()
|
|
723
|
+
|
|
724
|
+
@patch.object(httpx.Client, "send")
|
|
725
|
+
def test_load_sync(self, send: MagicMock):
|
|
726
|
+
esi = ESIClientProvider(
|
|
727
|
+
ua_appname=self.app_name,
|
|
728
|
+
ua_url=self.app_url,
|
|
729
|
+
ua_version=self.app_ver,
|
|
730
|
+
compatibility_date="2020-01-01",
|
|
731
|
+
tags=["Status"]
|
|
732
|
+
)
|
|
733
|
+
cache.clear()
|
|
734
|
+
expires = (
|
|
735
|
+
timezone.now() + timedelta(minutes=5)
|
|
736
|
+
).strftime('%a, %d %b %Y %H:%M:%S %Z')
|
|
737
|
+
|
|
738
|
+
spec = None
|
|
739
|
+
with open(SPEC_PATH) as f:
|
|
740
|
+
spec = json.load(f)
|
|
741
|
+
|
|
742
|
+
send.return_value = httpx.Response(
|
|
743
|
+
200,
|
|
744
|
+
json=spec,
|
|
745
|
+
headers={
|
|
746
|
+
"expires": expires
|
|
747
|
+
},
|
|
748
|
+
request=httpx.Request(
|
|
749
|
+
"GET",
|
|
750
|
+
"test",
|
|
751
|
+
),
|
|
752
|
+
)
|
|
753
|
+
|
|
754
|
+
esi.client
|
|
755
|
+
self.assertIsNotNone(esi.client.Status)
|
|
File without changes
|
|
File without changes
|