19
19
import gzip
20
20
import io
21
21
import json
22
+ import re
22
23
import ssl
23
24
import warnings
24
25
from platform import python_version
30
31
31
32
from elasticsearch import AIOHttpConnection , AsyncElasticsearch , __versionstr__
32
33
from elasticsearch .compat import reraise_exceptions
33
- from elasticsearch .exceptions import ConnectionError
34
+ from elasticsearch .exceptions import ConnectionError , NotFoundError
34
35
35
36
pytestmark = pytest .mark .asyncio
36
37
@@ -41,7 +42,9 @@ def gzip_decompress(data):
41
42
42
43
43
44
class TestAIOHttpConnection :
44
- async def _get_mock_connection (self , connection_params = {}, response_body = b"{}" ):
45
+ async def _get_mock_connection (
46
+ self , connection_params = {}, status_code = 200 , response_body = b"{}"
47
+ ):
45
48
con = AIOHttpConnection (** connection_params )
46
49
await con ._create_aiohttp_session ()
47
50
@@ -61,7 +64,7 @@ async def read(self):
61
64
62
65
dummy_response = DummyResponse ()
63
66
dummy_response .headers = CIMultiDict ()
64
- dummy_response .status = 200
67
+ dummy_response .status = status_code
65
68
_dummy_request .call_args = (args , kwargs )
66
69
return dummy_response
67
70
@@ -313,6 +316,91 @@ async def test_uncompressed_body_logged(self, logger):
313
316
assert '> {"example": "body"}' == req [0 ][0 ] % req [0 ][1 :]
314
317
assert "< {}" == resp [0 ][0 ] % resp [0 ][1 :]
315
318
319
+ @patch ("elasticsearch.connection.base.logger" )
320
+ async def test_full_url_logged (self , logger ):
321
+ conn = await self ._get_mock_connection ()
322
+ await conn .perform_request (
323
+ "GET" , "/" , params = {"key" : "val" }, body = b'{"example": "body"}'
324
+ )
325
+
326
+ assert logger .info .call_count == 1
327
+ assert (
328
+ logger .info .call_args_list [0 ][0 ][0 ] % logger .info .call_args_list [0 ][0 ][1 :]
329
+ == "GET http://localhost:9200/?key=val [status:200 request:0.000s]"
330
+ )
331
+
332
+ conn = await self ._get_mock_connection (status_code = 404 )
333
+ with pytest .raises (NotFoundError ):
334
+ await conn .perform_request (
335
+ "GET" , "/" , params = {"key" : "val" }, body = b'{"example": "body"}'
336
+ )
337
+
338
+ assert logger .warning .call_count == 1
339
+ assert (
340
+ logger .warning .call_args_list [0 ][0 ][0 ]
341
+ % logger .warning .call_args_list [0 ][0 ][1 :]
342
+ == "GET http://localhost:9200/?key=val [status:404 request:0.000s]"
343
+ )
344
+
345
+ @patch ("elasticsearch.connection.base.tracer" )
346
+ @patch ("elasticsearch.connection.base.logger" )
347
+ async def test_failed_request_logs_and_traces (self , logger , tracer ):
348
+ conn = await self ._get_mock_connection (
349
+ response_body = b'{"answer": 42}' , status_code = 404
350
+ )
351
+ with pytest .raises (NotFoundError ):
352
+ await conn .perform_request ("GET" , "/" , params = {"param" : 42 }, body = b"{}" )
353
+
354
+ # trace request
355
+ assert 1 == tracer .info .call_count
356
+ # trace response
357
+ assert 1 == tracer .debug .call_count
358
+ # log url and duration
359
+ assert 1 == logger .warning .call_count
360
+ assert re .match (
361
+ r"^GET http://localhost:9200/\?param=42 \[status:404 request:0.[0-9]{3}s\]" ,
362
+ logger .warning .call_args [0 ][0 ] % logger .warning .call_args [0 ][1 :],
363
+ )
364
+
365
+ @patch ("elasticsearch.connection.base.tracer" )
366
+ @patch ("elasticsearch.connection.base.logger" )
367
+ async def test_success_logs_and_traces (self , logger , tracer ):
368
+ conn = await self ._get_mock_connection (
369
+ response_body = b"""{"answer": "that's it!"}"""
370
+ )
371
+ await conn .perform_request (
372
+ "GET" ,
373
+ "/" ,
374
+ {"param" : 42 },
375
+ """{"question": "what's that?"}""" .encode ("utf-8" ),
376
+ )
377
+
378
+ # trace request
379
+ assert 1 == tracer .info .call_count
380
+ assert (
381
+ """curl -H 'Content-Type: application/json' -XGET 'http://localhost:9200/?pretty¶m=42' -d '{\n "question": "what\\ u0027s that?"\n }'"""
382
+ == tracer .info .call_args [0 ][0 ] % tracer .info .call_args [0 ][1 :]
383
+ )
384
+ # trace response
385
+ assert 1 == tracer .debug .call_count
386
+ assert re .match (
387
+ r'#\[200\] \(0.[0-9]{3}s\)\n#{\n# "answer": "that\\u0027s it!"\n#}' ,
388
+ tracer .debug .call_args [0 ][0 ] % tracer .debug .call_args [0 ][1 :],
389
+ )
390
+
391
+ # log url and duration
392
+ assert 1 == logger .info .call_count
393
+ assert re .match (
394
+ r"GET http://localhost:9200/\?param=42 \[status:200 request:0.[0-9]{3}s\]" ,
395
+ logger .info .call_args [0 ][0 ] % logger .info .call_args [0 ][1 :],
396
+ )
397
+
398
+ # log request body and response
399
+ assert 2 == logger .debug .call_count
400
+ req , resp = logger .debug .call_args_list
401
+ assert '> {"question": "what\' s that?"}' == req [0 ][0 ] % req [0 ][1 :]
402
+ assert '< {"answer": "that\' s it!"}' == resp [0 ][0 ] % resp [0 ][1 :]
403
+
316
404
async def test_surrogatepass_into_bytes (self ):
317
405
buf = b"\xe4 \xbd \xa0 \xe5 \xa5 \xbd \xed \xa9 \xaa "
318
406
con = await self ._get_mock_connection (response_body = buf )
0 commit comments