Files
2020-04-08 10:39:44 -07:00

220 lines
7.7 KiB
Python

import time
import pytest
import mock
from ddtrace.span import Span
from ddtrace.api import API
from ddtrace.internal.writer import AgentWriter, Q, Empty
from ..base import BaseTestCase
class RemoveAllFilter:
def __init__(self):
self.filtered_traces = 0
def process_trace(self, trace):
self.filtered_traces += 1
return None
class KeepAllFilter:
def __init__(self):
self.filtered_traces = 0
def process_trace(self, trace):
self.filtered_traces += 1
return trace
class AddTagFilter:
def __init__(self, tag_name):
self.tag_name = tag_name
self.filtered_traces = 0
def process_trace(self, trace):
self.filtered_traces += 1
for span in trace:
span.set_tag(self.tag_name, "A value")
return trace
class DummyAPI(API):
def __init__(self):
# Call API.__init__ to setup required properties
super(DummyAPI, self).__init__(hostname="localhost", port=8126)
self.traces = []
def send_traces(self, traces):
responses = []
for trace in traces:
self.traces.append(trace)
response = mock.Mock()
response.status = 200
responses.append(response)
return responses
class FailingAPI(object):
@staticmethod
def send_traces(traces):
return [Exception("oops")]
class AgentWriterTests(BaseTestCase):
N_TRACES = 11
def create_worker(self, filters=None, api_class=DummyAPI, enable_stats=False):
with self.override_global_config(dict(health_metrics_enabled=enable_stats)):
self.dogstatsd = mock.Mock()
worker = AgentWriter(dogstatsd=self.dogstatsd, filters=filters)
worker._STATS_EVERY_INTERVAL = 1
self.api = api_class()
worker.api = self.api
for i in range(self.N_TRACES):
worker.write(
[Span(tracer=None, name="name", trace_id=i, span_id=j, parent_id=j - 1 or None) for j in range(7)]
)
worker.stop()
worker.join()
return worker
def test_send_stats(self):
dogstatsd = mock.Mock()
worker = AgentWriter(dogstatsd=dogstatsd)
assert worker._send_stats is False
with self.override_global_config(dict(health_metrics_enabled=True)):
assert worker._send_stats is True
worker = AgentWriter(dogstatsd=None)
assert worker._send_stats is False
with self.override_global_config(dict(health_metrics_enabled=True)):
assert worker._send_stats is False
def test_filters_keep_all(self):
filtr = KeepAllFilter()
self.create_worker([filtr])
self.assertEqual(len(self.api.traces), self.N_TRACES)
self.assertEqual(filtr.filtered_traces, self.N_TRACES)
def test_filters_remove_all(self):
filtr = RemoveAllFilter()
self.create_worker([filtr])
self.assertEqual(len(self.api.traces), 0)
self.assertEqual(filtr.filtered_traces, self.N_TRACES)
def test_filters_add_tag(self):
tag_name = "Tag"
filtr = AddTagFilter(tag_name)
self.create_worker([filtr])
self.assertEqual(len(self.api.traces), self.N_TRACES)
self.assertEqual(filtr.filtered_traces, self.N_TRACES)
for trace in self.api.traces:
for span in trace:
self.assertIsNotNone(span.get_tag(tag_name))
def test_filters_short_circuit(self):
filtr = KeepAllFilter()
filters = [RemoveAllFilter(), filtr]
self.create_worker(filters)
self.assertEqual(len(self.api.traces), 0)
self.assertEqual(filtr.filtered_traces, 0)
def test_no_dogstats(self):
worker = self.create_worker()
assert worker._send_stats is False
assert [] == self.dogstatsd.gauge.mock_calls
def test_dogstatsd(self):
self.create_worker(enable_stats=True)
assert [
mock.call("datadog.tracer.heartbeat", 1),
mock.call("datadog.tracer.queue.max_length", 1000),
] == self.dogstatsd.gauge.mock_calls
assert [
mock.call("datadog.tracer.flushes"),
mock.call("datadog.tracer.flush.traces.total", 11, tags=None),
mock.call("datadog.tracer.flush.spans.total", 77, tags=None),
mock.call("datadog.tracer.flush.traces_filtered.total", 0, tags=None),
mock.call("datadog.tracer.api.requests.total", 11, tags=None),
mock.call("datadog.tracer.api.errors.total", 0, tags=None),
mock.call("datadog.tracer.api.responses.total", 11, tags=["status:200"]),
mock.call("datadog.tracer.queue.dropped.traces", 0),
mock.call("datadog.tracer.queue.enqueued.traces", 11),
mock.call("datadog.tracer.queue.enqueued.spans", 77),
mock.call("datadog.tracer.shutdown"),
] == self.dogstatsd.increment.mock_calls
histogram_calls = [
mock.call("datadog.tracer.flush.traces", 11, tags=None),
mock.call("datadog.tracer.flush.spans", 77, tags=None),
mock.call("datadog.tracer.flush.traces_filtered", 0, tags=None),
mock.call("datadog.tracer.api.requests", 11, tags=None),
mock.call("datadog.tracer.api.errors", 0, tags=None),
mock.call("datadog.tracer.api.responses", 11, tags=["status:200"]),
]
if hasattr(time, "thread_time"):
histogram_calls.append(mock.call("datadog.tracer.writer.cpu_time", mock.ANY))
assert histogram_calls == self.dogstatsd.histogram.mock_calls
def test_dogstatsd_failing_api(self):
self.create_worker(api_class=FailingAPI, enable_stats=True)
assert [
mock.call("datadog.tracer.heartbeat", 1),
mock.call("datadog.tracer.queue.max_length", 1000),
] == self.dogstatsd.gauge.mock_calls
assert [
mock.call("datadog.tracer.flushes"),
mock.call("datadog.tracer.flush.traces.total", 11, tags=None),
mock.call("datadog.tracer.flush.spans.total", 77, tags=None),
mock.call("datadog.tracer.flush.traces_filtered.total", 0, tags=None),
mock.call("datadog.tracer.api.requests.total", 1, tags=None),
mock.call("datadog.tracer.api.errors.total", 1, tags=None),
mock.call("datadog.tracer.queue.dropped.traces", 0),
mock.call("datadog.tracer.queue.enqueued.traces", 11),
mock.call("datadog.tracer.queue.enqueued.spans", 77),
mock.call("datadog.tracer.shutdown"),
] == self.dogstatsd.increment.mock_calls
histogram_calls = [
mock.call("datadog.tracer.flush.traces", 11, tags=None),
mock.call("datadog.tracer.flush.spans", 77, tags=None),
mock.call("datadog.tracer.flush.traces_filtered", 0, tags=None),
mock.call("datadog.tracer.api.requests", 1, tags=None),
mock.call("datadog.tracer.api.errors", 1, tags=None),
]
if hasattr(time, "thread_time"):
histogram_calls.append(mock.call("datadog.tracer.writer.cpu_time", mock.ANY))
assert histogram_calls == self.dogstatsd.histogram.mock_calls
def test_queue_full():
q = Q(maxsize=3)
q.put([1])
q.put(2)
q.put([3])
q.put([4, 4])
assert list(q.queue) == [[1], 2, [4, 4]] or list(q.queue) == [[1], [4, 4], [3]] or list(q.queue) == [[4, 4], 2, [3]]
assert q.dropped == 1
assert q.accepted == 4
assert q.accepted_lengths == 5
dropped, accepted, accepted_lengths = q.reset_stats()
assert dropped == 1
assert accepted == 4
assert accepted_lengths == 5
def test_queue_get():
q = Q(maxsize=3)
q.put(1)
q.put(2)
assert list(q.get()) == [1, 2]
with pytest.raises(Empty):
q.get(block=False)