|
4 | 4 | import time |
5 | 5 | import unittest |
6 | 6 |
|
7 | | - |
8 | | -from prometheus_client import Gauge, Counter, Summary, Histogram, Metric |
9 | | -from prometheus_client import CollectorRegistry, generate_latest, ProcessCollector |
10 | | -from prometheus_client import push_to_gateway, pushadd_to_gateway, delete_from_gateway |
11 | | -from prometheus_client import CONTENT_TYPE_LATEST, instance_ip_grouping_key |
12 | | - |
13 | | -try: |
14 | | - from BaseHTTPServer import BaseHTTPRequestHandler |
15 | | - from BaseHTTPServer import HTTPServer |
16 | | -except ImportError: |
17 | | - # Python 3 |
18 | | - from http.server import BaseHTTPRequestHandler |
19 | | - from http.server import HTTPServer |
20 | | - |
21 | | - |
| 7 | +from prometheus_client.core import * |
22 | 8 |
|
23 | 9 | class TestCounter(unittest.TestCase): |
24 | 10 | def setUp(self): |
@@ -304,178 +290,83 @@ def test_invalid_names_raise(self): |
304 | 290 | self.assertRaises(ValueError, Summary, 'c', '', labelnames=['quantile']) |
305 | 291 |
|
306 | 292 |
|
307 | | -class TestGenerateText(unittest.TestCase): |
| 293 | +class TestMetricFamilies(unittest.TestCase): |
308 | 294 | def setUp(self): |
309 | 295 | self.registry = CollectorRegistry() |
310 | 296 |
|
| 297 | + def custom_collector(self, metric_family): |
| 298 | + class CustomCollector(object): |
| 299 | + def collect(self): |
| 300 | + return [metric_family] |
| 301 | + self.registry.register(CustomCollector()) |
| 302 | + |
311 | 303 | def test_counter(self): |
312 | | - c = Counter('cc', 'A counter', registry=self.registry) |
313 | | - c.inc() |
314 | | - self.assertEqual(b'# HELP cc A counter\n# TYPE cc counter\ncc 1.0\n', generate_latest(self.registry)) |
| 304 | + self.custom_collector(CounterMetricFamily('c', 'help', value=1)) |
| 305 | + self.assertEqual(1, self.registry.get_sample_value('c', {})) |
| 306 | + |
| 307 | + def test_counter_labels(self): |
| 308 | + cmf = CounterMetricFamily('c', 'help', labels=['a', 'c']) |
| 309 | + cmf.add_metric(['b', 'd'], 2) |
| 310 | + self.custom_collector(cmf) |
| 311 | + self.assertEqual(2, self.registry.get_sample_value('c', {'a': 'b', 'c': 'd'})) |
315 | 312 |
|
316 | 313 | def test_gauge(self): |
317 | | - g = Gauge('gg', 'A gauge', registry=self.registry) |
318 | | - g.set(17) |
319 | | - self.assertEqual(b'# HELP gg A gauge\n# TYPE gg gauge\ngg 17.0\n', generate_latest(self.registry)) |
| 314 | + self.custom_collector(GaugeMetricFamily('g', 'help', value=1)) |
| 315 | + self.assertEqual(1, self.registry.get_sample_value('g', {})) |
| 316 | + |
| 317 | + def test_gauge_labels(self): |
| 318 | + cmf = GaugeMetricFamily('g', 'help', labels=['a']) |
| 319 | + cmf.add_metric(['b'], 2) |
| 320 | + self.custom_collector(cmf) |
| 321 | + self.assertEqual(2, self.registry.get_sample_value('g', {'a':'b'})) |
320 | 322 |
|
321 | 323 | def test_summary(self): |
322 | | - s = Summary('ss', 'A summary', ['a', 'b'], registry=self.registry) |
323 | | - s.labels('c', 'd').observe(17) |
324 | | - 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)) |
325 | | - |
326 | | - def test_unicode(self): |
327 | | - c = Counter('cc', '\u4500', ['l'], registry=self.registry) |
328 | | - c.labels('\u4500').inc() |
329 | | - self.assertEqual(b'# HELP cc \xe4\x94\x80\n# TYPE cc counter\ncc{l="\xe4\x94\x80"} 1.0\n', generate_latest(self.registry)) |
330 | | - |
331 | | - def test_escaping(self): |
332 | | - c = Counter('cc', 'A\ncount\\er', ['a'], registry=self.registry) |
333 | | - c.labels('\\x\n"').inc(1) |
334 | | - self.assertEqual(b'# HELP cc A\\ncount\\\\er\n# TYPE cc counter\ncc{a="\\\\x\\n\\""} 1.0\n', generate_latest(self.registry)) |
335 | | - |
336 | | - def test_nonnumber(self): |
337 | | - class MyNumber(): |
338 | | - def __repr__(self): |
339 | | - return "MyNumber(123)" |
340 | | - def __float__(self): |
341 | | - return 123.0 |
342 | | - class MyCollector(): |
343 | | - def collect(self): |
344 | | - metric = Metric("nonnumber", "Non number", 'untyped') |
345 | | - metric.add_sample("nonnumber", {}, MyNumber()) |
346 | | - yield metric |
347 | | - self.registry.register(MyCollector()) |
348 | | - self.assertEqual(b'# HELP nonnumber Non number\n# TYPE nonnumber untyped\nnonnumber 123.0\n', generate_latest(self.registry)) |
| 324 | + self.custom_collector(SummaryMetricFamily('s', 'help', count_value=1, sum_value=2)) |
| 325 | + self.assertEqual(1, self.registry.get_sample_value('s_count', {})) |
| 326 | + self.assertEqual(2, self.registry.get_sample_value('s_sum', {})) |
349 | 327 |
|
| 328 | + def test_summary_labels(self): |
| 329 | + cmf = SummaryMetricFamily('s', 'help', labels=['a']) |
| 330 | + cmf.add_metric(['b'], count_value=1, sum_value=2) |
| 331 | + self.custom_collector(cmf) |
| 332 | + self.assertEqual(1, self.registry.get_sample_value('s_count', {'a': 'b'})) |
| 333 | + self.assertEqual(2, self.registry.get_sample_value('s_sum', {'a': 'b'})) |
350 | 334 |
|
351 | | -class TestProcessCollector(unittest.TestCase): |
352 | | - def setUp(self): |
353 | | - self.registry = CollectorRegistry() |
354 | | - self.test_proc = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'proc') |
355 | | - |
356 | | - def test_working(self): |
357 | | - collector = ProcessCollector(proc=self.test_proc, pid=lambda: 26231, registry=self.registry) |
358 | | - collector._ticks = 100 |
359 | | - |
360 | | - self.assertEqual(17.21, self.registry.get_sample_value('process_cpu_seconds_total')) |
361 | | - self.assertEqual(56274944.0, self.registry.get_sample_value('process_virtual_memory_bytes')) |
362 | | - self.assertEqual(8114176, self.registry.get_sample_value('process_resident_memory_bytes')) |
363 | | - self.assertEqual(1418184099.75, self.registry.get_sample_value('process_start_time_seconds')) |
364 | | - self.assertEqual(2048.0, self.registry.get_sample_value('process_max_fds')) |
365 | | - self.assertEqual(5.0, self.registry.get_sample_value('process_open_fds')) |
366 | | - self.assertEqual(None, self.registry.get_sample_value('process_fake_namespace')) |
367 | | - |
368 | | - def test_namespace(self): |
369 | | - collector = ProcessCollector(proc=self.test_proc, pid=lambda: 26231, registry=self.registry, namespace='n') |
370 | | - collector._ticks = 100 |
371 | | - |
372 | | - self.assertEqual(17.21, self.registry.get_sample_value('n_process_cpu_seconds_total')) |
373 | | - self.assertEqual(56274944.0, self.registry.get_sample_value('n_process_virtual_memory_bytes')) |
374 | | - self.assertEqual(8114176, self.registry.get_sample_value('n_process_resident_memory_bytes')) |
375 | | - self.assertEqual(1418184099.75, self.registry.get_sample_value('n_process_start_time_seconds')) |
376 | | - self.assertEqual(2048.0, self.registry.get_sample_value('n_process_max_fds')) |
377 | | - self.assertEqual(5.0, self.registry.get_sample_value('n_process_open_fds')) |
378 | | - self.assertEqual(None, self.registry.get_sample_value('process_cpu_seconds_total')) |
379 | | - |
380 | | - def test_working_584(self): |
381 | | - collector = ProcessCollector(proc=self.test_proc, pid=lambda: "584\n", registry=self.registry) |
382 | | - collector._ticks = 100 |
383 | | - |
384 | | - self.assertEqual(0.0, self.registry.get_sample_value('process_cpu_seconds_total')) |
385 | | - self.assertEqual(10395648.0, self.registry.get_sample_value('process_virtual_memory_bytes')) |
386 | | - self.assertEqual(634880, self.registry.get_sample_value('process_resident_memory_bytes')) |
387 | | - self.assertEqual(1418291667.75, self.registry.get_sample_value('process_start_time_seconds')) |
388 | | - self.assertEqual(None, self.registry.get_sample_value('process_max_fds')) |
389 | | - self.assertEqual(None, self.registry.get_sample_value('process_open_fds')) |
390 | | - |
391 | | - def test_working_fake_pid(self): |
392 | | - collector = ProcessCollector(proc=self.test_proc, pid=lambda: 123, registry=self.registry) |
393 | | - collector._ticks = 100 |
394 | | - |
395 | | - self.assertEqual(None, self.registry.get_sample_value('process_cpu_seconds_total')) |
396 | | - self.assertEqual(None, self.registry.get_sample_value('process_virtual_memory_bytes')) |
397 | | - self.assertEqual(None, self.registry.get_sample_value('process_resident_memory_bytes')) |
398 | | - self.assertEqual(None, self.registry.get_sample_value('process_start_time_seconds')) |
399 | | - self.assertEqual(None, self.registry.get_sample_value('process_max_fds')) |
400 | | - self.assertEqual(None, self.registry.get_sample_value('process_open_fds')) |
401 | | - self.assertEqual(None, self.registry.get_sample_value('process_fake_namespace')) |
402 | | - |
403 | | - |
404 | | -class TestPushGateway(unittest.TestCase): |
405 | | - def setUp(self): |
406 | | - self.registry = CollectorRegistry() |
407 | | - self.counter = Gauge('g', 'help', registry=self.registry) |
408 | | - self.requests = requests = [] |
409 | | - class TestHandler(BaseHTTPRequestHandler): |
410 | | - def do_PUT(self): |
411 | | - length = int(self.headers['content-length']) |
412 | | - requests.append((self, self.rfile.read(length))) |
413 | | - self.send_response(201) |
414 | | - self.end_headers() |
415 | | - |
416 | | - do_POST = do_PUT |
417 | | - do_DELETE = do_PUT |
418 | | - |
419 | | - httpd = HTTPServer(('', 0), TestHandler) |
420 | | - self.address = 'localhost:' + str(httpd.server_address[1]) |
421 | | - class TestServer(threading.Thread): |
422 | | - def run(self): |
423 | | - httpd.handle_request() |
424 | | - self.server = TestServer() |
425 | | - self.server.daemon = True |
426 | | - self.server.start() |
427 | | - |
428 | | - def test_push(self): |
429 | | - push_to_gateway(self.address, "my_job", self.registry) |
430 | | - self.assertEqual(self.requests[0][0].command, 'PUT') |
431 | | - self.assertEqual(self.requests[0][0].path, '/job/my_job') |
432 | | - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
433 | | - self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') |
434 | | - |
435 | | - def test_push_with_groupingkey(self): |
436 | | - push_to_gateway(self.address, "my_job", self.registry, {'a': 9}) |
437 | | - self.assertEqual(self.requests[0][0].command, 'PUT') |
438 | | - self.assertEqual(self.requests[0][0].path, '/job/my_job/a/9') |
439 | | - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
440 | | - self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') |
441 | | - |
442 | | - def test_push_with_complex_groupingkey(self): |
443 | | - push_to_gateway(self.address, "my_job", self.registry, {'a': 9, 'b': 'a/ z'}) |
444 | | - self.assertEqual(self.requests[0][0].command, 'PUT') |
445 | | - self.assertEqual(self.requests[0][0].path, '/job/my_job/a/9/b/a%2F+z') |
446 | | - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
447 | | - self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') |
448 | | - |
449 | | - def test_pushadd(self): |
450 | | - pushadd_to_gateway(self.address, "my_job", self.registry) |
451 | | - self.assertEqual(self.requests[0][0].command, 'POST') |
452 | | - self.assertEqual(self.requests[0][0].path, '/job/my_job') |
453 | | - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
454 | | - self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') |
455 | | - |
456 | | - def test_pushadd_with_groupingkey(self): |
457 | | - pushadd_to_gateway(self.address, "my_job", self.registry, {'a': 9}) |
458 | | - self.assertEqual(self.requests[0][0].command, 'POST') |
459 | | - self.assertEqual(self.requests[0][0].path, '/job/my_job/a/9') |
460 | | - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
461 | | - self.assertEqual(self.requests[0][1], b'# HELP g help\n# TYPE g gauge\ng 0.0\n') |
462 | | - |
463 | | - def test_delete(self): |
464 | | - delete_from_gateway(self.address, "my_job") |
465 | | - self.assertEqual(self.requests[0][0].command, 'DELETE') |
466 | | - self.assertEqual(self.requests[0][0].path, '/job/my_job') |
467 | | - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
468 | | - self.assertEqual(self.requests[0][1], b'') |
469 | | - |
470 | | - def test_delete_with_groupingkey(self): |
471 | | - delete_from_gateway(self.address, "my_job", {'a': 9}) |
472 | | - self.assertEqual(self.requests[0][0].command, 'DELETE') |
473 | | - self.assertEqual(self.requests[0][0].path, '/job/my_job/a/9') |
474 | | - self.assertEqual(self.requests[0][0].headers.get('content-type'), CONTENT_TYPE_LATEST) |
475 | | - self.assertEqual(self.requests[0][1], b'') |
476 | | - |
477 | | - def test_instance_ip_grouping_key(self): |
478 | | - self.assertTrue('' != instance_ip_grouping_key()['instance']) |
| 335 | + def test_histogram(self): |
| 336 | + self.custom_collector(HistogramMetricFamily('h', 'help', buckets=[('0', 1), ('+Inf', 2)], sum_value=3)) |
| 337 | + self.assertEqual(1, self.registry.get_sample_value('h_bucket', {'le': '0'})) |
| 338 | + self.assertEqual(2, self.registry.get_sample_value('h_bucket', {'le': '+Inf'})) |
| 339 | + self.assertEqual(2, self.registry.get_sample_value('h_count', {})) |
| 340 | + self.assertEqual(3, self.registry.get_sample_value('h_sum', {})) |
| 341 | + |
| 342 | + def test_histogram_labels(self): |
| 343 | + cmf = HistogramMetricFamily('h', 'help', labels=['a']) |
| 344 | + cmf.add_metric(['b'], buckets=[('0', 1), ('+Inf', 2)], sum_value=3) |
| 345 | + self.custom_collector(cmf) |
| 346 | + self.assertEqual(1, self.registry.get_sample_value('h_bucket', {'a': 'b', 'le': '0'})) |
| 347 | + self.assertEqual(2, self.registry.get_sample_value('h_bucket', {'a': 'b', 'le': '+Inf'})) |
| 348 | + self.assertEqual(2, self.registry.get_sample_value('h_count', {'a': 'b'})) |
| 349 | + self.assertEqual(3, self.registry.get_sample_value('h_sum', {'a': 'b'})) |
| 350 | + |
| 351 | + def test_bad_constructors(self): |
| 352 | + self.assertRaises(ValueError, CounterMetricFamily, 'c', 'help', value=1, labels=[]) |
| 353 | + self.assertRaises(ValueError, CounterMetricFamily, 'c', 'help', value=1, labels=['a']) |
| 354 | + |
| 355 | + self.assertRaises(ValueError, GaugeMetricFamily, 'g', 'help', value=1, labels=[]) |
| 356 | + self.assertRaises(ValueError, GaugeMetricFamily, 'g', 'help', value=1, labels=['a']) |
| 357 | + |
| 358 | + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', sum_value=1) |
| 359 | + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', count_value=1) |
| 360 | + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', count_value=1, labels=['a']) |
| 361 | + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', sum_value=1, labels=['a']) |
| 362 | + self.assertRaises(ValueError, SummaryMetricFamily, 's', 'help', count_value=1, sum_value=1, labels=['a']) |
| 363 | + |
| 364 | + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', sum_value=1) |
| 365 | + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', buckets={}) |
| 366 | + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', sum_value=1, labels=['a']) |
| 367 | + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', buckets={}, labels=['a']) |
| 368 | + self.assertRaises(ValueError, HistogramMetricFamily, 'h', 'help', buckets={}, sum_value=1, labels=['a']) |
| 369 | + self.assertRaises(KeyError, HistogramMetricFamily, 'h', 'help', buckets={}, sum_value=1) |
479 | 370 |
|
480 | 371 |
|
481 | 372 | if __name__ == '__main__': |
|
0 commit comments