diff options
author | Igor Scheller <igor.scheller@igorshp.de> | 2018-12-18 02:23:44 +0100 |
---|---|---|
committer | msquare <msquare@notrademark.de> | 2018-12-19 22:36:42 +0100 |
commit | c5621b82cfeddee23b81871a53035fde747f73a9 (patch) | |
tree | 36e91622ac463011bd2b45f552d837a1abfb56ba /tests/Unit/Controllers/Metrics | |
parent | 3c8d0eeb440b8c263686ba81df7be87290ad9695 (diff) |
Implemented /metrics endpoint and reimplemented /stats
closes #418 (/metrics endpoint)
Usage:
```yaml
scrape_configs:
- job_name: 'engelsystem'
static_configs:
- targets: ['engelsystem.example.com:80']
```
Diffstat (limited to 'tests/Unit/Controllers/Metrics')
-rw-r--r-- | tests/Unit/Controllers/Metrics/ControllerTest.php | 165 | ||||
-rw-r--r-- | tests/Unit/Controllers/Metrics/MetricsEngineTest.php | 69 | ||||
-rw-r--r-- | tests/Unit/Controllers/Metrics/StatsTest.php | 74 |
3 files changed, 308 insertions, 0 deletions
diff --git a/tests/Unit/Controllers/Metrics/ControllerTest.php b/tests/Unit/Controllers/Metrics/ControllerTest.php new file mode 100644 index 00000000..013a3352 --- /dev/null +++ b/tests/Unit/Controllers/Metrics/ControllerTest.php @@ -0,0 +1,165 @@ +<?php + +namespace Engelsystem\Test\Unit\Controllers\Metrics; + +use Engelsystem\Config\Config; +use Engelsystem\Controllers\Metrics\Controller; +use Engelsystem\Controllers\Metrics\MetricsEngine; +use Engelsystem\Controllers\Metrics\Stats; +use Engelsystem\Http\Exceptions\HttpForbidden; +use Engelsystem\Http\Request; +use Engelsystem\Http\Response; +use Engelsystem\Test\Unit\TestCase; +use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Component\HttpFoundation\ServerBag; + +class ControllerTest extends TestCase +{ + /** + * @covers \Engelsystem\Controllers\Metrics\Controller::__construct + * @covers \Engelsystem\Controllers\Metrics\Controller::metrics + */ + public function testMetrics() + { + /** @var Response|MockObject $response */ + /** @var Request|MockObject $request */ + /** @var MetricsEngine|MockObject $engine */ + /** @var Stats|MockObject $stats */ + /** @var Config $config */ + list($response, $request, $engine, $stats, $config) = $this->getMocks(); + + $request->server = new ServerBag(); + $request->server->set('REQUEST_TIME_FLOAT', 0.0123456789); + + $engine->expects($this->once()) + ->method('get') + ->willReturnCallback(function ($path, $data) use ($response) { + $this->assertEquals('/metrics', $path); + $this->assertArrayHasKey('users', $data); + $this->assertArrayHasKey('users_working', $data); + $this->assertArrayHasKey('work_seconds', $data); + $this->assertArrayHasKey('registration_enabled', $data); + $this->assertArrayHasKey('scrape_duration_seconds', $data); + + return 'metrics return'; + }); + + $response->expects($this->once()) + ->method('withHeader') + ->with('Content-Type', 'text/plain; version=0.0.4') + ->willReturn($response); + $response->expects($this->once()) + ->method('withContent') + ->with('metrics return') + ->willReturn($response); + + $stats->expects($this->exactly(2)) + ->method('arrivedUsers') + ->withConsecutive([false], [true]) + ->willReturnOnConsecutiveCalls(7, 43); + $stats->expects($this->exactly(2)) + ->method('currentlyWorkingUsers') + ->withConsecutive([false], [true]) + ->willReturnOnConsecutiveCalls(10, 1); + $stats->expects($this->exactly(3)) + ->method('workSeconds') + ->withConsecutive([true, false], [false, false], [null, true]) + ->willReturnOnConsecutiveCalls(60 * 37, 60 * 251, 60 * 3); + $this->setExpects($stats, 'newUsers', null, 9); + + $config->set('registration_enabled', 1); + + $controller = new Controller($response, $engine, $config, $request, $stats); + $controller->metrics(); + } + + /** + * @covers \Engelsystem\Controllers\Metrics\Controller::stats + * @covers \Engelsystem\Controllers\Metrics\Controller::checkAuth + */ + public function testStats() + { + /** @var Response|MockObject $response */ + /** @var Request|MockObject $request */ + /** @var MetricsEngine|MockObject $engine */ + /** @var Stats|MockObject $stats */ + /** @var Config $config */ + list($response, $request, $engine, $stats, $config) = $this->getMocks(); + + $response->expects($this->once()) + ->method('withHeader') + ->with('Content-Type', 'application/json') + ->willReturn($response); + $response->expects($this->once()) + ->method('withContent') + ->with(json_encode([ + 'user_count' => 13, + 'arrived_user_count' => 10, + 'done_work_hours' => 99, + 'users_in_action' => 5 + ])) + ->willReturn($response); + + $request->expects($this->once()) + ->method('get') + ->with('api_key') + ->willReturn('ApiKey987'); + + $config->set('api_key', 'ApiKey987'); + + $stats->expects($this->once()) + ->method('workSeconds') + ->with(true) + ->willReturn(60 * 60 * 99.47); + $this->setExpects($stats, 'newUsers', null, 3); + $this->setExpects($stats, 'arrivedUsers', null, 10, $this->exactly(2)); + $this->setExpects($stats, 'currentlyWorkingUsers', null, 5); + + $controller = new Controller($response, $engine, $config, $request, $stats); + $controller->stats(); + } + + /** + * @covers \Engelsystem\Controllers\Metrics\Controller::checkAuth + */ + public function testCheckAuth() + { + /** @var Response|MockObject $response */ + /** @var Request|MockObject $request */ + /** @var MetricsEngine|MockObject $engine */ + /** @var Stats|MockObject $stats */ + /** @var Config $config */ + list($response, $request, $engine, $stats, $config) = $this->getMocks(); + + $request->expects($this->once()) + ->method('get') + ->with('api_key') + ->willReturn('LoremIpsum!'); + + $config->set('api_key', 'fooBar!'); + + $controller = new Controller($response, $engine, $config, $request, $stats); + + $this->expectException(HttpForbidden::class); + $this->expectExceptionMessage(json_encode(['error' => 'The api_key is invalid'])); + $controller->stats(); + } + + /** + * @return array + */ + protected function getMocks(): array + { + /** @var Response|MockObject $response */ + $response = $this->createMock(Response::class); + /** @var Request|MockObject $request */ + $request = $this->createMock(Request::class); + /** @var MetricsEngine|MockObject $engine */ + $engine = $this->createMock(MetricsEngine::class); + /** @var Stats|MockObject $stats */ + $stats = $this->createMock(Stats::class); + $config = new Config(); + + return array($response, $request, $engine, $stats, $config); + } +} diff --git a/tests/Unit/Controllers/Metrics/MetricsEngineTest.php b/tests/Unit/Controllers/Metrics/MetricsEngineTest.php new file mode 100644 index 00000000..b810b10a --- /dev/null +++ b/tests/Unit/Controllers/Metrics/MetricsEngineTest.php @@ -0,0 +1,69 @@ +<?php + +namespace Engelsystem\Test\Unit\Controllers\Metrics; + +use Engelsystem\Controllers\Metrics\MetricsEngine; +use Engelsystem\Test\Unit\TestCase; + +class MetricsEngineTest extends TestCase +{ + /** + * @covers \Engelsystem\Controllers\Metrics\MetricsEngine::get + * @covers \Engelsystem\Controllers\Metrics\MetricsEngine::formatData + * @covers \Engelsystem\Controllers\Metrics\MetricsEngine::renderLabels + * @covers \Engelsystem\Controllers\Metrics\MetricsEngine::renderValue + * @covers \Engelsystem\Controllers\Metrics\MetricsEngine::formatValue + * @covers \Engelsystem\Controllers\Metrics\MetricsEngine::escape + */ + public function testGet() + { + $engine = new MetricsEngine(); + + $this->assertEquals('', $engine->get('/metrics')); + + $this->assertEquals('engelsystem_users 13', $engine->get('/metrics', ['users' => 13])); + + $this->assertEquals('engelsystem_bool_val 0', $engine->get('/metrics', ['bool_val' => false])); + + $this->assertEquals('# Lorem \n Ipsum', $engine->get('/metrics', ["Lorem \n Ipsum"])); + + $this->assertEquals( + 'engelsystem_foo{lorem="ip\\\\sum"} \\"lorem\\n\\\\ipsum\\"', + $engine->get('/metrics', [ + 'foo' => ['labels' => ['lorem' => 'ip\\sum'], 'value' => "\"lorem\n\\ipsum\""] + ]) + ); + + $this->assertEquals( + 'engelsystem_foo_count{bar="14"} 42', + $engine->get('/metrics', ['foo_count' => ['labels' => ['bar' => 14], 'value' => 42],]) + ); + + $this->assertEquals( + 'engelsystem_lorem{test="123"} NaN' . "\n" . 'engelsystem_lorem{test="456"} 999.99', + $engine->get('/metrics', [ + 'lorem' => [ + ['labels' => ['test' => 123], 'value' => 'NaN'], + ['labels' => ['test' => 456], 'value' => 999.99], + ], + ]) + ); + + $this->assertEquals( + "# HELP engelsystem_test Some help\\n text\n# TYPE engelsystem_test counter\nengelsystem_test 99", + $engine->get('/metrics', ['test' => ['help' => "Some help\n text", 'type' => 'counter', 'value' => 99]]) + ); + } + + /** + * @covers \Engelsystem\Controllers\Metrics\MetricsEngine::canRender + */ + public function testCanRender() + { + $engine = new MetricsEngine(); + + $this->assertFalse($engine->canRender('/')); + $this->assertFalse($engine->canRender('/metrics.foo')); + $this->assertTrue($engine->canRender('/metrics')); + } +} diff --git a/tests/Unit/Controllers/Metrics/StatsTest.php b/tests/Unit/Controllers/Metrics/StatsTest.php new file mode 100644 index 00000000..1618b99b --- /dev/null +++ b/tests/Unit/Controllers/Metrics/StatsTest.php @@ -0,0 +1,74 @@ +<?php + +namespace Engelsystem\Test\Unit\Controllers\Metrics; + +use Engelsystem\Controllers\Metrics\Stats; +use Engelsystem\Models\User\State; +use Engelsystem\Models\User\User; +use Engelsystem\Test\Unit\HasDatabase; +use Engelsystem\Test\Unit\TestCase; +use Illuminate\Support\Str; + +class StatsTest extends TestCase +{ + use HasDatabase; + + /** + * @covers \Engelsystem\Controllers\Metrics\Stats::newUsers + * @covers \Engelsystem\Controllers\Metrics\Stats::getQuery + * @covers \Engelsystem\Controllers\Metrics\Stats::__construct + */ + public function testNewUsers() + { + $this->initDatabase(); + $this->addUsers(); + + $stats = new Stats($this->database); + $this->assertEquals(2, $stats->newUsers()); + } + + /** + * @covers \Engelsystem\Controllers\Metrics\Stats::arrivedUsers + */ + public function testArrivedUsers() + { + $this->initDatabase(); + $this->addUsers(); + + $stats = new Stats($this->database); + $this->assertEquals(3, $stats->arrivedUsers()); + } + + /** + * Add some example users + */ + protected function addUsers() + { + $this->addUser(); + $this->addUser(); + $this->addUser(['arrived' => 1]); + $this->addUser(['arrived' => 1, 'active' => 1]); + $this->addUser(['arrived' => 1, 'active' => 1]); + } + + /** + * @param array $state + */ + protected function addUser(array $state = []) + { + $name = 'user_' . Str::random(5); + + $user = new User([ + 'name' => $name, + 'password' => '', + 'email' => $name . '@engel.example.com', + 'api_key' => '', + ]); + $user->save(); + + $state = new State($state); + $state->user() + ->associate($user) + ->save(); + } +} |