import http.client as httplib from urllib.parse import urlparse import pytest from aws_xray_sdk.core import patch, xray_recorder from aws_xray_sdk.core.context import Context from aws_xray_sdk.ext.util import get_hostname, strip_url # httpbin.org is created by the same author of requests to make testing http easy. BASE_URL = 'httpbin.org' @pytest.fixture(autouse=True) def construct_ctx(): """ Clean up context storage on each test run and begin a segment so that later subsegment can be attached. After each test run it cleans up context storage again. """ from aws_xray_sdk.ext.httplib import reset_ignored, unpatch patch(('httplib',)) xray_recorder.configure(service='test', sampling=False, context=Context()) xray_recorder.clear_trace_entities() xray_recorder.begin_segment('name') yield xray_recorder.clear_trace_entities() unpatch() reset_ignored() def _do_req(url, method='GET', use_https=True): parts = urlparse(url) host, _, port = parts.netloc.partition(':') if port == '': port = None if use_https: conn = httplib.HTTPSConnection(parts.netloc, port) else: conn = httplib.HTTPConnection(parts.netloc, port) path = '{}?{}'.format(parts.path, parts.query) if parts.query else parts.path conn.request(method, path) resp = conn.getresponse() def test_ok(): status_code = 200 url = 'https://{}/status/{}?foo=bar&baz=foo'.format(BASE_URL, status_code) _do_req(url) subsegment = xray_recorder.current_segment().subsegments[1] assert subsegment.name == get_hostname(url) http_meta = subsegment.http assert http_meta['request']['url'] == strip_url(url) assert http_meta['request']['method'].upper() == 'GET' assert http_meta['response']['status'] == status_code def test_error(): status_code = 400 url = 'https://{}/status/{}'.format(BASE_URL, status_code) _do_req(url, 'POST') subsegment = xray_recorder.current_segment().subsegments[1] assert subsegment.name == get_hostname(url) assert subsegment.error http_meta = subsegment.http assert http_meta['request']['url'] == strip_url(url) assert http_meta['request']['method'].upper() == 'POST' assert http_meta['response']['status'] == status_code def test_throttle(): status_code = 429 url = 'https://{}/status/{}'.format(BASE_URL, status_code) _do_req(url, 'HEAD') subsegment = xray_recorder.current_segment().subsegments[1] assert subsegment.name == get_hostname(url) assert subsegment.error assert subsegment.throttle http_meta = subsegment.http assert http_meta['request']['url'] == strip_url(url) assert http_meta['request']['method'].upper() == 'HEAD' assert http_meta['response']['status'] == status_code def test_fault(): status_code = 500 url = 'https://{}/status/{}'.format(BASE_URL, status_code) _do_req(url, 'PUT') subsegment = xray_recorder.current_segment().subsegments[1] assert subsegment.name == get_hostname(url) assert subsegment.fault http_meta = subsegment.http assert http_meta['request']['url'] == strip_url(url) assert http_meta['request']['method'].upper() == 'PUT' assert http_meta['response']['status'] == status_code def test_invalid_url(): try: _do_req('http://doesnt.exist') except Exception: # prevent uncatch exception from breaking test run pass subsegment = xray_recorder.current_segment().subsegments[0] assert subsegment.fault exception = subsegment.cause['exceptions'][0] assert exception.type == 'gaierror' def test_correct_identify_http(): status_code = 200 url = 'http://{}/status/{}?foo=bar&baz=foo'.format(BASE_URL, status_code) _do_req(url, use_https=False) subsegment = xray_recorder.current_segment().subsegments[0] assert subsegment.name == get_hostname(url) http_meta = subsegment.http assert http_meta['request']['url'].split(":")[0] == 'http' def test_correct_identify_https(): status_code = 200 url = 'https://{}/status/{}?foo=bar&baz=foo'.format(BASE_URL, status_code) _do_req(url, use_https=True) subsegment = xray_recorder.current_segment().subsegments[0] assert subsegment.name == get_hostname(url) https_meta = subsegment.http assert https_meta['request']['url'].split(":")[0] == 'https' def test_ignore_url(): from aws_xray_sdk.ext.httplib import add_ignored path = '/status/200' url = 'https://{}{}'.format(BASE_URL, path) add_ignored(urls=[path]) _do_req(url, use_https=True) assert len(xray_recorder.current_segment().subsegments) == 0 def test_ignore_hostname(): from aws_xray_sdk.ext.httplib import add_ignored path = '/status/200' url = 'https://{}{}'.format(BASE_URL, path) add_ignored(hostname=BASE_URL) _do_req(url, use_https=True) assert len(xray_recorder.current_segment().subsegments) == 0 def test_ignore_hostname_glob(): from aws_xray_sdk.ext.httplib import add_ignored path = '/status/200' url = 'https://{}{}'.format(BASE_URL, path) add_ignored(hostname='http*.org') _do_req(url, use_https=True) assert len(xray_recorder.current_segment().subsegments) == 0 class CustomHttpsConnection(httplib.HTTPSConnection): pass def test_ignore_subclass(): from aws_xray_sdk.ext.httplib import add_ignored path = '/status/200' subclass = 'tests.ext.httplib.test_httplib.CustomHttpsConnection' add_ignored(subclass=subclass) conn = CustomHttpsConnection(BASE_URL) conn.request('GET', path) conn.getresponse() assert len(xray_recorder.current_segment().subsegments) == 0 def test_ignore_multiple_match(): from aws_xray_sdk.ext.httplib import add_ignored path = '/status/200' subclass = 'tests.ext.httplib.test_httplib.CustomHttpsConnection' add_ignored(subclass=subclass, hostname=BASE_URL) conn = CustomHttpsConnection(BASE_URL) conn.request('GET', path) conn.getresponse() assert len(xray_recorder.current_segment().subsegments) == 0 def test_ignore_multiple_no_match(): from aws_xray_sdk.ext.httplib import add_ignored path = '/status/200' subclass = 'tests.ext.httplib.test_httplib.CustomHttpsConnection' add_ignored(subclass=subclass, hostname='fake.host') conn = CustomHttpsConnection(BASE_URL) conn.request('GET', path) conn.getresponse() assert len(xray_recorder.current_segment().subsegments) > 0