diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/__init__.py | 0 | ||||
-rw-r--r-- | tests/graphite_bridge.py | 69 | ||||
-rw-r--r-- | tests/proc/26231/fd/0 | 0 | ||||
-rw-r--r-- | tests/proc/26231/fd/1 | 0 | ||||
-rw-r--r-- | tests/proc/26231/fd/2 | 0 | ||||
-rw-r--r-- | tests/proc/26231/fd/3 | 0 | ||||
-rw-r--r-- | tests/proc/26231/fd/4 | 0 | ||||
-rw-r--r-- | tests/proc/26231/limits | 15 | ||||
-rw-r--r-- | tests/proc/26231/stat | 1 | ||||
-rw-r--r-- | tests/proc/584/stat | 1 | ||||
-rw-r--r-- | tests/proc/stat | 16 | ||||
-rw-r--r-- | tests/test_client.py | 373 | ||||
-rw-r--r-- | tests/test_exposition.py | 167 | ||||
-rw-r--r-- | tests/test_parser.py | 188 | ||||
-rw-r--r-- | tests/test_process_collector.py | 62 |
15 files changed, 892 insertions, 0 deletions
diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/__init__.py diff --git a/tests/graphite_bridge.py b/tests/graphite_bridge.py new file mode 100644 index 0000000..0ac2420 --- /dev/null +++ b/tests/graphite_bridge.py @@ -0,0 +1,69 @@ +import unittest +import threading +try: + import SocketServer +except ImportError: + import socketserver as SocketServer + +from prometheus_client import Counter, CollectorRegistry +from prometheus_client.bridge.graphite import GraphiteBridge + +class FakeTime(object): + def time(self): + return 1434898897.5 + +class TestGraphiteBridge(unittest.TestCase): + def setUp(self): + self.registry = CollectorRegistry() + + self.data = '' + class TCPHandler(SocketServer.BaseRequestHandler): + def handle(s): + self.data = s.request.recv(1024) + server = SocketServer.TCPServer(('', 0), TCPHandler) + class ServingThread(threading.Thread): + def run(self): + server.handle_request() + server.socket.close() + self.t = ServingThread() + self.t.start() + + # Explicitly use localhost as the target host, since connecting to 0.0.0.0 fails on Windows + address = ('localhost', server.server_address[1]) + self.gb = GraphiteBridge(address, self.registry, _time=FakeTime()) + + def test_nolabels(self): + counter = Counter('c', 'help', registry=self.registry) + counter.inc() + + self.gb.push() + self.t.join() + + self.assertEqual(b'c 1.0 1434898897\n', self.data) + + def test_labels(self): + labels = Counter('labels', 'help', ['a', 'b'], registry=self.registry) + labels.labels('c', 'd').inc() + + self.gb.push() + self.t.join() + + self.assertEqual(b'labels.a.c.b.d 1.0 1434898897\n', self.data) + + def test_prefix(self): + labels = Counter('labels', 'help', ['a', 'b'], registry=self.registry) + labels.labels('c', 'd').inc() + + self.gb.push(prefix = 'pre.fix') + self.t.join() + + self.assertEqual(b'pre.fix.labels.a.c.b.d 1.0 1434898897\n', self.data) + + def test_sanitizing(self): + labels = Counter('labels', 'help', ['a'], registry=self.registry) + labels.labels('c.:8').inc() + + self.gb.push() + self.t.join() + + self.assertEqual(b'labels.a.c__8 1.0 1434898897\n', self.data) diff --git a/tests/proc/26231/fd/0 b/tests/proc/26231/fd/0 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/proc/26231/fd/0 diff --git a/tests/proc/26231/fd/1 b/tests/proc/26231/fd/1 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/proc/26231/fd/1 diff --git a/tests/proc/26231/fd/2 b/tests/proc/26231/fd/2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/proc/26231/fd/2 diff --git a/tests/proc/26231/fd/3 b/tests/proc/26231/fd/3 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/proc/26231/fd/3 diff --git a/tests/proc/26231/fd/4 b/tests/proc/26231/fd/4 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/proc/26231/fd/4 diff --git a/tests/proc/26231/limits b/tests/proc/26231/limits new file mode 100644 index 0000000..d477b9b --- /dev/null +++ b/tests/proc/26231/limits @@ -0,0 +1,15 @@ +Limit Soft Limit Hard Limit Units +Max cpu time unlimited unlimited seconds +Max file size unlimited unlimited bytes +Max data size unlimited unlimited bytes +Max stack size 8388608 unlimited bytes +Max core file size 0 unlimited bytes +Max resident set unlimited unlimited bytes +Max processes 62898 62898 processes +Max open files 2048 4096 files +Max locked memory 65536 65536 bytes +Max address space unlimited unlimited bytes +Max file locks unlimited unlimited locks +Max pending signals 62898 62898 signals +Max msgqueue size 819200 819200 bytes +Max nice priority 0 0 diff --git a/tests/proc/26231/stat b/tests/proc/26231/stat new file mode 100644 index 0000000..438aaa9 --- /dev/null +++ b/tests/proc/26231/stat @@ -0,0 +1 @@ +26231 (vim) R 5392 7446 5392 34835 7446 4218880 32533 309516 26 82 1677 44 158 99 20 0 1 0 82375 56274944 1981 18446744073709551615 4194304 6294284 140736914091744 140736914087944 139965136429984 0 0 12288 1870679807 0 0 0 17 0 0 0 31 0 0 8391624 8481048 16420864 140736914093252 140736914093279 140736914093279 140736914096107 0 diff --git a/tests/proc/584/stat b/tests/proc/584/stat new file mode 100644 index 0000000..af0d385 --- /dev/null +++ b/tests/proc/584/stat @@ -0,0 +1 @@ +1020 ((a b ) ( c d) ) R 28378 1020 28378 34842 1020 4218880 286 0 0 0 0 0 0 0 20 0 1 0 10839175 10395648 155 18446744073709551615 4194304 4238788 140736466511168 140736466511168 140609271124624 0 0 0 0 0 0 0 17 5 0 0 0 0 0 6336016 6337300 25579520 140736466515030 140736466515061 140736466515061 140736466518002 0 diff --git a/tests/proc/stat b/tests/proc/stat new file mode 100644 index 0000000..32fd6d2 --- /dev/null +++ b/tests/proc/stat @@ -0,0 +1,16 @@ +cpu 301854 612 111922 8979004 3552 2 3944 0 0 0 +cpu0 44490 19 21045 1087069 220 1 3410 0 0 0 +cpu1 47869 23 16474 1110787 591 0 46 0 0 0 +cpu2 46504 36 15916 1112321 441 0 326 0 0 0 +cpu3 47054 102 15683 1113230 533 0 60 0 0 0 +cpu4 28413 25 10776 1140321 217 0 8 0 0 0 +cpu5 29271 101 11586 1136270 672 0 30 0 0 0 +cpu6 29152 36 10276 1139721 319 0 29 0 0 0 +cpu7 29098 268 10164 1139282 555 0 31 0 0 0 +intr 8885917 17 0 0 0 0 0 0 0 1 79281 0 0 0 0 0 0 0 231237 0 0 0 0 250586 103 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 223424 190745 13 906 1283803 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0intr 8885917 17 0 0 0 0 0 0 0 1 79281 0 0 0 0 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +ctxt 38014093 +btime 1418183276 +processes 26442 +procs_running 2 +procs_blocked 0 +softirq 5057579 250191 1481983 1647 211099 186066 0 1783454 622196 12499 508444 diff --git a/tests/test_client.py b/tests/test_client.py new file mode 100644 index 0000000..83b15e8 --- /dev/null +++ b/tests/test_client.py @@ -0,0 +1,373 @@ +from __future__ import unicode_literals +import os +import threading +import time +import unittest + +from prometheus_client.core import * + +class TestCounter(unittest.TestCase): + def setUp(self): + self.registry = CollectorRegistry() + self.counter = Counter('c', 'help', registry=self.registry) + + def test_increment(self): + self.assertEqual(0, self.registry.get_sample_value('c')) + self.counter.inc() + self.assertEqual(1, self.registry.get_sample_value('c')) + self.counter.inc(7) + self.assertEqual(8, self.registry.get_sample_value('c')) + + def test_negative_increment_raises(self): + self.assertRaises(ValueError, self.counter.inc, -1) + + def test_function_decorator(self): + @self.counter.count_exceptions(ValueError) + def f(r): + if r: + raise ValueError + else: + raise TypeError + + try: + f(False) + except TypeError: + pass + self.assertEqual(0, self.registry.get_sample_value('c')) + + try: + f(True) + except ValueError: + raised = True + self.assertEqual(1, self.registry.get_sample_value('c')) + + def test_block_decorator(self): + with self.counter.count_exceptions(): + pass + self.assertEqual(0, self.registry.get_sample_value('c')) + + raised = False + try: + with self.counter.count_exceptions(): + raise ValueError + except: + raised = True + self.assertTrue(raised) + self.assertEqual(1, self.registry.get_sample_value('c')) + + +class TestGauge(unittest.TestCase): + def setUp(self): + self.registry = CollectorRegistry() + self.gauge = Gauge('g', 'help', registry=self.registry) + + def test_gauge(self): + self.assertEqual(0, self.registry.get_sample_value('g')) + self.gauge.inc() + self.assertEqual(1, self.registry.get_sample_value('g')) + self.gauge.dec(3) + self.assertEqual(-2, self.registry.get_sample_value('g')) + self.gauge.set(9) + self.assertEqual(9, self.registry.get_sample_value('g')) + + def test_function_decorator(self): + self.assertEqual(0, self.registry.get_sample_value('g')) + + @self.gauge.track_inprogress() + def f(): + self.assertEqual(1, self.registry.get_sample_value('g')) + + f() + self.assertEqual(0, self.registry.get_sample_value('g')) + + def test_block_decorator(self): + self.assertEqual(0, self.registry.get_sample_value('g')) + with self.gauge.track_inprogress(): + self.assertEqual(1, self.registry.get_sample_value('g')) + self.assertEqual(0, self.registry.get_sample_value('g')) + + def test_gauge_function(self): + x = {} + self.gauge.set_function(lambda: len(x)) + self.assertEqual(0, self.registry.get_sample_value('g')) + self.gauge.inc() + self.assertEqual(0, self.registry.get_sample_value('g')) + x['a'] = None + self.assertEqual(1, self.registry.get_sample_value('g')) + + def test_function_decorator(self): + self.assertEqual(0, self.registry.get_sample_value('g')) + + @self.gauge.time() + def f(): + time.sleep(.001) + + f() + self.assertNotEqual(0, self.registry.get_sample_value('g')) + + def test_block_decorator(self): + self.assertEqual(0, self.registry.get_sample_value('g')) + with self.gauge.time(): + time.sleep(.001) + self.assertNotEqual(0, self.registry.get_sample_value('g')) + + +class TestSummary(unittest.TestCase): + def setUp(self): + self.registry = CollectorRegistry() + self.summary = Summary('s', 'help', registry=self.registry) + + def test_summary(self): + self.assertEqual(0, self.registry.get_sample_value('s_count')) + self.assertEqual(0, self.registry.get_sample_value('s_sum')) + self.summary.observe(10) + self.assertEqual(1, self.registry.get_sample_value('s_count')) + self.assertEqual(10, self.registry.get_sample_value('s_sum')) + + def test_function_decorator(self): + self.assertEqual(0, self.registry.get_sample_value('s_count')) + + @self.summary.time() + def f(): + pass + + f() + self.assertEqual(1, self.registry.get_sample_value('s_count')) + + def test_block_decorator(self): + self.assertEqual(0, self.registry.get_sample_value('s_count')) + with self.summary.time(): + pass + self.assertEqual(1, self.registry.get_sample_value('s_count')) + + +class TestHistogram(unittest.TestCase): + def setUp(self): + self.registry = CollectorRegistry() + self.histogram = Histogram('h', 'help', registry=self.registry) + self.labels = Histogram('hl', 'help', ['l'], registry=self.registry) + + def test_histogram(self): + self.assertEqual(0, self.registry.get_sample_value('h_bucket', {'le': '1.0'})) + self.assertEqual(0, self.registry.get_sample_value('h_bucket', {'le': '2.5'})) + self.assertEqual(0, self.registry.get_sample_value('h_bucket', {'le': '5.0'})) + self.assertEqual(0, self.registry.get_sample_value('h_bucket', {'le': '+Inf'})) + self.assertEqual(0, self.registry.get_sample_value('h_count')) + self.assertEqual(0, self.registry.get_sample_value('h_sum')) + + self.histogram.observe(2) + self.assertEqual(0, self.registry.get_sample_value('h_bucket', {'le': '1.0'})) + self.assertEqual(1, self.registry.get_sample_value('h_bucket', {'le': '2.5'})) + self.assertEqual(1, self.registry.get_sample_value('h_bucket', {'le': '5.0'})) + self.assertEqual(1, self.registry.get_sample_value('h_bucket', {'le': '+Inf'})) + self.assertEqual(1, self.registry.get_sample_value('h_count')) + self.assertEqual(2, self.registry.get_sample_value('h_sum')) + + self.histogram.observe(2.5) + self.assertEqual(0, self.registry.get_sample_value('h_bucket', {'le': '1.0'})) + self.assertEqual(2, self.registry.get_sample_value('h_bucket', {'le': '2.5'})) + self.assertEqual(2, self.registry.get_sample_value('h_bucket', {'le': '5.0'})) + self.assertEqual(2, self.registry.get_sample_value('h_bucket', {'le': '+Inf'})) + self.assertEqual(2, self.registry.get_sample_value('h_count')) + self.assertEqual(4.5, self.registry.get_sample_value('h_sum')) + + self.histogram.observe(float("inf")) + self.assertEqual(0, self.registry.get_sample_value('h_bucket', {'le': '1.0'})) + self.assertEqual(2, self.registry.get_sample_value('h_bucket', {'le': '2.5'})) + self.assertEqual(2, self.registry.get_sample_value('h_bucket', {'le': '5.0'})) + self.assertEqual(3, self.registry.get_sample_value('h_bucket', {'le': '+Inf'})) + self.assertEqual(3, self.registry.get_sample_value('h_count')) + self.assertEqual(float("inf"), self.registry.get_sample_value('h_sum')) + + def test_setting_buckets(self): + h = Histogram('h', 'help', registry=None, buckets=[0, 1, 2]) + self.assertEqual([0.0, 1.0, 2.0, float("inf")], h._upper_bounds) + + h = Histogram('h', 'help', registry=None, buckets=[0, 1, 2, float("inf")]) + self.assertEqual([0.0, 1.0, 2.0, float("inf")], h._upper_bounds) + + self.assertRaises(ValueError, Histogram, 'h', 'help', registry=None, buckets=[]) + self.assertRaises(ValueError, Histogram, 'h', 'help', registry=None, buckets=[float("inf")]) + self.assertRaises(ValueError, Histogram, 'h', 'help', registry=None, buckets=[3, 1]) + + def test_labels(self): + self.labels.labels('a').observe(2) + self.assertEqual(0, self.registry.get_sample_value('hl_bucket', {'le': '1.0', 'l': 'a'})) + self.assertEqual(1, self.registry.get_sample_value('hl_bucket', {'le': '2.5', 'l': 'a'})) + self.assertEqual(1, self.registry.get_sample_value('hl_bucket', {'le': '5.0', 'l': 'a'})) + self.assertEqual(1, self.registry.get_sample_value('hl_bucket', {'le': '+Inf', 'l': 'a'})) + self.assertEqual(1, self.registry.get_sample_value('hl_count', {'l': 'a'})) + self.assertEqual(2, self.registry.get_sample_value('hl_sum', {'l': 'a'})) + + def test_function_decorator(self): + self.assertEqual(0, self.registry.get_sample_value('h_count')) + self.assertEqual(0, self.registry.get_sample_value('h_bucket', {'le': '+Inf'})) + + @self.histogram.time() + def f(): + pass + + f() + self.assertEqual(1, self.registry.get_sample_value('h_count')) + self.assertEqual(1, self.registry.get_sample_value('h_bucket', {'le': '+Inf'})) + + def test_block_decorator(self): + self.assertEqual(0, self.registry.get_sample_value('h_count')) + self.assertEqual(0, self.registry.get_sample_value('h_bucket', {'le': '+Inf'})) + with self.histogram.time(): + pass + self.assertEqual(1, self.registry.get_sample_value('h_count')) + self.assertEqual(1, self.registry.get_sample_value('h_bucket', {'le': '+Inf'})) + + +class TestMetricWrapper(unittest.TestCase): + def setUp(self): + self.registry = CollectorRegistry() + self.counter = Counter('c', 'help', labelnames=['l'], registry=self.registry) + self.two_labels = Counter('two', 'help', labelnames=['a', 'b'], registry=self.registry) + + def test_child(self): + self.counter.labels('x').inc() + self.assertEqual(1, self.registry.get_sample_value('c', {'l': 'x'})) + self.two_labels.labels('x', 'y').inc(2) + self.assertEqual(2, self.registry.get_sample_value('two', {'a': 'x', 'b': 'y'})) + + def test_remove(self): + self.counter.labels('x').inc() + self.counter.labels('y').inc(2) + self.assertEqual(1, self.registry.get_sample_value('c', {'l': 'x'})) + self.assertEqual(2, self.registry.get_sample_value('c', {'l': 'y'})) + self.counter.remove('x') + self.assertEqual(None, self.registry.get_sample_value('c', {'l': 'x'})) + self.assertEqual(2, self.registry.get_sample_value('c', {'l': 'y'})) + + def test_incorrect_label_count_raises(self): + self.assertRaises(ValueError, self.counter.labels) + self.assertRaises(ValueError, self.counter.labels, 'a', 'b') + self.assertRaises(ValueError, self.counter.remove) + self.assertRaises(ValueError, self.counter.remove, 'a', 'b') + + def test_labels_coerced_to_string(self): + self.counter.labels(None).inc() + self.counter.labels({'l': None}).inc() + self.assertEqual(2, self.registry.get_sample_value('c', {'l': 'None'})) + + self.counter.remove(None) + self.assertEqual(None, self.registry.get_sample_value('c', {'l': 'None'})) + + def test_non_string_labels_raises(self): + class Test(object): + __str__ = None + self.assertRaises(TypeError, self.counter.labels, Test()) + self.assertRaises(TypeError, self.counter.labels, {'l': Test()}) + + def test_namespace_subsystem_concatenated(self): + c = Counter('c', 'help', namespace='a', subsystem='b', registry=self.registry) + c.inc() + self.assertEqual(1, self.registry.get_sample_value('a_b_c')) + + def test_labels_by_dict(self): + self.counter.labels({'l': 'x'}).inc() + self.assertEqual(1, self.registry.get_sample_value('c', {'l': 'x'})) + self.assertRaises(ValueError, self.counter.labels, {'l': 'x', 'm': 'y'}) + self.assertRaises(ValueError, self.counter.labels, {'m': 'y'}) + self.assertRaises(ValueError, self.counter.labels, {}) + self.two_labels.labels({'a': 'x', 'b': 'y'}).inc() + self.assertEqual(1, self.registry.get_sample_value('two', {'a': 'x', 'b': 'y'})) + self.assertRaises(ValueError, self.two_labels.labels, {'a': 'x', 'b': 'y', 'c': 'z'}) + self.assertRaises(ValueError, self.two_labels.labels, {'a': 'x', 'c': 'z'}) + self.assertRaises(ValueError, self.two_labels.labels, {'b': 'y', 'c': 'z'}) + self.assertRaises(ValueError, self.two_labels.labels, {'c': 'z'}) + self.assertRaises(ValueError, self.two_labels.labels, {}) + + def test_invalid_names_raise(self): + self.assertRaises(ValueError, Counter, '', 'help') + self.assertRaises(ValueError, Counter, '^', 'help') + self.assertRaises(ValueError, Counter, '', 'help', namespace='&') + self.assertRaises(ValueError, Counter, '', 'help', subsystem='(') + self.assertRaises(ValueError, Counter, 'c', '', labelnames=['^']) + self.assertRaises(ValueError, Counter, 'c', '', labelnames=['__reserved']) + self.assertRaises(ValueError, Summary, 'c', '', labelnames=['quantile']) + + +class TestMetricFamilies(unittest.TestCase): + def setUp(self): + self.registry = CollectorRegistry() + + def custom_collector(self, metric_family): + class CustomCollector(object): + def collect(self): + return [metric_family] + self.registry.register(CustomCollector()) + + def test_counter(self): + self.custom_collector(CounterMetricFamily('c', 'help', value=1)) + self.assertEqual(1, self.registry.get_sample_value('c', {})) + + def test_counter_labels(self): + cmf = CounterMetricFamily('c', 'help', labels=['a', 'c']) + cmf.add_metric(['b', 'd'], 2) + self.custom_collector(cmf) + self.assertEqual(2, self.registry.get_sample_value('c', {'a': 'b', 'c': 'd'})) + + def test_gauge(self): + self.custom_collector(GaugeMetricFamily('g', 'help', value=1)) + self.assertEqual(1, self.registry.get_sample_value('g', {})) + + def test_gauge_labels(self): + cmf = GaugeMetricFamily('g', 'help', labels=['a']) + cmf.add_metric(['b'], 2) + self.custom_collector(cmf) + self.assertEqual(2, self.registry.get_sample_value('g', {'a':'b'})) + + def test_summary(self): + self.custom_collector(SummaryMetricFamily('s', 'help', count_value=1, sum_value=2)) + self.assertEqual(1, self.registry.get_sample_value('s_count', {})) + self.assertEqual(2, self.registry.get_sample_value('s_sum', {})) + + def test_summary_labels(self): + cmf = SummaryMetricFamily('s', 'help', labels=['a']) + cmf.add_metric(['b'], count_value=1, sum_value=2) + self.custom_collector(cmf) + self.assertEqual(1, self.registry.get_sample_value('s_count', {'a': 'b'})) + self.assertEqual(2, self.registry.get_sample_value('s_sum', {'a': 'b'})) + + def test_histogram(self): + self.custom_collector(HistogramMetricFamily('h', 'help', buckets=[('0', 1), ('+Inf', 2)], sum_value=3)) + self.assertEqual(1, self.registry.get_sample_value('h_bucket', {'le': '0'})) + self.assertEqual(2, self.registry.get_sample_value('h_bucket', {'le': '+Inf'})) + self.assertEqual(2, self.registry.get_sample_value('h_count', {})) + self.assertEqual(3, self.registry.get_sample_value('h_sum', {})) + + def test_histogram_labels(self): + cmf = HistogramMetricFamily('h', 'help', labels=['a']) + cmf.add_metric(['b'], buckets=[('0', 1), ('+Inf', 2)], sum_value=3) + self.custom_collector(cmf) + self.assertEqual(1, self.registry.get_sample_value('h_bucket', {'a': 'b', 'le': '0'})) + self.assertEqual(2, self.registry.get_sample_value('h_bucket', {'a': 'b', 'le': '+Inf'})) + self.assertEqual(2, self.registry.get_sample_value('h_count', {'a': 'b'})) + self.assertEqual(3, self.registry.get_sample_value('h_sum', {'a': 'b'})) + + def test_bad_constructors(self): + self.assertRaises(ValueError, CounterMetricFamily, 'c', 'help', value=1, labels=[]) + self.assertRaises(ValueError, CounterMetricFamily, 'c', 'help', value=1, labels=['a']) + + self.assertRaises(ValueError, GaugeMetricFamily, 'g', 'help', value=1, labels=[]) + self.assertRaises(ValueError, GaugeMetricFamily, 'g', 'help', value=1, labels=['a']) + + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', sum_value=1) + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', count_value=1) + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', count_value=1, labels=['a']) + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', sum_value=1, labels=['a']) + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', count_value=1, sum_value=1, labels=['a']) + + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', sum_value=1) + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', buckets={}) + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', sum_value=1, labels=['a']) + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', buckets={}, labels=['a']) + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', buckets={}, sum_value=1, labels=['a']) + self.assertRaises(KeyError, HistogramMetricFamily, 'h', 'help', buckets={}, sum_value=1) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_exposition.py b/tests/test_exposition.py new file mode 100644 index 0000000..c5fd1fe --- /dev/null +++ b/tests/test_exposition.py @@ -0,0 +1,167 @@ +from __future__ import unicode_literals +import os +import threading +import time +import unittest + + +from prometheus_client import Gauge, Counter, Summary, Histogram, Metric +from prometheus_client import CollectorRegistry, generate_latest +from prometheus_client import push_to_gateway, pushadd_to_gateway, delete_from_gateway +from prometheus_client import CONTENT_TYPE_LATEST, instance_ip_grouping_key + +try: + from BaseHTTPServer import BaseHTTPRequestHandler + from BaseHTTPServer import HTTPServer +except ImportError: + # Python 3 + from http.server import BaseHTTPRequestHandler + from http.server import HTTPServer + + +class TestGenerateText(unittest.TestCase): + def setUp(self): + self.registry = CollectorRegistry() + + def test_counter(self): + c = Counter('cc', 'A counter', registry=self.registry) + c.inc() + self.assertEqual(b'# HELP cc A counter\n# TYPE cc counter\ncc 1.0\n', generate_latest(self.registry)) + + def test_gauge(self): + g = Gauge('gg', 'A gauge', registry=self.registry) + g.set(17) + self.assertEqual(b'# HELP gg A gauge\n# TYPE gg gauge\ngg 17.0\n', generate_latest(self.registry)) + + def test_summary(self): + s = Summary('ss', 'A summary', ['a', 'b'], registry=self.registry) + s.labels('c', 'd').observe(17) + self.assertEqual(b'# HELP ss A summary\n# TYPE ss summary\nss_count{a="c",b="d"} 1.0\nss_sum{a="c",b="d"} 17.0\n', generate_latest(self.registry)) + + def test_histogram(self): + s = Histogram('hh', 'A histogram', registry=self.registry) + s.observe(0.05) + self.assertEqual(b'''# HELP hh A histogram +# TYPE hh histogram +hh_bucket{le="0.005"} 0.0 +hh_bucket{le="0.01"} 0.0 +hh_bucket{le="0.025"} 0.0 +hh_bucket{le="0.05"} 1.0 +hh_bucket{le="0.075"} 1.0 +hh_bucket{le="0.1"} 1.0 +hh_bucket{le="0.25"} 1.0 +hh_bucket{le="0.5"} 1.0 +hh_bucket{le="0.75"} 1.0 +hh_bucket{le="1.0"} 1.0 +hh_bucket{le="2.5"} 1.0 +hh_bucket{le="5.0"} 1.0 +hh_bucket{le="7.5"} 1.0 +hh_bucket{le="10.0"} 1.0 +hh_bucket{le="+Inf"} 1.0 +hh_count 1.0 +hh_sum 0.05 +''', generate_latest(self.registry)) + + def test_unicode(self): + c = Counter('cc', '\u4500', ['l'], registry=self.registry) + c.labels('\u4500').inc() + self.assertEqual(b'# HELP cc \xe4\x94\x80\n# TYPE cc counter\ncc{l="\xe4\x94\x80"} 1.0\n', generate_latest(self.registry)) + + def test_escaping(self): + c = Counter('cc', 'A\ncount\\er', ['a'], registry=self.registry) + c.labels('\\x\n"').inc(1) + self.assertEqual(b'# HELP cc A\\ncount\\\\er\n# TYPE cc counter\ncc{a="\\\\x\\n\\""} 1.0\n', generate_latest(self.registry)) + + def test_nonnumber(self): + class MyNumber(): + def __repr__(self): + return "MyNumber(123)" + def __float__(self): + return 123.0 + class MyCollector(): + def collect(self): + metric = Metric("nonnumber", "Non number", 'untyped') + metric.add_sample("nonnumber", {}, MyNumber()) + yield metric + self.registry.register(MyCollector()) + self.assertEqual(b'# HELP nonnumber Non number\n# TYPE nonnumber untyped\nnonnumber 123.0\n', generate_latest(self.registry)) + + +class TestPushGateway(unittest.TestCase): + def setUp(self): + self.registry = CollectorRegistry() + self.counter = Gauge('g', 'help', registry=self.registry) + self.requests = requests = [] + class TestHandler(BaseHTTPRequestHandler): + def do_PUT(self): + self.send_response(201) + length = int(self.headers['content-length']) + requests.append((self, self.rfile.read(length))) + + do_POST = do_PUT + do_DELETE = do_PUT + + httpd = HTTPServer(('', 0), TestHandler) + self.address = ':'.join([str(x) for x in httpd.server_address]) + class TestServer(threading.Thread): + def run(self): + httpd.handle_request() + self.server = TestServer() + self.server.daemon = True + self.server.start() + + def test_push(self): + push_to_gateway(self.address, "my_job", self.registry) + self.assertEqual(self.requests[0][0].command, 'PUT') + self.assertEqual(self.requests[0][0].path, '/metrics/job/my_job') + self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) + self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') + + def test_push_with_groupingkey(self): + push_to_gateway(self.address, "my_job", self.registry, {'a': 9}) + self.assertEqual(self.requests[0][0].command, 'PUT') + self.assertEqual(self.requests[0][0].path, '/metrics/job/my_job/a/9') + self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) + self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') + + def test_push_with_complex_groupingkey(self): + push_to_gateway(self.address, "my_job", self.registry, {'a': 9, 'b': 'a/ z'}) + self.assertEqual(self.requests[0][0].command, 'PUT') + self.assertEqual(self.requests[0][0].path, '/metrics/job/my_job/a/9/b/a%2F+z') + self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) + self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') + + def test_pushadd(self): + pushadd_to_gateway(self.address, "my_job", self.registry) + self.assertEqual(self.requests[0][0].command, 'POST') + self.assertEqual(self.requests[0][0].path, '/metrics/job/my_job') + self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) + self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') + + def test_pushadd_with_groupingkey(self): + pushadd_to_gateway(self.address, "my_job", self.registry, {'a': 9}) + self.assertEqual(self.requests[0][0].command, 'POST') + self.assertEqual(self.requests[0][0].path, '/metrics/job/my_job/a/9') + self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) + self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') + + def test_delete(self): + delete_from_gateway(self.address, "my_job") + self.assertEqual(self.requests[0][0].command, 'DELETE') + self.assertEqual(self.requests[0][0].path, '/metrics/job/my_job') + self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) + self.assertEqual(self.requests[0][1], b'') + + def test_delete_with_groupingkey(self): + delete_from_gateway(self.address, "my_job", {'a': 9}) + self.assertEqual(self.requests[0][0].command, 'DELETE') + self.assertEqual(self.requests[0][0].path, '/metrics/job/my_job/a/9') + self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) + self.assertEqual(self.requests[0][1], b'') + + def test_instance_ip_grouping_key(self): + self.assertTrue('' != instance_ip_grouping_key()['instance']) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_parser.py b/tests/test_parser.py new file mode 100644 index 0000000..f207a22 --- /dev/null +++ b/tests/test_parser.py @@ -0,0 +1,188 @@ +from __future__ import unicode_literals + +import unittest + +from prometheus_client.core import * +from prometheus_client.exposition import * +from prometheus_client.parser import * + + +class TestParse(unittest.TestCase): + + def test_simple_counter(self): + families = text_string_to_metric_families("""# TYPE a counter +# HELP a help +a 1 +""") + self.assertEqual([CounterMetricFamily("a", "help", value=1)], list(families)) + + def test_simple_gauge(self): + families = text_string_to_metric_families("""# TYPE a gauge +# HELP a help +a 1 +""") + self.assertEqual([GaugeMetricFamily("a", "help", value=1)], list(families)) + + def test_simple_summary(self): + families = text_string_to_metric_families("""# TYPE a summary +# HELP a help +a_count 1 +a_sum 2 +""") + + def test_summary_quantiles(self): + families = text_string_to_metric_families("""# TYPE a summary +# HELP a help +a_count 1 +a_sum 2 +a{quantile="0.5"} 0.7 +""") + # The Python client doesn't support quantiles, but we + # still need to be able to parse them. + metric_family = SummaryMetricFamily("a", "help", count_value=1, sum_value=2) + metric_family.add_sample("a", {"quantile": "0.5"}, 0.7) + self.assertEqual([metric_family], list(families)) + + def test_simple_histogram(self): + families = text_string_to_metric_families("""# TYPE a histogram +# HELP a help +a_bucket{le="1"} 0 +a_bucket{le="+Inf"} 3 +a_count 3 +a_sum 2 +""") + self.assertEqual([HistogramMetricFamily("a", "help", sum_value=2, buckets=[("1", 0.0), ("+Inf", 3.0)])], list(families)) + + def test_no_metadata(self): + families = text_string_to_metric_families("""a 1 +""") + metric_family = Metric("a", "", "untyped") + metric_family.add_sample("a", {}, 1) + self.assertEqual([metric_family], list(families)) + + def test_type_help_switched(self): + families = text_string_to_metric_families("""# HELP a help +# TYPE a counter +a 1 +""") + self.assertEqual([CounterMetricFamily("a", "help", value=1)], list(families)) + + def test_blank_lines_and_comments(self): + families = text_string_to_metric_families(""" +# TYPE a counter +# FOO a +# BAR b +# HELP a help + +a 1 +""") + self.assertEqual([CounterMetricFamily("a", "help", value=1)], list(families)) + + def test_tabs(self): + families = text_string_to_metric_families("""#\tTYPE\ta\tcounter +#\tHELP\ta\thelp +a\t1 +""") + self.assertEqual([CounterMetricFamily("a", "help", value=1)], list(families)) + + def test_empty_help(self): + families = text_string_to_metric_families("""# TYPE a counter +# HELP a +a 1 +""") + self.assertEqual([CounterMetricFamily("a", "", value=1)], list(families)) + + def test_labels_and_infinite(self): + families = text_string_to_metric_families("""# TYPE a counter +# HELP a help +a{foo="bar"} +Inf +a{foo="baz"} -Inf +""") + metric_family = CounterMetricFamily("a", "help", labels=["foo"]) + metric_family.add_metric(["bar"], core._INF) + metric_family.add_metric(["baz"], core._MINUS_INF) + self.assertEqual([metric_family], list(families)) + + def test_spaces(self): + families = text_string_to_metric_families("""# TYPE a counter +# HELP a help +a{ foo = "bar" } 1 +a\t\t{\t\tfoo\t\t=\t\t"baz"\t\t}\t\t2 +""") + metric_family = CounterMetricFamily("a", "help", labels=["foo"]) + metric_family.add_metric(["bar"], 1) + metric_family.add_metric(["baz"], 2) + self.assertEqual([metric_family], list(families)) + + def test_nan(self): + families = text_string_to_metric_families("""a NaN +""") + # Can't use a simple comparison as nan != nan. + self.assertTrue(math.isnan(list(families)[0].samples[0][2])) + + def test_escaping(self): + families = text_string_to_metric_families("""# TYPE a counter +# HELP a he\\n\\\\l\\tp +a{foo="b\\"a\\nr"} 1 +a{foo="b\\\\a\\z"} 2 +""") + metric_family = CounterMetricFamily("a", "he\n\\l\\tp", labels=["foo"]) + metric_family.add_metric(["b\"a\nr"], 1) + metric_family.add_metric(["b\\a\\z"], 2) + self.assertEqual([metric_family], list(families)) + + def test_roundtrip(self): + text = """# HELP go_gc_duration_seconds A summary of the GC invocation durations. +# TYPE go_gc_duration_seconds summary +go_gc_duration_seconds{quantile="0"} 0.013300656000000001 +go_gc_duration_seconds{quantile="0.25"} 0.013638736 +go_gc_duration_seconds{quantile="0.5"} 0.013759906 +go_gc_duration_seconds{quantile="0.75"} 0.013962066 +go_gc_duration_seconds{quantile="1"} 0.021383540000000003 +go_gc_duration_seconds_sum 56.12904785 +go_gc_duration_seconds_count 7476.0 +# HELP go_goroutines Number of goroutines that currently exist. +# TYPE go_goroutines gauge +go_goroutines 166.0 +# HELP prometheus_local_storage_indexing_batch_duration_milliseconds Quantiles for batch indexing duration in milliseconds. +# TYPE prometheus_local_storage_indexing_batch_duration_milliseconds summary +prometheus_local_storage_indexing_batch_duration_milliseconds{quantile="0.5"} NaN +prometheus_local_storage_indexing_batch_duration_milliseconds{quantile="0.9"} NaN +prometheus_local_storage_indexing_batch_duration_milliseconds{quantile="0.99"} NaN +prometheus_local_storage_indexing_batch_duration_milliseconds_sum 871.5665949999999 +prometheus_local_storage_indexing_batch_duration_milliseconds_count 229.0 +# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds. +# TYPE process_cpu_seconds_total counter +process_cpu_seconds_total 29323.4 +# HELP process_virtual_memory_bytes Virtual memory size in bytes. +# TYPE process_virtual_memory_bytes gauge +process_virtual_memory_bytes 2478268416.0 +# HELP prometheus_build_info A metric with a constant '1' value labeled by version, revision, and branch from which Prometheus was built. +# TYPE prometheus_build_info gauge +prometheus_build_info{branch="HEAD",revision="ef176e5",version="0.16.0rc1"} 1.0 +# HELP prometheus_local_storage_chunk_ops_total The total number of chunk operations by their type. +# TYPE prometheus_local_storage_chunk_ops_total counter +prometheus_local_storage_chunk_ops_total{type="clone"} 28.0 +prometheus_local_storage_chunk_ops_total{type="create"} 997844.0 +prometheus_local_storage_chunk_ops_total{type="drop"} 1345758.0 +prometheus_local_storage_chunk_ops_total{type="load"} 1641.0 +prometheus_local_storage_chunk_ops_total{type="persist"} 981408.0 +prometheus_local_storage_chunk_ops_total{type="pin"} 32662.0 +prometheus_local_storage_chunk_ops_total{type="transcode"} 980180.0 +prometheus_local_storage_chunk_ops_total{type="unpin"} 32662.0 +""" + families = list(text_string_to_metric_families(text)) + + class TextCollector(object): + def collect(self): + return families + + + registry = CollectorRegistry() + registry.register(TextCollector()) + self.assertEqual(text.encode('utf-8'), generate_latest(registry)) + + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_process_collector.py b/tests/test_process_collector.py new file mode 100644 index 0000000..6455d43 --- /dev/null +++ b/tests/test_process_collector.py @@ -0,0 +1,62 @@ +from __future__ import unicode_literals +import os +import unittest + + +from prometheus_client import CollectorRegistry, ProcessCollector + +class TestProcessCollector(unittest.TestCase): + def setUp(self): + self.registry = CollectorRegistry() + self.test_proc = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'proc') + + def test_working(self): + collector = ProcessCollector(proc=self.test_proc, pid=lambda: 26231, registry=self.registry) + collector._ticks = 100 + + self.assertEqual(17.21, self.registry.get_sample_value('process_cpu_seconds_total')) + self.assertEqual(56274944.0, self.registry.get_sample_value('process_virtual_memory_bytes')) + self.assertEqual(8114176, self.registry.get_sample_value('process_resident_memory_bytes')) + self.assertEqual(1418184099.75, self.registry.get_sample_value('process_start_time_seconds')) + self.assertEqual(2048.0, self.registry.get_sample_value('process_max_fds')) + self.assertEqual(5.0, self.registry.get_sample_value('process_open_fds')) + self.assertEqual(None, self.registry.get_sample_value('process_fake_namespace')) + + def test_namespace(self): + collector = ProcessCollector(proc=self.test_proc, pid=lambda: 26231, registry=self.registry, namespace='n') + collector._ticks = 100 + + self.assertEqual(17.21, self.registry.get_sample_value('n_process_cpu_seconds_total')) + self.assertEqual(56274944.0, self.registry.get_sample_value('n_process_virtual_memory_bytes')) + self.assertEqual(8114176, self.registry.get_sample_value('n_process_resident_memory_bytes')) + self.assertEqual(1418184099.75, self.registry.get_sample_value('n_process_start_time_seconds')) + self.assertEqual(2048.0, self.registry.get_sample_value('n_process_max_fds')) + self.assertEqual(5.0, self.registry.get_sample_value('n_process_open_fds')) + self.assertEqual(None, self.registry.get_sample_value('process_cpu_seconds_total')) + + def test_working_584(self): + collector = ProcessCollector(proc=self.test_proc, pid=lambda: "584\n", registry=self.registry) + collector._ticks = 100 + + self.assertEqual(0.0, self.registry.get_sample_value('process_cpu_seconds_total')) + self.assertEqual(10395648.0, self.registry.get_sample_value('process_virtual_memory_bytes')) + self.assertEqual(634880, self.registry.get_sample_value('process_resident_memory_bytes')) + self.assertEqual(1418291667.75, self.registry.get_sample_value('process_start_time_seconds')) + self.assertEqual(None, self.registry.get_sample_value('process_max_fds')) + self.assertEqual(None, self.registry.get_sample_value('process_open_fds')) + + def test_working_fake_pid(self): + collector = ProcessCollector(proc=self.test_proc, pid=lambda: 123, registry=self.registry) + collector._ticks = 100 + + self.assertEqual(None, self.registry.get_sample_value('process_cpu_seconds_total')) + self.assertEqual(None, self.registry.get_sample_value('process_virtual_memory_bytes')) + self.assertEqual(None, self.registry.get_sample_value('process_resident_memory_bytes')) + self.assertEqual(None, self.registry.get_sample_value('process_start_time_seconds')) + self.assertEqual(None, self.registry.get_sample_value('process_max_fds')) + self.assertEqual(None, self.registry.get_sample_value('process_open_fds')) + self.assertEqual(None, self.registry.get_sample_value('process_fake_namespace')) + + +if __name__ == '__main__': + unittest.main() |