Changeset View
Changeset View
Standalone View
Standalone View
swh/core/tests/test_statsd.py
Show First 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | |||||
class SlowSocket(FakeSocket): | class SlowSocket(FakeSocket): | ||||
def send(self, payload): | def send(self, payload): | ||||
raise socket.timeout("Socket timeout") | raise socket.timeout("Socket timeout") | ||||
class TestStatsd(unittest.TestCase): | class TestStatsd(unittest.TestCase): | ||||
def setUp(self): | def setUp(self): | ||||
""" | """ | ||||
Set up a default Statsd instance and mock the socket. | Set up a default Statsd instance and mock the socket. | ||||
""" | """ | ||||
# | # | ||||
self.statsd = Statsd() | self.statsd = Statsd() | ||||
self.statsd._socket = FakeSocket() | self.statsd._socket = FakeSocket() | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | def test_sample_rate(self): | ||||
assert not self.recv() | assert not self.recv() | ||||
for i in range(10000): | for i in range(10000): | ||||
self.statsd.increment('sampled_counter', sample_rate=0.3) | self.statsd.increment('sampled_counter', sample_rate=0.3) | ||||
self.assert_almost_equal(3000, len(self.statsd.socket.payloads), 150) | self.assert_almost_equal(3000, len(self.statsd.socket.payloads), 150) | ||||
self.assertEqual('sampled_counter:1|c|@0.3', self.recv()) | self.assertEqual('sampled_counter:1|c|@0.3', self.recv()) | ||||
def test_tags_and_samples(self): | def test_tags_and_samples(self): | ||||
for i in range(100): | for i in range(100): | ||||
self.statsd.gauge('gst', 23, tags={"sampled": True}, | self.statsd.gauge('gst', 23, tags={"sampled": True}, sample_rate=0.9) | ||||
sample_rate=0.9) | |||||
self.assert_almost_equal(90, len(self.statsd.socket.payloads), 10) | self.assert_almost_equal(90, len(self.statsd.socket.payloads), 10) | ||||
self.assertEqual('gst:23|g|@0.9|#sampled:True', self.recv()) | self.assertEqual('gst:23|g|@0.9|#sampled:True', self.recv()) | ||||
def test_timing(self): | def test_timing(self): | ||||
self.statsd.timing('t', 123) | self.statsd.timing('t', 123) | ||||
self.assertEqual('t:123|ms', self.recv()) | self.assertEqual('t:123|ms', self.recv()) | ||||
def test_metric_namespace(self): | def test_metric_namespace(self): | ||||
""" | """ | ||||
Namespace prefixes all metric names. | Namespace prefixes all metric names. | ||||
""" | """ | ||||
self.statsd.namespace = "foo" | self.statsd.namespace = "foo" | ||||
self.statsd.gauge('gauge', 123.4) | self.statsd.gauge('gauge', 123.4) | ||||
self.assertEqual('foo.gauge:123.4|g', self.recv()) | self.assertEqual('foo.gauge:123.4|g', self.recv()) | ||||
# Test Client level constant tags | # Test Client level constant tags | ||||
def test_gauge_constant_tags(self): | def test_gauge_constant_tags(self): | ||||
self.statsd.constant_tags = { | self.statsd.constant_tags = {'bar': 'baz'} | ||||
'bar': 'baz', | |||||
} | |||||
self.statsd.gauge('gauge', 123.4) | self.statsd.gauge('gauge', 123.4) | ||||
assert self.recv() == 'gauge:123.4|g|#bar:baz' | assert self.recv() == 'gauge:123.4|g|#bar:baz' | ||||
def test_counter_constant_tag_with_metric_level_tags(self): | def test_counter_constant_tag_with_metric_level_tags(self): | ||||
self.statsd.constant_tags = { | self.statsd.constant_tags = {'bar': 'baz', 'foo': True} | ||||
'bar': 'baz', | |||||
'foo': True, | |||||
} | |||||
self.statsd.increment('page.views', tags={'extra': 'extra'}) | self.statsd.increment('page.views', tags={'extra': 'extra'}) | ||||
self.assertEqual( | self.assertEqual('page.views:1|c|#bar:baz,extra:extra,foo:True', self.recv()) | ||||
'page.views:1|c|#bar:baz,extra:extra,foo:True', | |||||
self.recv(), | |||||
) | |||||
def test_gauge_constant_tags_with_metric_level_tags_twice(self): | def test_gauge_constant_tags_with_metric_level_tags_twice(self): | ||||
metric_level_tag = {'foo': 'bar'} | metric_level_tag = {'foo': 'bar'} | ||||
self.statsd.constant_tags = {'bar': 'baz'} | self.statsd.constant_tags = {'bar': 'baz'} | ||||
self.statsd.gauge('gauge', 123.4, tags=metric_level_tag) | self.statsd.gauge('gauge', 123.4, tags=metric_level_tag) | ||||
assert self.recv() == 'gauge:123.4|g|#bar:baz,foo:bar' | assert self.recv() == 'gauge:123.4|g|#bar:baz,foo:bar' | ||||
# sending metrics multiple times with same metric-level tags | # sending metrics multiple times with same metric-level tags | ||||
# should not duplicate the tags being sent | # should not duplicate the tags being sent | ||||
self.statsd.gauge('gauge', 123.4, tags=metric_level_tag) | self.statsd.gauge('gauge', 123.4, tags=metric_level_tag) | ||||
assert self.recv() == 'gauge:123.4|g|#bar:baz,foo:bar' | assert self.recv() == 'gauge:123.4|g|#bar:baz,foo:bar' | ||||
def assert_almost_equal(self, a, b, delta): | def assert_almost_equal(self, a, b, delta): | ||||
self.assertTrue( | self.assertTrue( | ||||
0 <= abs(a - b) <= delta, | 0 <= abs(a - b) <= delta, "%s - %s not within %s" % (a, b, delta) | ||||
"%s - %s not within %s" % (a, b, delta) | |||||
) | ) | ||||
def test_socket_error(self): | def test_socket_error(self): | ||||
self.statsd._socket = BrokenSocket() | self.statsd._socket = BrokenSocket() | ||||
self.statsd.gauge('no error', 1) | self.statsd.gauge('no error', 1) | ||||
assert True, 'success' | assert True, 'success' | ||||
def test_socket_timeout(self): | def test_socket_timeout(self): | ||||
self.statsd._socket = SlowSocket() | self.statsd._socket = SlowSocket() | ||||
self.statsd.gauge('no error', 1) | self.statsd.gauge('no error', 1) | ||||
assert True, 'success' | assert True, 'success' | ||||
def test_timed(self): | def test_timed(self): | ||||
""" | """ | ||||
Measure the distribution of a function's run time. | Measure the distribution of a function's run time. | ||||
""" | """ | ||||
@self.statsd.timed('timed.test') | @self.statsd.timed('timed.test') | ||||
def func(a, b, c=1, d=1): | def func(a, b, c=1, d=1): | ||||
"""docstring""" | """docstring""" | ||||
time.sleep(0.5) | time.sleep(0.5) | ||||
return (a, b, c, d) | return (a, b, c, d) | ||||
self.assertEqual('func', func.__name__) | self.assertEqual('func', func.__name__) | ||||
self.assertEqual('docstring', func.__doc__) | self.assertEqual('docstring', func.__doc__) | ||||
Show All 10 Lines | def test_timed(self): | ||||
self.assertEqual('timed.test', name) | self.assertEqual('timed.test', name) | ||||
self.assert_almost_equal(500, float(value), 100) | self.assert_almost_equal(500, float(value), 100) | ||||
def test_timed_exception(self): | def test_timed_exception(self): | ||||
""" | """ | ||||
Exception bubble out of the decorator and is reported | Exception bubble out of the decorator and is reported | ||||
to statsd as a dedicated counter. | to statsd as a dedicated counter. | ||||
""" | """ | ||||
@self.statsd.timed('timed.test') | @self.statsd.timed('timed.test') | ||||
def func(a, b, c=1, d=1): | def func(a, b, c=1, d=1): | ||||
"""docstring""" | """docstring""" | ||||
time.sleep(0.5) | time.sleep(0.5) | ||||
return (a / b, c, d) | return (a / b, c, d) | ||||
self.assertEqual('func', func.__name__) | self.assertEqual('func', func.__name__) | ||||
self.assertEqual('docstring', func.__doc__) | self.assertEqual('docstring', func.__doc__) | ||||
with self.assertRaises(ZeroDivisionError): | with self.assertRaises(ZeroDivisionError): | ||||
func(1, 0) | func(1, 0) | ||||
packet = self.recv() | packet = self.recv() | ||||
name_value, type_ = packet.split('|') | name_value, type_ = packet.split('|') | ||||
name, value = name_value.split(':') | name, value = name_value.split(':') | ||||
self.assertEqual('c', type_) | self.assertEqual('c', type_) | ||||
self.assertEqual('timed.test_error_count', name) | self.assertEqual('timed.test_error_count', name) | ||||
self.assertEqual(int(value), 1) | self.assertEqual(int(value), 1) | ||||
def test_timed_no_metric(self, ): | def test_timed_no_metric(self,): | ||||
""" | """ | ||||
Test using a decorator without providing a metric. | Test using a decorator without providing a metric. | ||||
""" | """ | ||||
@self.statsd.timed() | @self.statsd.timed() | ||||
def func(a, b, c=1, d=1): | def func(a, b, c=1, d=1): | ||||
"""docstring""" | """docstring""" | ||||
time.sleep(0.5) | time.sleep(0.5) | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | def test_timed_context(self): | ||||
self.assert_almost_equal(500, float(value), 100) | self.assert_almost_equal(500, float(value), 100) | ||||
self.assert_almost_equal(500, timer.elapsed, 100) | self.assert_almost_equal(500, timer.elapsed, 100) | ||||
def test_timed_context_exception(self): | def test_timed_context_exception(self): | ||||
""" | """ | ||||
Exception bubbles out of the `timed` context manager and is | Exception bubbles out of the `timed` context manager and is | ||||
reported to statsd as a dedicated counter. | reported to statsd as a dedicated counter. | ||||
""" | """ | ||||
class ContextException(Exception): | class ContextException(Exception): | ||||
pass | pass | ||||
def func(self): | def func(self): | ||||
with self.statsd.timed('timed_context.test'): | with self.statsd.timed('timed_context.test'): | ||||
time.sleep(0.5) | time.sleep(0.5) | ||||
raise ContextException() | raise ContextException() | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | class TestStatsd(unittest.TestCase): | ||||
def test_batched_buffer_autoflush(self): | def test_batched_buffer_autoflush(self): | ||||
fake_socket = FakeSocket() | fake_socket = FakeSocket() | ||||
with Statsd() as statsd: | with Statsd() as statsd: | ||||
statsd._socket = fake_socket | statsd._socket = fake_socket | ||||
for i in range(51): | for i in range(51): | ||||
statsd.increment('mycounter') | statsd.increment('mycounter') | ||||
self.assertEqual( | self.assertEqual( | ||||
'\n'.join(['mycounter:1|c' for i in range(50)]), | '\n'.join(['mycounter:1|c' for i in range(50)]), fake_socket.recv() | ||||
fake_socket.recv(), | |||||
) | ) | ||||
self.assertEqual('mycounter:1|c', fake_socket.recv()) | self.assertEqual('mycounter:1|c', fake_socket.recv()) | ||||
def test_module_level_instance(self): | def test_module_level_instance(self): | ||||
from swh.core.statsd import statsd | from swh.core.statsd import statsd | ||||
self.assertTrue(isinstance(statsd, Statsd)) | self.assertTrue(isinstance(statsd, Statsd)) | ||||
def test_instantiating_does_not_connect(self): | def test_instantiating_does_not_connect(self): | ||||
local_statsd = Statsd() | local_statsd = Statsd() | ||||
self.assertEqual(None, local_statsd._socket) | self.assertEqual(None, local_statsd._socket) | ||||
def test_accessing_socket_opens_socket(self): | def test_accessing_socket_opens_socket(self): | ||||
local_statsd = Statsd() | local_statsd = Statsd() | ||||
Show All 11 Lines | class TestStatsd(unittest.TestCase): | ||||
def test_tags_from_environment(self): | def test_tags_from_environment(self): | ||||
with preserve_envvars('STATSD_TAGS'): | with preserve_envvars('STATSD_TAGS'): | ||||
os.environ['STATSD_TAGS'] = 'country:china,age:45' | os.environ['STATSD_TAGS'] = 'country:china,age:45' | ||||
statsd = Statsd() | statsd = Statsd() | ||||
statsd._socket = FakeSocket() | statsd._socket = FakeSocket() | ||||
statsd.gauge('gt', 123.4) | statsd.gauge('gt', 123.4) | ||||
self.assertEqual('gt:123.4|g|#age:45,country:china', | self.assertEqual('gt:123.4|g|#age:45,country:china', statsd.socket.recv()) | ||||
statsd.socket.recv()) | |||||
def test_tags_from_environment_and_constant(self): | def test_tags_from_environment_and_constant(self): | ||||
with preserve_envvars('STATSD_TAGS'): | with preserve_envvars('STATSD_TAGS'): | ||||
os.environ['STATSD_TAGS'] = 'country:china,age:45' | os.environ['STATSD_TAGS'] = 'country:china,age:45' | ||||
statsd = Statsd(constant_tags={'country': 'canada'}) | statsd = Statsd(constant_tags={'country': 'canada'}) | ||||
statsd._socket = FakeSocket() | statsd._socket = FakeSocket() | ||||
statsd.gauge('gt', 123.4) | statsd.gauge('gt', 123.4) | ||||
self.assertEqual('gt:123.4|g|#age:45,country:canada', | self.assertEqual('gt:123.4|g|#age:45,country:canada', statsd.socket.recv()) | ||||
statsd.socket.recv()) | |||||
def test_tags_from_environment_warning(self): | def test_tags_from_environment_warning(self): | ||||
with preserve_envvars('STATSD_TAGS'): | with preserve_envvars('STATSD_TAGS'): | ||||
os.environ['STATSD_TAGS'] = 'valid:tag,invalid_tag' | os.environ['STATSD_TAGS'] = 'valid:tag,invalid_tag' | ||||
with pytest.warns(UserWarning) as record: | with pytest.warns(UserWarning) as record: | ||||
statsd = Statsd() | statsd = Statsd() | ||||
assert len(record) == 1 | assert len(record) == 1 | ||||
▲ Show 20 Lines • Show All 85 Lines • Show Last 20 Lines |