2021-09-16 17:48:57 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Wikimedia\Tests\Metrics;
|
|
|
|
|
|
|
|
|
|
use PHPUnit\Framework\TestCase;
|
2021-10-22 19:50:07 +00:00
|
|
|
use Psr\Log\NullLogger;
|
2021-09-16 17:48:57 +00:00
|
|
|
use Wikimedia\Metrics\Exceptions\InvalidLabelsException;
|
|
|
|
|
use Wikimedia\Metrics\MetricsFactory;
|
|
|
|
|
|
|
|
|
|
/**
|
2022-11-01 18:47:15 +00:00
|
|
|
* @covers \Wikimedia\Metrics\Metrics\NullMetric
|
|
|
|
|
* @covers \Wikimedia\Metrics\Metrics\CounterMetric
|
|
|
|
|
* @covers \Wikimedia\Metrics\Metrics\GaugeMetric
|
|
|
|
|
* @covers \Wikimedia\Metrics\Metrics\TimingMetric
|
2021-10-22 19:50:07 +00:00
|
|
|
* @covers \Wikimedia\Metrics\MetricUtils
|
2021-09-16 17:48:57 +00:00
|
|
|
*/
|
|
|
|
|
class MetricTest extends TestCase {
|
|
|
|
|
|
|
|
|
|
public const FORMATS = [ 'statsd', 'dogstatsd' ];
|
|
|
|
|
|
|
|
|
|
public const TYPES = [ 'counter', 'gauge', 'timing' ];
|
|
|
|
|
|
|
|
|
|
public const TESTS = [
|
|
|
|
|
'basic' => [
|
|
|
|
|
'config' => [
|
|
|
|
|
'name' => 'test.unit',
|
2022-11-01 17:51:22 +00:00
|
|
|
'component' => 'testComponent',
|
2021-09-16 17:48:57 +00:00
|
|
|
'labels' => [],
|
|
|
|
|
],
|
|
|
|
|
'value' => 2,
|
|
|
|
|
'labels' => []
|
|
|
|
|
],
|
|
|
|
|
'invalidLabel' => [
|
|
|
|
|
'config' => [
|
|
|
|
|
'name' => 'test.unit',
|
2022-11-01 17:51:22 +00:00
|
|
|
'component' => 'testComponent',
|
2021-09-16 17:48:57 +00:00
|
|
|
'labels' => [ 'x' ]
|
|
|
|
|
],
|
|
|
|
|
'value' => 2,
|
|
|
|
|
'labels' => [ ': labelOne ' ]
|
|
|
|
|
],
|
|
|
|
|
'oneLabel' => [
|
|
|
|
|
'config' => [
|
|
|
|
|
'name' => 'test.unit',
|
2022-11-01 17:51:22 +00:00
|
|
|
'component' => 'testComponent',
|
2021-09-16 17:48:57 +00:00
|
|
|
'labels' => [ 'x' ]
|
|
|
|
|
],
|
|
|
|
|
'value' => 2,
|
|
|
|
|
'labels' => [ 'labelOne' ]
|
|
|
|
|
],
|
|
|
|
|
'multiLabel' => [
|
|
|
|
|
'config' => [
|
|
|
|
|
'name' => 'test.unit',
|
2022-11-01 17:51:22 +00:00
|
|
|
'component' => 'testComponent',
|
2021-09-16 17:48:57 +00:00
|
|
|
'labels' => [ 'x', 'y' ]
|
|
|
|
|
],
|
|
|
|
|
'value' => 2,
|
|
|
|
|
'labels' => [ 'labelOne', 'labelTwo' ]
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
public const RESULTS = [
|
2022-11-01 17:51:22 +00:00
|
|
|
'statsd.counter.basic' => [ 'mediawiki.testComponent.test_unit:2|c' ],
|
|
|
|
|
'statsd.counter.invalidLabel' => [ 'mediawiki.testComponent.test_unit.labelOne:2|c' ],
|
|
|
|
|
'statsd.counter.oneLabel' => [ 'mediawiki.testComponent.test_unit.labelOne:2|c' ],
|
|
|
|
|
'statsd.counter.multiLabel' => [ 'mediawiki.testComponent.test_unit.labelOne.labelTwo:2|c' ],
|
|
|
|
|
'statsd.gauge.basic' => [ 'mediawiki.testComponent.test_unit:2|g' ],
|
|
|
|
|
'statsd.gauge.invalidLabel' => [ 'mediawiki.testComponent.test_unit.labelOne:2|g' ],
|
|
|
|
|
'statsd.gauge.oneLabel' => [ 'mediawiki.testComponent.test_unit.labelOne:2|g' ],
|
|
|
|
|
'statsd.gauge.multiLabel' => [ 'mediawiki.testComponent.test_unit.labelOne.labelTwo:2|g' ],
|
|
|
|
|
'statsd.timing.basic' => [ 'mediawiki.testComponent.test_unit:2|ms' ],
|
|
|
|
|
'statsd.timing.invalidLabel' => [ 'mediawiki.testComponent.test_unit.labelOne:2|ms' ],
|
|
|
|
|
'statsd.timing.oneLabel' => [ 'mediawiki.testComponent.test_unit.labelOne:2|ms' ],
|
|
|
|
|
'statsd.timing.multiLabel' => [ 'mediawiki.testComponent.test_unit.labelOne.labelTwo:2|ms' ],
|
2021-09-16 17:48:57 +00:00
|
|
|
|
2022-11-01 17:51:22 +00:00
|
|
|
'dogstatsd.counter.basic' => [ 'mediawiki.testComponent.test_unit:2|c' ],
|
|
|
|
|
'dogstatsd.counter.invalidLabel' => [ 'mediawiki.testComponent.test_unit:2|c|#x:labelOne' ],
|
|
|
|
|
'dogstatsd.counter.oneLabel' => [ 'mediawiki.testComponent.test_unit:2|c|#x:labelOne' ],
|
2021-09-16 17:48:57 +00:00
|
|
|
'dogstatsd.counter.multiLabel' => [
|
2022-11-01 17:51:22 +00:00
|
|
|
'mediawiki.testComponent.test_unit:2|c|#x:labelOne,y:labelTwo' ],
|
|
|
|
|
'dogstatsd.gauge.basic' => [ 'mediawiki.testComponent.test_unit:2|g' ],
|
|
|
|
|
'dogstatsd.gauge.invalidLabel' => [ 'mediawiki.testComponent.test_unit:2|g|#x:labelOne' ],
|
|
|
|
|
'dogstatsd.gauge.oneLabel' => [ 'mediawiki.testComponent.test_unit:2|g|#x:labelOne' ],
|
2021-09-16 17:48:57 +00:00
|
|
|
'dogstatsd.gauge.multiLabel' => [
|
2022-11-01 17:51:22 +00:00
|
|
|
'mediawiki.testComponent.test_unit:2|g|#x:labelOne,y:labelTwo' ],
|
|
|
|
|
'dogstatsd.timing.basic' => [ 'mediawiki.testComponent.test_unit:2|ms' ],
|
|
|
|
|
'dogstatsd.timing.invalidLabel' => [ 'mediawiki.testComponent.test_unit:2|ms|#x:labelOne' ],
|
|
|
|
|
'dogstatsd.timing.oneLabel' => [ 'mediawiki.testComponent.test_unit:2|ms|#x:labelOne' ],
|
2021-09-16 17:48:57 +00:00
|
|
|
'dogstatsd.timing.multiLabel' => [
|
2022-11-01 17:51:22 +00:00
|
|
|
'mediawiki.testComponent.test_unit:2|ms|#x:labelOne,y:labelTwo' ],
|
2021-09-16 17:48:57 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
public function testValidateLabels() {
|
|
|
|
|
$this->expectException( InvalidLabelsException::class );
|
2021-10-22 19:50:07 +00:00
|
|
|
$m = new MetricsFactory( [ 'prefix' => 'mediawiki' ], new NullLogger );
|
2021-09-16 17:48:57 +00:00
|
|
|
$counter = $m->getCounter( [
|
|
|
|
|
'name' => 'test',
|
2022-11-01 17:51:22 +00:00
|
|
|
'component' => 'testComponent',
|
2021-09-16 17:48:57 +00:00
|
|
|
'labels' => [ 'a', 'b' ]
|
|
|
|
|
] );
|
|
|
|
|
$counter->increment( [ 'a' ] );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function handleTest( $test, $type, $format, $metricsFactory ) {
|
|
|
|
|
$config = self::TESTS[$test];
|
|
|
|
|
// null target destroys cache
|
|
|
|
|
$metricsFactory->flush();
|
|
|
|
|
$name = implode( '.', [ $format, $type, $test ] );
|
|
|
|
|
$this->setName( $name );
|
|
|
|
|
switch ( $type ) {
|
|
|
|
|
case 'counter':
|
|
|
|
|
$metric = $metricsFactory->getCounter( $config['config'] );
|
|
|
|
|
$metric->incrementBy( $config['value'], $config['labels'] );
|
|
|
|
|
break;
|
|
|
|
|
case 'gauge':
|
|
|
|
|
$metric = $metricsFactory->getGauge( self::TESTS[$test]['config'] );
|
|
|
|
|
$metric->set( $config['value'], $config['labels'] );
|
|
|
|
|
break;
|
|
|
|
|
case 'timing':
|
|
|
|
|
$metric = $metricsFactory->getTiming( self::TESTS[$test]['config'] );
|
|
|
|
|
$metric->observe( $config['value'], $config['labels'] );
|
|
|
|
|
break;
|
|
|
|
|
case 'default':
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
$this->assertEquals( self::RESULTS[$name], $metric->render() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function handleType( $type, $format, $metricsFactory ) {
|
|
|
|
|
foreach ( array_keys( self::TESTS ) as $test ) {
|
|
|
|
|
$this->handleTest( $test, $type, $format, $metricsFactory );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function handleFormat( $format ) {
|
2021-10-22 19:50:07 +00:00
|
|
|
$metricsFactory = new MetricsFactory( [ 'prefix' => 'mediawiki', 'format' => $format ], new NullLogger );
|
2021-09-16 17:48:57 +00:00
|
|
|
foreach ( self::TYPES as $type ) {
|
|
|
|
|
$this->handleType( $type, $format, $metricsFactory );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testMetrics() {
|
|
|
|
|
foreach ( self::FORMATS as $format ) {
|
|
|
|
|
$this->handleFormat( $format );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testSampledMetrics() {
|
|
|
|
|
$rounds = 10;
|
|
|
|
|
foreach ( self::FORMATS as $format ) {
|
2021-10-22 19:50:07 +00:00
|
|
|
$m = new MetricsFactory( [ 'prefix' => $format, 'format' => $format ], new NullLogger );
|
2021-09-16 17:48:57 +00:00
|
|
|
$ten_percent = $m->getCounter(
|
|
|
|
|
[
|
|
|
|
|
'name' => 'test.sampled.ten',
|
2022-11-01 17:51:22 +00:00
|
|
|
'component' => 'counter',
|
2021-09-16 17:48:57 +00:00
|
|
|
'sampleRate' => 0.1
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
$hundred_percent = $m->getCounter(
|
|
|
|
|
[
|
|
|
|
|
'name' => 'test.sampled.hundred',
|
2022-11-01 17:51:22 +00:00
|
|
|
'component' => 'counter',
|
2021-09-16 17:48:57 +00:00
|
|
|
'sampleRate' => 1.0
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
$zero_percent = $m->getCounter(
|
|
|
|
|
[
|
|
|
|
|
'name' => 'test.sampled.zero',
|
2022-11-01 17:51:22 +00:00
|
|
|
'component' => 'counter',
|
2021-09-16 17:48:57 +00:00
|
|
|
'sampleRate' => 0.0
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
for ( $i = 0; $i < $rounds; $i++ ) {
|
|
|
|
|
$ten_percent->increment();
|
|
|
|
|
$hundred_percent->increment();
|
|
|
|
|
$zero_percent->increment();
|
|
|
|
|
}
|
|
|
|
|
$this->assertTrue( count( $ten_percent->render() ) <= $rounds ); // random
|
|
|
|
|
$this->assertEquals( count( $hundred_percent->render() ), $rounds );
|
|
|
|
|
$this->assertEquals( count( $zero_percent->render() ), 0 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|