def test_flush_connection_timeout(endpoint_test_timeout_server): payload = mock.Mock() payload.get_payload.return_value = "foobar" payload.length = 12 api = API(_HOST, _TIMEOUT_PORT) response = api._flush(payload) assert isinstance(response, socket.timeout)
class TestRateByService(TestCase): """ Check we get feedback from the agent and we're able to process it. """ def setUp(self): """ Create a tracer without workers, while spying the ``send()`` method """ # create a new API object to test the transport using synchronous calls self.tracer = get_dummy_tracer() self.api_json = API('localhost', 8126, encoder=JSONEncoder()) self.api_msgpack = API('localhost', 8126, encoder=MsgpackEncoder()) def test_send_single_trace(self): # register a single trace with a span and send them to the trace agent self.tracer.trace('client.testing').finish() trace = self.tracer.writer.pop() traces = [trace] # [TODO:christian] when CI has an agent that is able to process the v0.4 # endpoint, add a check to: # - make sure the output is a valid JSON # - make sure the priority sampler (if enabled) is updated # test JSON encoder response = self.api_json.send_traces(traces) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_traces(traces) ok_(response) eq_(response.status, 200)
def test_flush_connection_uds(endpoint_uds_server): payload = mock.Mock() payload.get_payload.return_value = "foobar" payload.length = 12 api = API(_HOST, 2019, uds_path=endpoint_uds_server.server_address) response = api._flush(payload) assert response.status == 200
def setUp(self): """ Create a tracer without workers, while spying the ``send()`` method """ # create a new API object to test the transport using synchronous calls self.tracer = get_dummy_tracer() self.api_json = API('localhost', 8126, encoder=JSONEncoder()) self.api_msgpack = API('localhost', 8126, encoder=MsgpackEncoder())
def setUp(self): """ Create a tracer without workers, while spying the ``send()`` method """ # create a new API object to test the transport using synchronous calls self.tracer = get_dummy_tracer() self.api_json = API('localhost', 7777, encoder=JSONEncoder()) self.api_msgpack = API('localhost', 7777, encoder=MsgpackEncoder())
def test_https(): conn = mock.MagicMock(spec=httplib.HTTPSConnection) api = API('localhost', 8126, https=True) with mock.patch('ddtrace.compat.httplib.HTTPSConnection') as HTTPSConnection: HTTPSConnection.return_value = conn api._put('/test', '<test data>', 1) conn.request.assert_called_once() conn.close.assert_called_once()
def test_flush_connection_reset(endpoint_test_reset_server): payload = mock.Mock() payload.get_payload.return_value = 'foobar' payload.length = 12 api = API(_HOST, _RESET_PORT) response = api._flush(payload) if PY3: assert isinstance(response, (httplib.BadStatusLine, ConnectionResetError)) # noqa: F821 else: assert isinstance(response, httplib.BadStatusLine)
def test_flush_connection_timeout_connect(): payload = mock.Mock() payload.get_payload.return_value = 'foobar' payload.length = 12 api = API(_HOST, 2019) response = api._flush(payload) if PY3: assert isinstance(response, (OSError, ConnectionRefusedError)) # noqa: F821 else: assert isinstance(response, socket.error) assert response.errno in (99, 111)
def setUp(self, get_container_info): """ Create a tracer without workers, while spying the ``send()`` method """ # Mock the container id we use for making requests get_container_info.return_value = CGroupInfo(container_id="test-container-id") # create a new API object to test the transport using synchronous calls self.tracer = get_dummy_tracer() self.api_json = API("localhost", 8126, encoder=JSONEncoder()) self.api_msgpack = API("localhost", 8126, encoder=MsgpackEncoder())
def test_api_container_info(get_container_info): # When we have container information # DEV: `get_container_info` will return a `CGroupInfo` with a `container_id` or `None` info = CGroupInfo(container_id="test-container-id") get_container_info.return_value = info api = API(_HOST, 8126) assert api._container_info is info assert api._headers["Datadog-Container-Id"] == "test-container-id" # When we do not have container information get_container_info.return_value = None api = API(_HOST, 8126) assert api._container_info is None assert "Datadog-Container-Id" not in api._headers
class TestRateByService(TestCase): """ Check we get feedback from the agent and we're able to process it. """ def setUp(self): """ Create a tracer without workers, while spying the ``send()`` method """ # create a new API object to test the transport using synchronous calls self.tracer = get_dummy_tracer() self.api_json = API("localhost", 8126, encoder=JSONEncoder(), priority_sampling=True) self.api_msgpack = API("localhost", 8126, encoder=MsgpackEncoder(), priority_sampling=True) @pytest.mark.skipif(AGENT_VERSION == "testagent", reason="Test agent doesn't yet support rate sampling.") def test_send_single_trace(self): # register a single trace with a span and send them to the trace agent self.tracer.trace("client.testing").finish() trace = self.tracer.writer.pop() traces = [trace] # [TODO:christian] when CI has an agent that is able to process the v0.4 # endpoint, add a check to: # - make sure the output is a valid JSON # - make sure the priority sampler (if enabled) is updated # test JSON encoder responses = self.api_json.send_traces(traces) assert len(responses) == 1 assert responses[0].status == 200 resp = responses[0].get_json() assert isinstance(resp["rate_by_service"]["service:,env:"], numeric_types) # test Msgpack encoder responses = self.api_msgpack.send_traces(traces) assert len(responses) == 1 assert responses[0].status == 200 resp = responses[0].get_json() assert isinstance(resp["rate_by_service"]["service:,env:"], numeric_types)
def test_downgrade_api(self): # make a call to a not existing endpoint, downgrades # the current API to a stable one tracer = get_dummy_tracer() tracer.trace('client.testing').finish() trace = tracer.writer.pop() # the encoder is right but we're targeting an API # endpoint that is not available api = API('localhost', 8126) api._traces = '/v0.0/traces' assert isinstance(api._encoder, MsgpackEncoder) # after the call, we downgrade to a working endpoint response = api.send_traces([trace]) assert response assert response.status == 200 assert isinstance(api._encoder, JSONEncoder)
def test_downgrade_api(self): # make a call to a not existing endpoint, downgrades # the current API to a stable one tracer = get_dummy_tracer() tracer.trace('client.testing').finish() trace = tracer.writer.pop() # the encoder is right but we're targeting an API # endpoint that is not available api = API('localhost', 8126) api._traces = '/v0.0/traces' ok_(isinstance(api._encoder, MsgpackEncoder)) # after the call, we downgrade to a working endpoint response = api.send_traces([trace]) ok_(response) eq_(response.status, 200) ok_(isinstance(api._encoder, JSONEncoder))
class APITests(TestCase): def setUp(self): # DEV: Mock here instead of in tests, before we have patched `httplib.HTTPConnection` self.conn = mock.MagicMock(spec=httplib.HTTPConnection) self.api = API('localhost', 8126) def tearDown(self): del self.api del self.conn @mock.patch('logging.Logger.debug') def test_parse_response_json(self, log): tracer = get_dummy_tracer() tracer.debug_logging = True test_cases = { 'OK': {'js': None, 'log': "please make sure trace-agent is up to date"}, 'OK\n': {'js': None, 'log': "please make sure trace-agent is up to date"}, 'error:unsupported-endpoint': {'js': None, 'log': "unable to load JSON 'error:unsupported-endpoint'"}, 42: {'js': None, 'log': "unable to load JSON '42'"}, # int as key to trigger TypeError '{}': {'js': {}}, '[]': {'js': []}, '{"rate_by_service": {"service:,env:":0.5, "service:mcnulty,env:test":0.9, "service:postgres,env:test":0.6}}': { # noqa 'js': { 'rate_by_service': { 'service:,env:': 0.5, 'service:mcnulty,env:test': 0.9, 'service:postgres,env:test': 0.6, }, }, }, ' [4,2,1] ': {'js': [4, 2, 1]}, } for k, v in iteritems(test_cases): r = ResponseMock(k) js = _parse_response_json(r) eq_(v['js'], js) if 'log' in v: ok_( 1 <= len(log.call_args_list), 'not enough elements in call_args_list: {}'.format( log.call_args_list), ) print(log.call_args_list) args = log.call_args_list[-1][0][0] ok_(v['log'] in args, 'unable to find {} in {}'.format(v['log'], args)) @mock.patch('ddtrace.compat.httplib.HTTPConnection') def test_put_connection_close(self, HTTPConnection): """ When calling API._put we close the HTTPConnection we create """ HTTPConnection.return_value = self.conn with warnings.catch_warnings(record=True) as w: self.api._put('/test', '<test data>', 1) self.assertEqual( len(w), 0, 'Test raised unexpected warnings: {0!r}'.format(w)) self.conn.request.assert_called_once() self.conn.close.assert_called_once() @mock.patch('ddtrace.compat.httplib.HTTPConnection') def test_put_connection_close_exception(self, HTTPConnection): """ When calling API._put raises an exception we close the HTTPConnection we create """ HTTPConnection.return_value = self.conn # Ensure calling `request` raises an exception self.conn.request.side_effect = Exception with warnings.catch_warnings(record=True) as w: with self.assertRaises(Exception): self.api._put('/test', '<test data>', 1) self.assertEqual( len(w), 0, 'Test raised unexpected warnings: {0!r}'.format(w)) self.conn.request.assert_called_once() self.conn.close.assert_called_once()
class TestAPITransport(TestCase): """ Ensures that traces are properly sent to a local agent. These are part of integration tests so real calls are triggered and you have to execute a real trace-agent to let them pass. """ @mock.patch('ddtrace.internal.runtime.container.get_container_info') def setUp(self, get_container_info): """ Create a tracer without workers, while spying the ``send()`` method """ # Mock the container id we use for making requests get_container_info.return_value = CGroupInfo( container_id='test-container-id') # create a new API object to test the transport using synchronous calls self.tracer = get_dummy_tracer() self.api_json = API('localhost', 8126, encoder=JSONEncoder()) self.api_msgpack = API('localhost', 8126, encoder=MsgpackEncoder()) @mock.patch('ddtrace.api.httplib.HTTPConnection') def test_send_presampler_headers(self, mocked_http): # register a single trace with a span and send them to the trace agent self.tracer.trace('client.testing').finish() trace = self.tracer.writer.pop() traces = [trace] # make a call and retrieve the `conn` Mock object self.api_msgpack.send_traces(traces) request_call = mocked_http.return_value.request assert request_call.call_count == 1 # retrieve the headers from the mocked request call expected_headers = { 'Datadog-Container-Id': 'test-container-id', # mocked in setUp() 'Datadog-Meta-Lang': 'python', 'Datadog-Meta-Lang-Interpreter': PYTHON_INTERPRETER, 'Datadog-Meta-Lang-Version': PYTHON_VERSION, 'Datadog-Meta-Tracer-Version': ddtrace.__version__, 'X-Datadog-Trace-Count': '1', 'Content-Type': 'application/msgpack', } params, _ = request_call.call_args_list[0] headers = params[3] assert len(expected_headers) == len(headers) for k, v in expected_headers.items(): assert v == headers[k] @mock.patch('ddtrace.api.httplib.HTTPConnection') def test_send_presampler_headers_not_in_services(self, mocked_http): # register some services and send them to the trace agent services = [{ 'client.service': { 'app': 'django', 'app_type': 'web', }, }] # make a call and retrieve the `conn` Mock object self.api_msgpack.send_services(services) request_call = mocked_http.return_value.request assert request_call.call_count == 0 def _send_traces_and_check(self, traces, nresponses=1): # test JSON encoder responses = self.api_json.send_traces(traces) assert len(responses) == nresponses for response in responses: assert response.status == 200 # test Msgpack encoder responses = self.api_msgpack.send_traces(traces) assert len(responses) == nresponses for response in responses: assert response.status == 200 def test_send_single_trace(self): # register a single trace with a span and send them to the trace agent self.tracer.trace('client.testing').finish() trace = self.tracer.writer.pop() traces = [trace] self._send_traces_and_check(traces) def test_send_many_traces(self): # register a single trace with a span and send them to the trace agent self.tracer.trace('client.testing').finish() trace = self.tracer.writer.pop() # 30k is a right number to have both json and msgpack send 2 payload :) traces = [trace] * 30000 self._send_traces_and_check(traces, 2) def test_send_single_with_wrong_errors(self): # if the error field is set to True, it must be cast as int so # that the agent decoder handles that properly without providing # a decoding error span = self.tracer.trace('client.testing') span.error = True span.finish() trace = self.tracer.writer.pop() traces = [trace] self._send_traces_and_check(traces) def test_send_multiple_traces(self): # register some traces and send them to the trace agent self.tracer.trace('client.testing').finish() trace_1 = self.tracer.writer.pop() self.tracer.trace('client.testing').finish() trace_2 = self.tracer.writer.pop() traces = [trace_1, trace_2] self._send_traces_and_check(traces) def test_send_single_trace_multiple_spans(self): # register some traces and send them to the trace agent with self.tracer.trace('client.testing'): self.tracer.trace('client.testing').finish() trace = self.tracer.writer.pop() traces = [trace] self._send_traces_and_check(traces) def test_send_multiple_traces_multiple_spans(self): # register some traces and send them to the trace agent with self.tracer.trace('client.testing'): self.tracer.trace('client.testing').finish() trace_1 = self.tracer.writer.pop() with self.tracer.trace('client.testing'): self.tracer.trace('client.testing').finish() trace_2 = self.tracer.writer.pop() traces = [trace_1, trace_2] self._send_traces_and_check(traces) def test_send_single_service(self): # register some services and send them to the trace agent services = [{ 'client.service': { 'app': 'django', 'app_type': 'web', }, }] # test JSON encoder response = self.api_json.send_services(services) assert response is None # test Msgpack encoder response = self.api_msgpack.send_services(services) assert response is None def test_send_service_called_multiple_times(self): # register some services and send them to the trace agent services = [{ 'backend': { 'app': 'django', 'app_type': 'web', }, 'database': { 'app': 'postgres', 'app_type': 'db', }, }] # test JSON encoder response = self.api_json.send_services(services) assert response is None # test Msgpack encoder response = self.api_msgpack.send_services(services) assert response is None
def test_api_str(): api = API('localhost', 8126) assert str(api) == 'localhost:8126' api = API('localhost', 8126, '/path/to/uds') assert str(api) == '/path/to/uds'
class TestAPITransport(TestCase): """ Ensures that traces are properly sent to a local agent. These are part of integration tests so real calls are triggered and you have to execute a real trace-agent to let them pass. """ def setUp(self): """ Create a tracer without workers, while spying the ``send()`` method """ # create a new API object to test the transport using synchronous calls self.tracer = get_dummy_tracer() self.api_json = API('localhost', 7777, encoder=JSONEncoder()) self.api_msgpack = API('localhost', 7777, encoder=MsgpackEncoder()) def test_send_single_trace(self): # register a single trace with a span and send them to the trace agent self.tracer.trace('client.testing').finish() trace = self.tracer.writer.pop() traces = [trace] # test JSON encoder response = self.api_json.send_traces(traces) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_traces(traces) ok_(response) eq_(response.status, 200) def test_send_multiple_traces(self): # register some traces and send them to the trace agent self.tracer.trace('client.testing').finish() trace_1 = self.tracer.writer.pop() self.tracer.trace('client.testing').finish() trace_2 = self.tracer.writer.pop() traces = [trace_1, trace_2] # test JSON encoder response = self.api_json.send_traces(traces) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_traces(traces) ok_(response) eq_(response.status, 200) def test_send_single_trace_multiple_spans(self): # register some traces and send them to the trace agent with self.tracer.trace('client.testing'): self.tracer.trace('client.testing').finish() trace = self.tracer.writer.pop() traces = [trace] # test JSON encoder response = self.api_json.send_traces(traces) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_traces(traces) ok_(response) eq_(response.status, 200) def test_send_multiple_traces_multiple_spans(self): # register some traces and send them to the trace agent with self.tracer.trace('client.testing'): self.tracer.trace('client.testing').finish() trace_1 = self.tracer.writer.pop() with self.tracer.trace('client.testing'): self.tracer.trace('client.testing').finish() trace_2 = self.tracer.writer.pop() traces = [trace_1, trace_2] # test JSON encoder response = self.api_json.send_traces(traces) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_traces(traces) ok_(response) eq_(response.status, 200) def test_send_single_service(self): # register some services and send them to the trace agent services = [{ 'client.service': { 'app': 'django', 'app_type': 'web', }, }] # test JSON encoder response = self.api_json.send_services(services) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_services(services) ok_(response) eq_(response.status, 200) def test_send_service_called_multiple_times(self): # register some services and send them to the trace agent services = [{ 'backend': { 'app': 'django', 'app_type': 'web', }, 'database': { 'app': 'postgres', 'app_type': 'db', }, }] # test JSON encoder response = self.api_json.send_services(services) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_services(services) ok_(response) eq_(response.status, 200)
class TestAPITransport(TestCase): """ Ensures that traces are properly sent to a local agent. These are part of integration tests so real calls are triggered and you have to execute a real trace-agent to let them pass. """ @mock.patch("ddtrace.internal.runtime.container.get_container_info") def setUp(self, get_container_info): """ Create a tracer without workers, while spying the ``send()`` method """ # Mock the container id we use for making requests get_container_info.return_value = CGroupInfo( container_id="test-container-id") # create a new API object to test the transport using synchronous calls self.tracer = get_dummy_tracer() self.api_json = API("localhost", 8126, encoder=JSONEncoder()) self.api_msgpack = API("localhost", 8126, encoder=MsgpackEncoder()) @mock.patch("ddtrace.api.httplib.HTTPConnection") def test_send_presampler_headers(self, mocked_http): # register a single trace with a span and send them to the trace agent self.tracer.trace("client.testing").finish() trace = self.tracer.writer.pop() traces = [trace] # make a call and retrieve the `conn` Mock object self.api_msgpack.send_traces(traces) request_call = mocked_http.return_value.request assert request_call.call_count == 1 # retrieve the headers from the mocked request call expected_headers = { "Datadog-Container-Id": "test-container-id", # mocked in setUp() "Datadog-Meta-Lang": "python", "Datadog-Meta-Lang-Interpreter": PYTHON_INTERPRETER, "Datadog-Meta-Lang-Version": PYTHON_VERSION, "Datadog-Meta-Tracer-Version": ddtrace.__version__, "X-Datadog-Trace-Count": "1", "Content-Type": "application/msgpack", } params, _ = request_call.call_args_list[0] headers = params[3] assert expected_headers == headers def _send_traces_and_check(self, traces, nresponses=1): # test JSON encoder responses = self.api_json.send_traces(traces) assert len(responses) == nresponses for response in responses: assert isinstance(response, Exception) or response.status == 200 # test Msgpack encoder responses = self.api_msgpack.send_traces(traces) assert len(responses) == nresponses for response in responses: assert isinstance(response, Exception) or response.status == 200 def test_send_single_trace(self): # register a single trace with a span and send them to the trace agent self.tracer.trace("client.testing").finish() trace = self.tracer.writer.pop() traces = [trace] self._send_traces_and_check(traces) def test_send_many_traces(self): # register a single trace with a span and send them to the trace agent self.tracer.trace("client.testing").finish() trace = self.tracer.writer.pop() # 20k is a right number to have both json and msgpack send 2 payload :) traces = [trace] * 20000 self._send_traces_and_check(traces, 2) def test_send_single_trace_max_payload(self): payload = Payload() # compute number of spans to create to surpass max payload trace = [Span(self.tracer, "child.span")] trace_size = len(payload.encoder.encode_trace(trace)) num_spans = int(math.floor(payload.max_payload_size / trace_size)) # setup logging capture log = logging.getLogger("ddtrace.api") log_handler = MockedLogHandler(level="WARNING") log.addHandler(log_handler) with self.tracer.trace("client.testing"): for n in range(num_spans): self.tracer.trace("child.span").finish() trace = self.tracer.writer.pop() self._send_traces_and_check([trace], 1) logged_warnings = log_handler.messages["warning"] assert len(logged_warnings) == 1 assert "Trace is larger than the max payload size, dropping it" in logged_warnings[ 0] def test_send_multiple_trace_max_payload(self): payload = Payload() # compute number of spans to create to surpass max payload trace = [Span(self.tracer, "child.span")] trace_size = len(payload.encoder.encode_trace(trace)) num_spans = int( math.floor((payload.max_payload_size - trace_size) / trace_size)) # setup logging capture log = logging.getLogger("ddtrace.api") log_handler = MockedLogHandler(level="WARNING") log.addHandler(log_handler) self.tracer.trace("client.testing").finish() traces = [self.tracer.writer.pop()] # create a trace larger than max payload size with self.tracer.trace("client.testing"): for n in range(num_spans): self.tracer.trace("child.span").finish() traces.append(self.tracer.writer.pop()) self._send_traces_and_check(traces, 2) logged_warnings = log_handler.messages["warning"] assert len(logged_warnings) == 1 assert "Trace is too big to fit in a payload, dropping it" in logged_warnings[ 0] def test_send_single_with_wrong_errors(self): # if the error field is set to True, it must be cast as int so # that the agent decoder handles that properly without providing # a decoding error span = self.tracer.trace("client.testing") span.error = True span.finish() trace = self.tracer.writer.pop() traces = [trace] self._send_traces_and_check(traces) def test_send_multiple_traces(self): # register some traces and send them to the trace agent self.tracer.trace("client.testing").finish() trace_1 = self.tracer.writer.pop() self.tracer.trace("client.testing").finish() trace_2 = self.tracer.writer.pop() traces = [trace_1, trace_2] self._send_traces_and_check(traces) def test_send_single_trace_multiple_spans(self): # register some traces and send them to the trace agent with self.tracer.trace("client.testing"): self.tracer.trace("client.testing").finish() trace = self.tracer.writer.pop() traces = [trace] self._send_traces_and_check(traces) def test_send_multiple_traces_multiple_spans(self): # register some traces and send them to the trace agent with self.tracer.trace("client.testing"): self.tracer.trace("client.testing").finish() trace_1 = self.tracer.writer.pop() with self.tracer.trace("client.testing"): self.tracer.trace("client.testing").finish() trace_2 = self.tracer.writer.pop() traces = [trace_1, trace_2] self._send_traces_and_check(traces)
def test_api_str(): api = API("localhost", 8126, https=True) assert str(api) == "https://localhost:8126" api = API("localhost", 8126, "/path/to/uds") assert str(api) == "unix:///path/to/uds"
class TestAPITransport(TestCase): """ Ensures that traces are properly sent to a local agent. These are part of integration tests so real calls are triggered and you have to execute a real trace-agent to let them pass. """ def setUp(self): """ Create a tracer without workers, while spying the ``send()`` method """ # create a new API object to test the transport using synchronous calls self.tracer = get_dummy_tracer() self.api_json = API('localhost', 8126, encoder=JSONEncoder()) self.api_msgpack = API('localhost', 8126, encoder=MsgpackEncoder()) @mock.patch('ddtrace.api.httplib.HTTPConnection') def test_send_presampler_headers(self, mocked_http): # register a single trace with a span and send them to the trace agent self.tracer.trace('client.testing').finish() trace = self.tracer.writer.pop() traces = [trace] # make a call and retrieve the `conn` Mock object response = self.api_msgpack.send_traces(traces) request_call = mocked_http.return_value.request eq_(request_call.call_count, 1) # retrieve the headers from the mocked request call expected_headers = { 'Datadog-Meta-Lang': 'python', 'Datadog-Meta-Lang-Interpreter': PYTHON_INTERPRETER, 'Datadog-Meta-Lang-Version': PYTHON_VERSION, 'Datadog-Meta-Tracer-Version': ddtrace.__version__, 'X-Datadog-Trace-Count': '1', 'Content-Type': 'application/msgpack' } params, _ = request_call.call_args_list[0] headers = params[3] eq_(len(expected_headers), len(headers)) for k, v in expected_headers.items(): eq_(v, headers[k]) @mock.patch('ddtrace.api.httplib.HTTPConnection') def test_send_presampler_headers_not_in_services(self, mocked_http): # register some services and send them to the trace agent services = [{ 'client.service': { 'app': 'django', 'app_type': 'web', }, }] # make a call and retrieve the `conn` Mock object response = self.api_msgpack.send_services(services) request_call = mocked_http.return_value.request eq_(request_call.call_count, 1) # retrieve the headers from the mocked request call expected_headers = { 'Datadog-Meta-Lang': 'python', 'Datadog-Meta-Lang-Interpreter': PYTHON_INTERPRETER, 'Datadog-Meta-Lang-Version': PYTHON_VERSION, 'Datadog-Meta-Tracer-Version': ddtrace.__version__, 'Content-Type': 'application/msgpack' } params, _ = request_call.call_args_list[0] headers = params[3] eq_(len(expected_headers), len(headers)) for k, v in expected_headers.items(): eq_(v, headers[k]) # retrieve the headers from the mocked request call params, _ = request_call.call_args_list[0] headers = params[3] ok_('X-Datadog-Trace-Count' not in headers.keys()) def test_send_single_trace(self): # register a single trace with a span and send them to the trace agent self.tracer.trace('client.testing').finish() trace = self.tracer.writer.pop() traces = [trace] # test JSON encoder response = self.api_json.send_traces(traces) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_traces(traces) ok_(response) eq_(response.status, 200) def test_send_single_with_wrong_errors(self): # if the error field is set to True, it must be cast as int so # that the agent decoder handles that properly without providing # a decoding error span = self.tracer.trace('client.testing') span.error = True span.finish() trace = self.tracer.writer.pop() traces = [trace] # test JSON encoder response = self.api_json.send_traces(traces) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_traces(traces) ok_(response) eq_(response.status, 200) def test_send_multiple_traces(self): # register some traces and send them to the trace agent self.tracer.trace('client.testing').finish() trace_1 = self.tracer.writer.pop() self.tracer.trace('client.testing').finish() trace_2 = self.tracer.writer.pop() traces = [trace_1, trace_2] # test JSON encoder response = self.api_json.send_traces(traces) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_traces(traces) ok_(response) eq_(response.status, 200) def test_send_single_trace_multiple_spans(self): # register some traces and send them to the trace agent with self.tracer.trace('client.testing'): self.tracer.trace('client.testing').finish() trace = self.tracer.writer.pop() traces = [trace] # test JSON encoder response = self.api_json.send_traces(traces) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_traces(traces) ok_(response) eq_(response.status, 200) def test_send_multiple_traces_multiple_spans(self): # register some traces and send them to the trace agent with self.tracer.trace('client.testing'): self.tracer.trace('client.testing').finish() trace_1 = self.tracer.writer.pop() with self.tracer.trace('client.testing'): self.tracer.trace('client.testing').finish() trace_2 = self.tracer.writer.pop() traces = [trace_1, trace_2] # test JSON encoder response = self.api_json.send_traces(traces) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_traces(traces) ok_(response) eq_(response.status, 200) def test_send_single_service(self): # register some services and send them to the trace agent services = [{ 'client.service': { 'app': 'django', 'app_type': 'web', }, }] # test JSON encoder response = self.api_json.send_services(services) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_services(services) ok_(response) eq_(response.status, 200) def test_send_service_called_multiple_times(self): # register some services and send them to the trace agent services = [{ 'backend': { 'app': 'django', 'app_type': 'web', }, 'database': { 'app': 'postgres', 'app_type': 'db', }, }] # test JSON encoder response = self.api_json.send_services(services) ok_(response) eq_(response.status, 200) # test Msgpack encoder response = self.api_msgpack.send_services(services) ok_(response) eq_(response.status, 200)
class APITests(TestCase): def setUp(self): # DEV: Mock here instead of in tests, before we have patched `httplib.HTTPConnection` self.conn = mock.MagicMock(spec=httplib.HTTPConnection) self.api = API("localhost", 8126) def tearDown(self): del self.api del self.conn def test_typecast_port(self): api = API("localhost", u"8126") self.assertEqual(api.port, 8126) @mock.patch("logging.Logger.debug") def test_parse_response_json(self, log): test_cases = { "OK": dict( js=None, log= "Cannot parse Datadog Agent response, please make sure your Datadog Agent is up to date", ), "OK\n": dict( js=None, log= "Cannot parse Datadog Agent response, please make sure your Datadog Agent is up to date", ), "error:unsupported-endpoint": dict( js=None, log= "Unable to parse Datadog Agent JSON response: 'error:unsupported-endpoint'", ), 42: dict( # int as key to trigger TypeError js=None, log="Unable to parse Datadog Agent JSON response: 42", ), "{}": dict(js={}), "[]": dict(js=[]), # Priority sampling "rate_by_service" response ('{"rate_by_service": ' '{"service:,env:":0.5, "service:mcnulty,env:test":0.9, "service:postgres,env:test":0.6}}'): dict(js=dict(rate_by_service={ "service:,env:": 0.5, "service:mcnulty,env:test": 0.9, "service:postgres,env:test": 0.6, }, ), ), " [4,2,1] ": dict(js=[4, 2, 1]), } for k, v in iteritems(test_cases): log.reset_mock() r = Response.from_http_response(ResponseMock(k)) js = r.get_json() assert v["js"] == js if "log" in v: log.assert_called_once() msg = log.call_args[0][0] % log.call_args[0][1:] assert re.match(v["log"], msg), msg @mock.patch("ddtrace.compat.httplib.HTTPConnection") def test_put_connection_close(self, HTTPConnection): """ When calling API._put we close the HTTPConnection we create """ HTTPConnection.return_value = self.conn with warnings.catch_warnings(record=True) as w: self.api._put("/test", "<test data>", 1) self.assertEqual( len(w), 0, "Test raised unexpected warnings: {0!r}".format(w)) self.conn.request.assert_called_once() self.conn.close.assert_called_once() @mock.patch("ddtrace.compat.httplib.HTTPConnection") def test_put_connection_close_exception(self, HTTPConnection): """ When calling API._put raises an exception we close the HTTPConnection we create """ HTTPConnection.return_value = self.conn # Ensure calling `request` raises an exception self.conn.request.side_effect = Exception with warnings.catch_warnings(record=True) as w: with self.assertRaises(Exception): self.api._put("/test", "<test data>", 1) self.assertEqual( len(w), 0, "Test raised unexpected warnings: {0!r}".format(w)) self.conn.request.assert_called_once() self.conn.close.assert_called_once()
def test_typecast_port(self): api = API('localhost', u'8126') self.assertEqual(api.port, 8126)
def setUp(self): # DEV: Mock here instead of in tests, before we have patched `httplib.HTTPConnection` self.conn = mock.MagicMock(spec=httplib.HTTPConnection) self.api = API('localhost', 8126)
class APITests(TestCase): def setUp(self): # DEV: Mock here instead of in tests, before we have patched `httplib.HTTPConnection` self.conn = mock.MagicMock(spec=httplib.HTTPConnection) self.api = API('localhost', 8126) def tearDown(self): del self.api del self.conn def test_typecast_port(self): api = API('localhost', u'8126') self.assertEqual(api.port, 8126) @mock.patch('logging.Logger.debug') def test_parse_response_json(self, log): tracer = get_dummy_tracer() tracer.debug_logging = True test_cases = { 'OK': dict( js=None, log= 'Cannot parse Datadog Agent response, please make sure your Datadog Agent is up to date', ), 'OK\n': dict( js=None, log= 'Cannot parse Datadog Agent response, please make sure your Datadog Agent is up to date', ), 'error:unsupported-endpoint': dict( js=None, log= 'Unable to parse Datadog Agent JSON response: .*? \'error:unsupported-endpoint\'', ), 42: dict( # int as key to trigger TypeError js=None, log='Unable to parse Datadog Agent JSON response: .*? 42', ), '{}': dict(js={}), '[]': dict(js=[]), # Priority sampling "rate_by_service" response ('{"rate_by_service": ' '{"service:,env:":0.5, "service:mcnulty,env:test":0.9, "service:postgres,env:test":0.6}}'): dict(js=dict(rate_by_service={ 'service:,env:': 0.5, 'service:mcnulty,env:test': 0.9, 'service:postgres,env:test': 0.6, }, ), ), ' [4,2,1] ': dict(js=[4, 2, 1]), } for k, v in iteritems(test_cases): log.reset_mock() r = Response.from_http_response(ResponseMock(k)) js = r.get_json() assert v['js'] == js if 'log' in v: log.assert_called_once() msg = log.call_args[0][0] % log.call_args[0][1:] assert re.match(v['log'], msg), msg @mock.patch('ddtrace.compat.httplib.HTTPConnection') def test_put_connection_close(self, HTTPConnection): """ When calling API._put we close the HTTPConnection we create """ HTTPConnection.return_value = self.conn with warnings.catch_warnings(record=True) as w: self.api._put('/test', '<test data>', 1) self.assertEqual( len(w), 0, 'Test raised unexpected warnings: {0!r}'.format(w)) self.conn.request.assert_called_once() self.conn.close.assert_called_once() @mock.patch('ddtrace.compat.httplib.HTTPConnection') def test_put_connection_close_exception(self, HTTPConnection): """ When calling API._put raises an exception we close the HTTPConnection we create """ HTTPConnection.return_value = self.conn # Ensure calling `request` raises an exception self.conn.request.side_effect = Exception with warnings.catch_warnings(record=True) as w: with self.assertRaises(Exception): self.api._put('/test', '<test data>', 1) self.assertEqual( len(w), 0, 'Test raised unexpected warnings: {0!r}'.format(w)) self.conn.request.assert_called_once() self.conn.close.assert_called_once()
def test_api_str(): api = API('localhost', 8126, https=True) assert str(api) == 'https://localhost:8126' api = API('localhost', 8126, '/path/to/uds') assert str(api) == 'unix:///path/to/uds'
def test_typecast_port(self): api = API("localhost", u"8126") self.assertEqual(api.port, 8126)