django-esi 8.0.0b1__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.0b1.dist-info → django_esi-8.0.0b2.dist-info}/METADATA +3 -2
- {django_esi-8.0.0b1.dist-info → django_esi-8.0.0b2.dist-info}/RECORD +46 -45
- esi/__init__.py +1 -1
- esi/aiopenapi3/plugins.py +12 -2
- esi/clients.py +41 -1
- esi/decorators.py +26 -10
- esi/exceptions.py +7 -3
- esi/helpers.py +1 -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 +139 -31
- esi/rate_limiting.py +50 -21
- esi/signals.py +21 -0
- esi/tests/__init__.py +30 -8
- esi/tests/test_decorators.py +61 -1
- esi/tests/test_openapi.json +65 -2
- esi/tests/test_openapi.py +387 -47
- {django_esi-8.0.0b1.dist-info → django_esi-8.0.0b2.dist-info}/WHEEL +0 -0
- {django_esi-8.0.0b1.dist-info → django_esi-8.0.0b2.dist-info}/licenses/LICENSE +0 -0
esi/tests/test_openapi.json
CHANGED
|
@@ -122,7 +122,12 @@
|
|
|
122
122
|
}
|
|
123
123
|
},
|
|
124
124
|
"type": "object"
|
|
125
|
+
},
|
|
126
|
+
"UniverseTypesGet": {
|
|
127
|
+
"items": { "format": "int64", "type": "integer" },
|
|
128
|
+
"type": "array"
|
|
125
129
|
}
|
|
130
|
+
|
|
126
131
|
},
|
|
127
132
|
"securitySchemes": {
|
|
128
133
|
"OAuth2": {
|
|
@@ -217,6 +222,58 @@
|
|
|
217
222
|
},
|
|
218
223
|
"openapi": "3.1.0",
|
|
219
224
|
"paths": {
|
|
225
|
+
"/universe/types": {
|
|
226
|
+
"get": {
|
|
227
|
+
"description": "Get a list of type ids\n\nThis route expires daily at 11:05",
|
|
228
|
+
"operationId": "GetUniverseTypes",
|
|
229
|
+
"parameters": [
|
|
230
|
+
{
|
|
231
|
+
"in": "query",
|
|
232
|
+
"name": "page",
|
|
233
|
+
"schema": {
|
|
234
|
+
"description": "Which page of results to return.",
|
|
235
|
+
"format": "int32",
|
|
236
|
+
"minimum": 1,
|
|
237
|
+
"type": "integer"
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
{ "$ref": "#/components/parameters/AcceptLanguage" },
|
|
241
|
+
{ "$ref": "#/components/parameters/IfNoneMatch" },
|
|
242
|
+
{ "$ref": "#/components/parameters/CompatibilityDate" },
|
|
243
|
+
{ "$ref": "#/components/parameters/Tenant" }
|
|
244
|
+
],
|
|
245
|
+
"responses": {
|
|
246
|
+
"200": {
|
|
247
|
+
"content": {
|
|
248
|
+
"application/json": {
|
|
249
|
+
"schema": { "$ref": "#/components/schemas/UniverseTypesGet" }
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
"description": "OK",
|
|
253
|
+
"headers": {
|
|
254
|
+
"Cache-Control": { "$ref": "#/components/headers/CacheControl" },
|
|
255
|
+
"ETag": { "$ref": "#/components/headers/ETag" },
|
|
256
|
+
"Last-Modified": { "$ref": "#/components/headers/LastModified" },
|
|
257
|
+
"X-Pages": {
|
|
258
|
+
"description": "The total number of pages in the result set.",
|
|
259
|
+
"schema": { "format": "int64", "type": "integer" }
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
"default": {
|
|
264
|
+
"content": {
|
|
265
|
+
"application/json": {
|
|
266
|
+
"schema": { "$ref": "#/components/schemas/Error" }
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
"description": "Error"
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
"summary": "Get types",
|
|
273
|
+
"tags": ["Universe"],
|
|
274
|
+
"x-compatibility-date": "2020-01-01"
|
|
275
|
+
}
|
|
276
|
+
},
|
|
220
277
|
"/status": {
|
|
221
278
|
"get": {
|
|
222
279
|
"description": "EVE Server status",
|
|
@@ -253,12 +310,18 @@
|
|
|
253
310
|
"summary": "Retrieve the uptime and player counts",
|
|
254
311
|
"tags": ["Status"],
|
|
255
312
|
"x-cache-age": 30,
|
|
256
|
-
"x-compatibility-date": "2020-01-01"
|
|
313
|
+
"x-compatibility-date": "2020-01-01",
|
|
314
|
+
"x-rate-limit": {
|
|
315
|
+
"group": "status",
|
|
316
|
+
"max-tokens": 600,
|
|
317
|
+
"window-size": "15m"
|
|
318
|
+
}
|
|
257
319
|
}
|
|
258
320
|
}
|
|
259
321
|
},
|
|
260
322
|
"servers": [{ "url": "https://esi.evetech.net" }],
|
|
261
323
|
"tags": [
|
|
262
|
-
{ "name": "Status" }
|
|
324
|
+
{ "name": "Status" },
|
|
325
|
+
{ "name": "Universe" }
|
|
263
326
|
]
|
|
264
327
|
}
|
esi/tests/test_openapi.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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
|
|
@@ -7,17 +7,21 @@ from datetime import date, timedelta
|
|
|
7
7
|
from esi.openapi_clients import ESIClientProvider
|
|
8
8
|
from django.core.cache import cache
|
|
9
9
|
from django.utils import timezone
|
|
10
|
+
from esi.tests import NoSocketsTestCase
|
|
10
11
|
from httpx import RequestError, HTTPStatusError
|
|
11
|
-
from esi.exceptions import ESIErrorLimitException, HTTPNotModified
|
|
12
|
+
from esi.exceptions import ESIErrorLimitException, HTTPClientError, HTTPNotModified, ESIBucketLimitException, HTTPServerError
|
|
13
|
+
from esi.rate_limiting import ESIRateLimits
|
|
12
14
|
from esi import app_settings
|
|
13
15
|
from esi import __title__, __url__, __version__
|
|
14
16
|
import httpx
|
|
15
17
|
|
|
18
|
+
from . import _generate_token
|
|
16
19
|
from .. import openapi_clients as oc
|
|
17
20
|
|
|
18
21
|
SPEC_PATH = os.path.join(
|
|
19
22
|
os.path.dirname(os.path.abspath(__file__)), "test_openapi.json"
|
|
20
23
|
)
|
|
24
|
+
MODULE_PATH_PLUGINS = 'esi.aiopenapi3.plugins'
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
class TestClientFunctions(TestCase):
|
|
@@ -78,7 +82,7 @@ class BuildUserAgentTests(TestCase):
|
|
|
78
82
|
ua = oc._build_user_agent(self.app_name, self.app_ver, self.app_url)
|
|
79
83
|
|
|
80
84
|
expected_app_name = "TestApp"
|
|
81
|
-
expected_title =
|
|
85
|
+
expected_title = "DjangoEsi"
|
|
82
86
|
|
|
83
87
|
self.assertEqual(
|
|
84
88
|
(
|
|
@@ -100,7 +104,7 @@ class BuildUserAgentTests(TestCase):
|
|
|
100
104
|
ua = oc._build_user_agent("test app", self.app_ver, self.app_url)
|
|
101
105
|
|
|
102
106
|
expected_app_name = "TestApp"
|
|
103
|
-
expected_title =
|
|
107
|
+
expected_title = "DjangoEsi"
|
|
104
108
|
|
|
105
109
|
self.assertEqual(
|
|
106
110
|
(
|
|
@@ -122,7 +126,7 @@ class BuildUserAgentTests(TestCase):
|
|
|
122
126
|
ua = oc._build_user_agent("test-app", self.app_ver, self.app_url)
|
|
123
127
|
|
|
124
128
|
expected_app_name = "TestApp"
|
|
125
|
-
expected_title =
|
|
129
|
+
expected_title = "DjangoEsi"
|
|
126
130
|
|
|
127
131
|
self.assertEqual(
|
|
128
132
|
(
|
|
@@ -137,7 +141,7 @@ class BuildUserAgentTests(TestCase):
|
|
|
137
141
|
ua = oc._build_user_agent(self.app_name, self.app_ver)
|
|
138
142
|
|
|
139
143
|
expected_app_name = "TestApp"
|
|
140
|
-
expected_title =
|
|
144
|
+
expected_title = "DjangoEsi"
|
|
141
145
|
|
|
142
146
|
self.assertEqual(
|
|
143
147
|
(
|
|
@@ -176,6 +180,7 @@ class BaseEsiOperationTests(TestCase):
|
|
|
176
180
|
]
|
|
177
181
|
self.fake_op.tags = ["test"]
|
|
178
182
|
self.fake_op.operationId = "fake_op"
|
|
183
|
+
self.fake_op.extensions = {}
|
|
179
184
|
self.api = MagicMock(app_name="TestApp")
|
|
180
185
|
self.op = oc.BaseEsiOperation(
|
|
181
186
|
("GET", "/fake_op", self.fake_op, {}),
|
|
@@ -246,6 +251,19 @@ class EsiOperationTests(TestCase):
|
|
|
246
251
|
self.op_mock.parameters = []
|
|
247
252
|
self.op_mock.tags = ["tag"]
|
|
248
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
|
+
}
|
|
249
267
|
|
|
250
268
|
self.api_mock = MagicMock()
|
|
251
269
|
self.api_mock.app_name = "TestApp"
|
|
@@ -260,6 +278,16 @@ class EsiOperationTests(TestCase):
|
|
|
260
278
|
self.api_mock
|
|
261
279
|
)
|
|
262
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
|
+
|
|
263
291
|
@patch.object(oc.EsiOperation, "_make_request")
|
|
264
292
|
def test_result_and_results(self, mock_make_request):
|
|
265
293
|
data = {"data": "stuff"}
|
|
@@ -268,8 +296,37 @@ class EsiOperationTests(TestCase):
|
|
|
268
296
|
data_resp = self.op(foo="bar").result()
|
|
269
297
|
self.assertEqual(data, data_resp)
|
|
270
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)
|
|
271
304
|
|
|
272
|
-
|
|
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()
|
|
326
|
+
|
|
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))
|
|
273
330
|
|
|
274
331
|
def test_compatibilitydate_date_to_string(self):
|
|
275
332
|
testdate_1 = date(2024, 1, 1)
|
|
@@ -280,19 +337,6 @@ class TestOpenapiClientProvider(TestCase):
|
|
|
280
337
|
|
|
281
338
|
@patch.object(httpx.Client, "send")
|
|
282
339
|
def test_ua(self, send: MagicMock):
|
|
283
|
-
app_name = "TestsApp"
|
|
284
|
-
app_ver = "1.2.3"
|
|
285
|
-
app_url = "https://tests.pass"
|
|
286
|
-
esi = ESIClientProvider(
|
|
287
|
-
ua_appname=app_name,
|
|
288
|
-
ua_url=app_url,
|
|
289
|
-
ua_version=app_ver,
|
|
290
|
-
compatibility_date="2020-01-01",
|
|
291
|
-
tags=["Status"],
|
|
292
|
-
spec_file=SPEC_PATH
|
|
293
|
-
)
|
|
294
|
-
cache.clear()
|
|
295
|
-
|
|
296
340
|
send.return_value = httpx.Response(
|
|
297
341
|
200,
|
|
298
342
|
json={
|
|
@@ -303,7 +347,7 @@ class TestOpenapiClientProvider(TestCase):
|
|
|
303
347
|
request=httpx.Request("GET", "test"),
|
|
304
348
|
)
|
|
305
349
|
|
|
306
|
-
status = esi.client.Status.GetStatus().result()
|
|
350
|
+
status = self.esi.client.Status.GetStatus().result()
|
|
307
351
|
call_args, call_kwargs = send.call_args
|
|
308
352
|
|
|
309
353
|
expected_app_name = "TestsApp"
|
|
@@ -312,19 +356,35 @@ class TestOpenapiClientProvider(TestCase):
|
|
|
312
356
|
self.assertEqual(
|
|
313
357
|
call_args[0].headers["user-agent"],
|
|
314
358
|
(
|
|
315
|
-
f"{expected_app_name}/{app_ver} "
|
|
316
|
-
f"({app_settings.ESI_USER_CONTACT_EMAIL}{f'; +{app_url})'} "
|
|
359
|
+
f"{expected_app_name}/{self.app_ver} "
|
|
360
|
+
f"({app_settings.ESI_USER_CONTACT_EMAIL}{f'; +{self.app_url})'} "
|
|
317
361
|
f"{expected_title}/{__version__} (+{__url__})"
|
|
318
362
|
)
|
|
319
363
|
)
|
|
320
364
|
self.assertEqual(status.players, 1234)
|
|
321
365
|
|
|
322
|
-
@patch
|
|
323
|
-
def
|
|
366
|
+
@patch(MODULE_PATH_PLUGINS + '.settings.DEBUG', True)
|
|
367
|
+
def test_no_tag_no_op_debug(self):
|
|
324
368
|
app_name = "TestsApp"
|
|
325
369
|
app_ver = "1.2.3"
|
|
326
370
|
app_url = "https://tests.pass"
|
|
327
|
-
|
|
371
|
+
|
|
372
|
+
esi = ESIClientProvider(
|
|
373
|
+
ua_appname=app_name,
|
|
374
|
+
ua_url=app_url,
|
|
375
|
+
ua_version=app_ver,
|
|
376
|
+
compatibility_date="2020-01-01",
|
|
377
|
+
spec_file=SPEC_PATH
|
|
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
|
+
|
|
328
388
|
esi = ESIClientProvider(
|
|
329
389
|
ua_appname=app_name,
|
|
330
390
|
ua_url=app_url,
|
|
@@ -333,7 +393,66 @@ class TestOpenapiClientProvider(TestCase):
|
|
|
333
393
|
tags=["Status"],
|
|
334
394
|
spec_file=SPEC_PATH
|
|
335
395
|
)
|
|
336
|
-
|
|
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'"
|
|
337
456
|
|
|
338
457
|
expires = (
|
|
339
458
|
timezone.now() + timedelta(minutes=5)
|
|
@@ -356,26 +475,15 @@ class TestOpenapiClientProvider(TestCase):
|
|
|
356
475
|
),
|
|
357
476
|
)
|
|
358
477
|
|
|
359
|
-
esi.client.Status.GetStatus().result()
|
|
478
|
+
self.esi.client.Status.GetStatus().result()
|
|
360
479
|
|
|
361
480
|
with self.assertRaises(HTTPNotModified):
|
|
362
|
-
esi.client.Status.GetStatus().result()
|
|
481
|
+
self.esi.client.Status.GetStatus().result()
|
|
363
482
|
|
|
364
483
|
@patch.object(httpx.Client, "send")
|
|
365
|
-
def
|
|
366
|
-
app_name = "TestsApp"
|
|
367
|
-
app_ver = "1.2.3"
|
|
368
|
-
app_url = "https://tests.pass"
|
|
484
|
+
def test_etag_not_hit_cached(self, send: MagicMock):
|
|
369
485
|
etag = "'123456789abcdef123456789abcdef'"
|
|
370
|
-
|
|
371
|
-
ua_appname=app_name,
|
|
372
|
-
ua_url=app_url,
|
|
373
|
-
ua_version=app_ver,
|
|
374
|
-
compatibility_date="2020-01-01",
|
|
375
|
-
tags=["Status"],
|
|
376
|
-
spec_file=SPEC_PATH
|
|
377
|
-
)
|
|
378
|
-
cache.clear()
|
|
486
|
+
|
|
379
487
|
expires = (
|
|
380
488
|
timezone.now() + timedelta(minutes=5)
|
|
381
489
|
).strftime('%a, %d %b %Y %H:%M:%S %Z')
|
|
@@ -396,12 +504,27 @@ class TestOpenapiClientProvider(TestCase):
|
|
|
396
504
|
"test",
|
|
397
505
|
),
|
|
398
506
|
)
|
|
399
|
-
esi.client.Status.GetStatus().result()
|
|
400
507
|
|
|
401
|
-
|
|
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')
|
|
402
520
|
|
|
403
521
|
send.return_value = httpx.Response(
|
|
404
|
-
|
|
522
|
+
200,
|
|
523
|
+
json={
|
|
524
|
+
"players": 1234,
|
|
525
|
+
"server_version": "1234",
|
|
526
|
+
"start_time": "2029-09-19T11:02:08Z"
|
|
527
|
+
},
|
|
405
528
|
headers={
|
|
406
529
|
"etag": etag,
|
|
407
530
|
"expires": expires
|
|
@@ -411,5 +534,222 @@ class TestOpenapiClientProvider(TestCase):
|
|
|
411
534
|
"test",
|
|
412
535
|
),
|
|
413
536
|
)
|
|
414
|
-
|
|
415
|
-
|
|
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()
|
|
656
|
+
self.assertEqual(
|
|
657
|
+
ESIRateLimits.get_bucket(self.esi.client.Status.GetStatus().bucket),
|
|
658
|
+
598
|
|
659
|
+
)
|
|
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
|